From 002f01cb2dfd11c731a44e18afebbda03b7d01f5 Mon Sep 17 00:00:00 2001 From: Tesshu Flower Date: Wed, 18 Dec 2024 09:07:20 -0500 Subject: [PATCH] VolSync deploy as helm charts from addon-controller - https://issues.redhat.com/browse/ACM-16311 (#512) * render helm chart, deploy in manifestwork - render local chart embedded in controller - still need to download remote charts from helm repo - helm test loading local index + ability to load remote repo Signed-off-by: Tesshu Flower * refactoring getmanifestvalues Signed-off-by: Tesshu Flower * only load helm charts locally, use helm always - still have annotation as override to use olm for openshift mgd clusters, but default will be helm - bundle helmcharts, cleanup Signed-off-by: Tesshu Flower * unit test updates, helmupdates Signed-off-by: Tesshu Flower * - addon status check updates Signed-off-by: Tesshu Flower * update imgs in stable-0.12 helm charts Signed-off-by: Tesshu Flower * exclude volsync embedded helmcharts from sonar Signed-off-by: Tesshu Flower * Simply branching in subhealthcheck Signed-off-by: Tesshu Flower * Upd to latest downstream volsync build v0.12.0-4 Signed-off-by: Tesshu Flower * Update rhtap dockerfile Signed-off-by: Tesshu Flower --------- Signed-off-by: Tesshu Flower --- Dockerfile | 4 + Dockerfile.rhtap | 4 + controllers/addoncontroller.go | 208 +- controllers/addoncontroller_legacyolm_test.go | 1572 +++++ controllers/addoncontroller_test.go | 696 ++- controllers/controllers_suite_test.go | 19 + controllers/helmutils/helmutils.go | 188 + controllers/helmutils/helmutils_suite_test.go | 55 + controllers/helmutils/helmutils_test.go | 121 + .../helmutils/helmutilstest/testhelper.go | 136 + controllers/manifesthelper.go | 86 + controllers/manifesthelper_helmdeploy.go | 181 + controllers/manifesthelper_operatordeploy.go | 124 + .../namespace.yaml} | 2 +- ...operatorpolicy-aggregate-clusterrole.yaml} | 6 +- ...olsync-operatorpolicy-remove-operator.yaml | 23 + .../operator-group-allnamespaces.yaml | 6 - .../operator-group-ownnamespace.yaml | 8 - .../{ => operator}/operator-subscription.yaml | 2 +- go.mod | 114 +- go.sum | 300 +- helmcharts/stable-0.12/volsync/.helmignore | 23 + helmcharts/stable-0.12/volsync/Chart.yaml | 71 + helmcharts/stable-0.12/volsync/README.md | 157 + .../stable-0.12/volsync/templates/NOTES.txt | 5 + .../volsync/templates/_helpers.tpl | 78 + .../templates/clusterrole-manager.yaml | 298 + .../templates/clusterrole-metrics-reader.yaml | 13 + .../templates/clusterrole-proxy-role.yaml | 21 + .../templates/clusterrolebinding-manager.yaml | 14 + .../templates/clusterrolebinding-proxy.yaml | 16 + .../templates/deployment-controller.yaml | 126 + .../templates/role-leader-election.yaml | 38 + .../rolebinding-leader-election.yaml | 14 + .../volsync/templates/service-metrics.yaml | 20 + .../volsync/templates/serviceaccount.yaml | 12 + .../templates/servicemonitor-volsync.yaml | 21 + ...lsync.backube_replicationdestinations.yaml | 4208 +++++++++++++ .../volsync.backube_replicationsources.yaml | 5372 +++++++++++++++++ helmcharts/stable-0.12/volsync/values.yaml | 89 + main.go | 9 + sonar-project.properties | 2 +- 42 files changed, 13779 insertions(+), 683 deletions(-) create mode 100644 controllers/addoncontroller_legacyolm_test.go create mode 100644 controllers/helmutils/helmutils.go create mode 100644 controllers/helmutils/helmutils_suite_test.go create mode 100644 controllers/helmutils/helmutils_test.go create mode 100644 controllers/helmutils/helmutilstest/testhelper.go create mode 100644 controllers/manifesthelper.go create mode 100644 controllers/manifesthelper_helmdeploy.go create mode 100644 controllers/manifesthelper_operatordeploy.go rename controllers/manifests/{operator-namespace.yaml => helm-chart/namespace.yaml} (56%) rename controllers/manifests/{operatorgroup-aggregate-clusterrole.yaml => helm-chart/volsync-operatorpolicy-aggregate-clusterrole.yaml} (53%) create mode 100644 controllers/manifests/helm-chart/volsync-operatorpolicy-remove-operator.yaml delete mode 100644 controllers/manifests/operator-group-allnamespaces.yaml delete mode 100644 controllers/manifests/operator-group-ownnamespace.yaml rename controllers/manifests/{ => operator}/operator-subscription.yaml (95%) create mode 100644 helmcharts/stable-0.12/volsync/.helmignore create mode 100644 helmcharts/stable-0.12/volsync/Chart.yaml create mode 100644 helmcharts/stable-0.12/volsync/README.md create mode 100644 helmcharts/stable-0.12/volsync/templates/NOTES.txt create mode 100644 helmcharts/stable-0.12/volsync/templates/_helpers.tpl create mode 100644 helmcharts/stable-0.12/volsync/templates/clusterrole-manager.yaml create mode 100644 helmcharts/stable-0.12/volsync/templates/clusterrole-metrics-reader.yaml create mode 100644 helmcharts/stable-0.12/volsync/templates/clusterrole-proxy-role.yaml create mode 100644 helmcharts/stable-0.12/volsync/templates/clusterrolebinding-manager.yaml create mode 100644 helmcharts/stable-0.12/volsync/templates/clusterrolebinding-proxy.yaml create mode 100644 helmcharts/stable-0.12/volsync/templates/deployment-controller.yaml create mode 100644 helmcharts/stable-0.12/volsync/templates/role-leader-election.yaml create mode 100644 helmcharts/stable-0.12/volsync/templates/rolebinding-leader-election.yaml create mode 100644 helmcharts/stable-0.12/volsync/templates/service-metrics.yaml create mode 100644 helmcharts/stable-0.12/volsync/templates/serviceaccount.yaml create mode 100644 helmcharts/stable-0.12/volsync/templates/servicemonitor-volsync.yaml create mode 100644 helmcharts/stable-0.12/volsync/templates/volsync.backube_replicationdestinations.yaml create mode 100644 helmcharts/stable-0.12/volsync/templates/volsync.backube_replicationsources.yaml create mode 100644 helmcharts/stable-0.12/volsync/values.yaml diff --git a/Dockerfile b/Dockerfile index e49fa0e..44a3d08 100644 --- a/Dockerfile +++ b/Dockerfile @@ -30,7 +30,11 @@ RUN microdnf -y --refresh update && \ WORKDIR / COPY --from=builder /workspace/controller . +# VolSync helm charts +COPY helmcharts/ helmcharts/ # uid/gid: nobody/nobody USER 65534:65534 +ENV EMBEDDED_CHARTS_DIR=/helmcharts + ENTRYPOINT ["/controller"] diff --git a/Dockerfile.rhtap b/Dockerfile.rhtap index 31b57d7..a23362b 100644 --- a/Dockerfile.rhtap +++ b/Dockerfile.rhtap @@ -30,7 +30,11 @@ RUN microdnf -y --refresh update && \ WORKDIR / COPY --from=builder /workspace/controller . +# VolSync helm charts +COPY helmcharts/ helmcharts/ # uid/gid: nobody/nobody USER 65534:65534 +ENV EMBEDDED_CHARTS_DIR=/helmcharts + ENTRYPOINT ["/controller"] diff --git a/controllers/addoncontroller.go b/controllers/addoncontroller.go index 614144c..d2e7795 100644 --- a/controllers/addoncontroller.go +++ b/controllers/addoncontroller.go @@ -2,26 +2,28 @@ package controllers import ( "embed" - "fmt" "strings" - "github.com/openshift/library-go/pkg/assets" operatorsv1 "github.com/operator-framework/api/pkg/operators/v1" operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + appsv1 "k8s.io/api/apps/v1" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/serializer" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/client-go/kubernetes/scheme" - "k8s.io/klog/v2" - "open-cluster-management.io/addon-framework/pkg/addonfactory" "open-cluster-management.io/addon-framework/pkg/agent" addonframeworkutils "open-cluster-management.io/addon-framework/pkg/utils" addonapiv1alpha1 "open-cluster-management.io/api/addon/v1alpha1" addonv1alpha1client "open-cluster-management.io/api/client/addon/clientset/versioned" clusterv1 "open-cluster-management.io/api/cluster/v1" workapiv1 "open-cluster-management.io/api/work/v1" + + //helmreleasev1 "open-cluster-management.io/multicloud-operators-subscription/pkg/apis/apps/helmrelease/v1" + //appsubscriptionv1 "open-cluster-management.io/multicloud-operators-subscription/pkg/apis/apps/v1" + policyv1beta1 "open-cluster-management.io/config-policy-controller/api/v1beta1" ) // @@ -42,12 +44,17 @@ const ( operatorName = "volsync-product" globalOperatorInstallNamespace = "openshift-operators" - // Defaults for ACM-2.12 + // Defaults for ACM-2.13 Operator deploy DefaultCatalogSource = "redhat-operators" DefaultCatalogSourceNamespace = "openshift-marketplace" - DefaultChannel = "stable-0.11" // No "acm-x.y" channel anymore - aligning ACM-2.12 with stable-0.11 + DefaultChannel = "stable-0.12" // aligning ACM-2.13 with stable-0.12 DefaultStartingCSV = "" // By default no starting CSV - will use the latest in the channel DefaultInstallPlanApproval = "Automatic" + + // Defaults for ACM-2.13 helm-based deploy + DefaultHelmChartKey = DefaultChannel // named the same as our operator channel + DefaultHelmChartName = "volsync" + DefaultHelmInstallNamespace = "volsync-system" ) const ( @@ -56,7 +63,9 @@ const ( // trigger the deployment of the volsync operator on that managed cluster ManagedClusterInstallVolSyncLabel = "addons.open-cluster-management.io/volsync" ManagedClusterInstallVolSyncLabelValue = "true" +) +const ( // Annotations on the ManagedClusterAddOn for overriding operator settings (in the operator Subscription) AnnotationChannelOverride = "operator-subscription-channel" AnnotationInstallPlanApprovalOverride = "operator-subscription-installPlanApproval" @@ -65,38 +74,40 @@ const ( AnnotationStartingCSVOverride = "operator-subscription-startingCSV" ) +const ( + AnnotationVolSyncAddonDeployTypeOverride = "volsync-addon-deploy-type" + //AnnotationVolSyncAddonDeployTypeOverrideHelmValue = "helm" + AnnotationVolSyncAddonDeployTypeOverrideOLMValue = "olm" + + AnnotationHelmChartKey = "helm-chart-key" +) + func init() { utilruntime.Must(scheme.AddToScheme(genericScheme)) utilruntime.Must(operatorsv1.AddToScheme(genericScheme)) utilruntime.Must(operatorsv1alpha1.AddToScheme(genericScheme)) + utilruntime.Must(apiextensionsv1.AddToScheme(genericScheme)) + utilruntime.Must(policyv1beta1.AddToScheme(genericScheme)) } //go:embed manifests -var fs embed.FS +var embedFS embed.FS -// If operator is deployed to a single namespace, the Namespace, OperatorGroup (and role to create the operatorgroup) -// is required, along with the Subscription for the operator -// This particular operator is deploying into all namespaces, but into a specific target namespace -// (Requires the annotation operatorframework.io/suggested-namespace: "mynamespace" to be set on the operator CSV) -var manifestFilesAllNamespacesInstallIntoSuggestedNamespace = []string{ - "manifests/operatorgroup-aggregate-clusterrole.yaml", - "manifests/operator-namespace.yaml", - "manifests/operator-group-allnamespaces.yaml", - "manifests/operator-subscription.yaml", +// If operator is deployed to a all namespaces and the operator wil be deployed into the global operators namespace +// (openshift-operators on OCP), the only thing needed is the Subscription for the operator +var manifestFilesOperatorDeploy = []string{ + "manifests/operator/operator-subscription.yaml", } -// Use these manifest files if deploying an operator into own namespace -//var manifestFilesOwnNamepace = []string{ -// "manifests/operatorgroup-aggregate-clusterrole.yaml", -// "manifests/operator-namespace.yaml", -// "manifests/operator-group-ownnamespace.yaml", -// "manifests/operator-subscription.yaml", -//} +var manifestFilesHelmDeploy = []string{ + "manifests/helm-chart/namespace.yaml", +} -// If operator is deployed to a all namespaces and the operator wil be deployed into the global operators namespace -// (openshift-operators on OCP), the only thing needed is the Subscription for the operator -var manifestFilesAllNamespaces = []string{ - "manifests/operator-subscription.yaml", +var manifestFilesHelmDeployOpenShift = []string{ + // Policy to remove the operator since we're going to deploy as a helm chart instead + "manifests/helm-chart/volsync-operatorpolicy-aggregate-clusterrole.yaml", + "manifests/helm-chart/volsync-operatorpolicy-remove-operator.yaml", + "manifests/helm-chart/namespace.yaml", } // Another agent with registration enabled. @@ -109,21 +120,8 @@ var _ agent.AgentAddon = &volsyncAgent{} func (h *volsyncAgent) Manifests(cluster *clusterv1.ManagedCluster, addon *addonapiv1alpha1.ManagedClusterAddOn, ) ([]runtime.Object, error) { - if !clusterSupportsAddonInstall(cluster) { - klog.InfoS("Cluster is not OpenShift, not deploying addon", "addonName", - addonName, "cluster", cluster.GetName()) - return []runtime.Object{}, nil - } - - objects := []runtime.Object{} - for _, file := range getManifestFileList(addon) { - object, err := h.loadManifestFromFile(file, cluster, addon) - if err != nil { - return nil, err - } - objects = append(objects, object) - } - return objects, nil + mh := getManifestHelper(embedFS, h.addonClient, cluster, addon) + return mh.loadManifests() } func (h *volsyncAgent) GetAgentAddonOptions() agent.AgentAddonOptions { @@ -138,7 +136,7 @@ func (h *volsyncAgent) GetAgentAddonOptions() agent.AgentAddonOptions { Group: "operators.coreos.com", Resource: "subscriptions", Name: operatorName, - Namespace: getInstallNamespace(), + Namespace: "openshift-operators", }, ProbeRules: []workapiv1.FeedbackRule{ { @@ -152,8 +150,22 @@ func (h *volsyncAgent) GetAgentAddonOptions() agent.AgentAddonOptions { }, }, }, + { + ResourceIdentifier: workapiv1.ResourceIdentifier{ + Group: appsv1.GroupName, + Resource: "deployments", + Name: "volsync", + Namespace: "*", + //Namespace: "volsync-system", + }, + ProbeRules: []workapiv1.FeedbackRule{ + { + Type: workapiv1.WellKnownStatusType, + }, + }, + }, }, - HealthCheck: subHealthCheck, + HealthChecker: subHealthChecker, }, }, SupportedConfigGVRs: []schema.GroupVersionResource{ @@ -162,106 +174,11 @@ func (h *volsyncAgent) GetAgentAddonOptions() agent.AgentAddonOptions { } } -func subHealthCheck(identifier workapiv1.ResourceIdentifier, result workapiv1.StatusFeedbackResult) error { - for _, feedbackValue := range result.Values { - if feedbackValue.Name == "installedCSV" { - klog.InfoS("Addon subscription", "installedCSV", feedbackValue.Value) - if feedbackValue.Value.Type != workapiv1.String || feedbackValue.Value.String == nil || - !strings.HasPrefix(*feedbackValue.Value.String, operatorName) { - - installedCSVErr := fmt.Errorf("addon subscription has unexpected installedCSV value") - klog.ErrorS(installedCSVErr, "Sub may not have installed CSV") - return installedCSVErr - } - } - } - klog.InfoS("health check successful") - return nil -} - -func (h *volsyncAgent) loadManifestFromFile(file string, cluster *clusterv1.ManagedCluster, - addon *addonapiv1alpha1.ManagedClusterAddOn, -) (runtime.Object, error) { - manifestConfig := struct { - OperatorName string - InstallNamespace string - OperatorGroupSpec string - CatalogSource string - CatalogSourceNamespace string - InstallPlanApproval string - Channel string - StartingCSV string - }{ - OperatorName: operatorName, - InstallNamespace: getInstallNamespace(), - CatalogSource: getCatalogSource(addon), - CatalogSourceNamespace: getCatalogSourceNamespace(addon), - InstallPlanApproval: getInstallPlanApproval(addon), - Channel: getChannel(addon), - StartingCSV: getStartingCSV(addon), - } - - manifestConfigValues := addonfactory.StructToValues(manifestConfig) - - // Get values from addonDeploymentConfig - deploymentConfigValues, err := addonfactory.GetAddOnDeploymentConfigValues( - addonframeworkutils.NewAddOnDeploymentConfigGetter(h.addonClient), - addonfactory.ToAddOnDeploymentConfigValues, - )(cluster, addon) - if err != nil { - return nil, err - } - - // Merge manifestConfig and deploymentConfigValues - mergedValues := addonfactory.MergeValues(manifestConfigValues, deploymentConfigValues) - - template, err := fs.ReadFile(file) - if err != nil { - return nil, err - } - - raw := assets.MustCreateAssetFromTemplate(file, template, &mergedValues).Data - object, _, err := genericCodec.Decode(raw, nil, nil) - if err != nil { - klog.ErrorS(err, "Error decoding manifest file", "filename", file) - return nil, err - } - return object, nil -} - -func getManifestFileList(_ *addonapiv1alpha1.ManagedClusterAddOn) []string { - installNamespace := getInstallNamespace() - if installNamespace == globalOperatorInstallNamespace { - // Do not need to create an operator group, namespace etc if installing into the global operator ns - return manifestFilesAllNamespaces - } - return manifestFilesAllNamespacesInstallIntoSuggestedNamespace -} - -func getInstallNamespace() string { - // The only namespace supported is openshift-operators, so ignore whatever is in the spec - return globalOperatorInstallNamespace -} - -func getCatalogSource(addon *addonapiv1alpha1.ManagedClusterAddOn) string { - return getAnnotationOverrideOrDefault(addon, AnnotationCatalogSourceOverride, DefaultCatalogSource) -} - -func getCatalogSourceNamespace(addon *addonapiv1alpha1.ManagedClusterAddOn) string { - return getAnnotationOverrideOrDefault(addon, AnnotationCatalogSourceNamespaceOverride, - DefaultCatalogSourceNamespace) -} - -func getInstallPlanApproval(addon *addonapiv1alpha1.ManagedClusterAddOn) string { - return getAnnotationOverrideOrDefault(addon, AnnotationInstallPlanApprovalOverride, DefaultInstallPlanApproval) -} - -func getChannel(addon *addonapiv1alpha1.ManagedClusterAddOn) string { - return getAnnotationOverrideOrDefault(addon, AnnotationChannelOverride, DefaultChannel) -} - -func getStartingCSV(addon *addonapiv1alpha1.ManagedClusterAddOn) string { - return getAnnotationOverrideOrDefault(addon, AnnotationStartingCSVOverride, DefaultStartingCSV) +func subHealthChecker(fieldResults []agent.FieldResult, + cluster *clusterv1.ManagedCluster, managedClusterAddOn *addonapiv1alpha1.ManagedClusterAddOn) error { + // ManifestHelper will run the health check + mh := getManifestHelper(embedFS, nil /* not needed for heatlh check */, cluster, managedClusterAddOn) + return mh.subHealthCheck(fieldResults) } func getAnnotationOverrideOrDefault(addon *addonapiv1alpha1.ManagedClusterAddOn, @@ -275,10 +192,11 @@ func getAnnotationOverrideOrDefault(addon *addonapiv1alpha1.ManagedClusterAddOn, return defaultValue } -func clusterSupportsAddonInstall(cluster *clusterv1.ManagedCluster) bool { +func isOpenShift(cluster *clusterv1.ManagedCluster) bool { vendor, ok := cluster.Labels["vendor"] if !ok || !strings.EqualFold(vendor, "OpenShift") { return false } + return true } diff --git a/controllers/addoncontroller_legacyolm_test.go b/controllers/addoncontroller_legacyolm_test.go new file mode 100644 index 0000000..d00a761 --- /dev/null +++ b/controllers/addoncontroller_legacyolm_test.go @@ -0,0 +1,1572 @@ +package controllers_test + +import ( + "fmt" + "strings" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/kubernetes/scheme" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + + operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + addonframeworkutils "open-cluster-management.io/addon-framework/pkg/utils" + addonv1alpha1 "open-cluster-management.io/api/addon/v1alpha1" + clusterv1 "open-cluster-management.io/api/cluster/v1" + workv1 "open-cluster-management.io/api/work/v1" + + "github.com/stolostron/volsync-addon-controller/controllers" +) + +// These tests are for deployment of VolSync as an OLM subscription +// This is the old behavior and will not be used by default +// (Only enabled if annotation is set on the managedclusteraddon) +var _ = Describe("Addoncontroller - legacy OLM deployment tests", func() { + logger := zap.New(zap.UseDevMode(true), zap.WriteTo(GinkgoWriter)) + + genericCodecs := serializer.NewCodecFactory(scheme.Scheme) + genericCodec := genericCodecs.UniversalDeserializer() + + // Make sure a ClusterManagementAddOn exists for volsync or addon-framework will not reconcile + // VolSync ManagedClusterAddOns + var clusterManagementAddon *addonv1alpha1.ClusterManagementAddOn + + BeforeEach(func() { + // clustermanagementaddon (this is a global resource) + clusterManagementAddon = &addonv1alpha1.ClusterManagementAddOn{ + ObjectMeta: metav1.ObjectMeta{ + Name: "volsync", + }, + Spec: addonv1alpha1.ClusterManagementAddOnSpec{ + AddOnMeta: addonv1alpha1.AddOnMeta{ + DisplayName: "VolSync", + Description: "VolSync", + }, + SupportedConfigs: []addonv1alpha1.ConfigMeta{ + { + ConfigGroupResource: addonv1alpha1.ConfigGroupResource{ + Group: "addon.open-cluster-management.io", + Resource: "addondeploymentconfigs", + }, + }, + }, + InstallStrategy: addonv1alpha1.InstallStrategy{ + Type: addonv1alpha1.AddonInstallStrategyManual, + }, + }, + } + }) + AfterEach(func() { + Expect(testK8sClient.Delete(testCtx, clusterManagementAddon)).To(Succeed()) + }) + + JustBeforeEach(func() { + // Create the clustermanagementaddon here so tests can modify it in their BeforeEach() + // before we create it + Expect(testK8sClient.Create(testCtx, clusterManagementAddon)).To(Succeed()) + }) + + Context("When a ManagedClusterExists", func() { + var testManagedCluster *clusterv1.ManagedCluster + var testManagedClusterNamespace *corev1.Namespace + + BeforeEach(func() { + // Create a managed cluster CR to use for this test + testManagedCluster = &clusterv1.ManagedCluster{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "addon-mgdcluster-", + Labels: map[string]string{ + "vendor": "OpenShift", + }, + }, + } + + Expect(testK8sClient.Create(testCtx, testManagedCluster)).To(Succeed()) + Expect(testManagedCluster.Name).NotTo(BeEmpty()) + + // Fake the status of the mgd cluster to be available + Eventually(func() error { + err := testK8sClient.Get(testCtx, client.ObjectKeyFromObject(testManagedCluster), testManagedCluster) + if err != nil { + return err + } + + clusterAvailableCondition := metav1.Condition{ + Type: clusterv1.ManagedClusterConditionAvailable, + Status: metav1.ConditionTrue, + Reason: "testupdate", + Message: "faking cluster available for test", + } + meta.SetStatusCondition(&testManagedCluster.Status.Conditions, clusterAvailableCondition) + + return testK8sClient.Status().Update(testCtx, testManagedCluster) + }, timeout, interval).Should(Succeed()) + + // Create a matching namespace for this managed cluster + // (namespace with name=managedclustername is expected to exist on the hub) + testManagedClusterNamespace = &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: testManagedCluster.GetName(), + }, + } + Expect(testK8sClient.Create(testCtx, testManagedClusterNamespace)).To(Succeed()) + }) + + Context("When a ManagedClusterAddon for this addon is created", func() { + var mcAddon *addonv1alpha1.ManagedClusterAddOn + var manifestWork *workv1.ManifestWork + BeforeEach(func() { + // Create a ManagedClusterAddon for the mgd cluster + mcAddon = &addonv1alpha1.ManagedClusterAddOn{ + ObjectMeta: metav1.ObjectMeta{ + Name: "volsync", + Namespace: testManagedCluster.GetName(), + Annotations: map[string]string{ + // Need to set special annotation to use OLM mode + //nolint: lll + controllers.AnnotationVolSyncAddonDeployTypeOverride: controllers.AnnotationVolSyncAddonDeployTypeOverrideOLMValue, + }, + }, + Spec: addonv1alpha1.ManagedClusterAddOnSpec{}, // Setting spec to empty + } + }) + JustBeforeEach(func() { + // Create the managed cluster addon + Expect(testK8sClient.Create(testCtx, mcAddon)).To(Succeed()) + + // Need to have the CMA as owner on the managedclusteraddon or the registration controller + // will ignore it (and therefore addondeploy controller won't call our Manifests() func) + // This step is normally done by a global controller on the hub - so simulate for our tests + Eventually(func() error { + err := addCMAOwnership(clusterManagementAddon, mcAddon) + if err != nil { + // Reload the mcAddOn before we try again in case there was a conflict with updating + reloadErr := testK8sClient.Get(testCtx, client.ObjectKeyFromObject(mcAddon), mcAddon) + if reloadErr != nil { + return reloadErr + } + return err + } + return nil + }, timeout, interval).Should(Succeed()) + + manifestWork = &workv1.ManifestWork{} + // The controller should create a ManifestWork for this ManagedClusterAddon + Eventually(func() bool { + allMwList := &workv1.ManifestWorkList{} + Expect(testK8sClient.List(testCtx, allMwList, + client.InNamespace(testManagedCluster.GetName()))).To(Succeed()) + + for _, mw := range allMwList.Items { + // addon-framework now creates manifestwork with "-0" prefix (to allow for + // creating multiple manifestworks if the content is large - will not be the case + // for VolSync - so we could alternatively just search for addon-volsync-deploy-0) + if strings.HasPrefix(mw.GetName(), "addon-volsync-deploy") == true { + manifestWork = &mw + return true /* found the manifestwork */ + } + } + return false + }, timeout, interval).Should(BeTrue()) + + Expect(manifestWork).ToNot(BeNil()) + }) + + Context("When installing into openshift-operators namespace (the default)", func() { + var operatorSubscription *operatorsv1alpha1.Subscription + + JustBeforeEach(func() { + // When installing into the global operator namespace (openshift-operators) + // we should expect the manifestwork to contain only: + // - the operator subscription + Expect(len(manifestWork.Spec.Workload.Manifests)).To(Equal(1)) + + // Subscription + subMF := manifestWork.Spec.Workload.Manifests[0] + subObj, _, err := genericCodec.Decode(subMF.Raw, nil, nil) + Expect(err).NotTo(HaveOccurred()) + var ok bool + operatorSubscription, ok = subObj.(*operatorsv1alpha1.Subscription) + Expect(ok).To(BeTrue()) + Expect(operatorSubscription).NotTo(BeNil()) + Expect(operatorSubscription.GetNamespace()).To(Equal("openshift-operators")) + Expect(operatorSubscription.Spec.Package).To(Equal("volsync-product")) // This is the "name" in json + + // No addonDeploymentConfig in these tests, so the operatorSub should not have any Config specified + Expect(operatorSubscription.Spec.Config).To(BeNil()) + + // More specific checks done in tests + }) + + Context("When the ManagedClusterAddOn spec set an installNamespace", func() { + BeforeEach(func() { + // Override to specifically set the ns in the spec - all the tests above in JustBeforeEach + // should still be valid here + mcAddon.Spec.InstallNamespace = "test1234" + }) + It("Should still install to the default openshift-operators namespace", func() { + // Code shouldn't have alterted the spec - but tests above will confirm that the + // operatorgroup/subscription were created in volsync-system + Expect(mcAddon.Spec.InstallNamespace).To(Equal("test1234")) + }) + }) + + Context("When no annotations are on the managedclusteraddon", func() { + It("Should create the subscription (within the ManifestWork) with proper defaults", func() { + // This ns is now the default in the mcao crd so will be used - note we ignore this + // and use openshift-operators (see the created subscription) + Expect(mcAddon.Spec.InstallNamespace).To(Equal("open-cluster-management-agent-addon")) + + Expect(operatorSubscription.Spec.Channel).To(Equal(controllers.DefaultChannel)) + Expect(string(operatorSubscription.Spec.InstallPlanApproval)).To(Equal( + controllers.DefaultInstallPlanApproval)) + Expect(operatorSubscription.Spec.CatalogSource).To(Equal(controllers.DefaultCatalogSource)) + Expect(operatorSubscription.Spec.CatalogSourceNamespace).To(Equal( + controllers.DefaultCatalogSourceNamespace)) + Expect(operatorSubscription.Spec.StartingCSV).To(Equal(controllers.DefaultStartingCSV)) + }) + }) + + Context("When the annotation to override the CatalogSource is on the managedclusteraddon", func() { + BeforeEach(func() { + mcAddon.Annotations[controllers.AnnotationCatalogSourceOverride] = "customcatalog-source" + }) + It("Should create the subscription (within the ManifestWork) with proper CatalogSource", func() { + Expect(operatorSubscription.Spec.CatalogSource).To(Equal("customcatalog-source")) + + // The rest should be defaults + Expect(operatorSubscription.Spec.Channel).To(Equal(controllers.DefaultChannel)) + Expect(string(operatorSubscription.Spec.InstallPlanApproval)).To(Equal( + controllers.DefaultInstallPlanApproval)) + Expect(operatorSubscription.Spec.CatalogSourceNamespace).To(Equal( + controllers.DefaultCatalogSourceNamespace)) + Expect(operatorSubscription.Spec.StartingCSV).To(Equal(controllers.DefaultStartingCSV)) + }) + }) + + Context("When the annotation to override the CatalogSourceNS is on the managedclusteraddon", func() { + BeforeEach(func() { + mcAddon.Annotations[controllers.AnnotationCatalogSourceNamespaceOverride] = "my-catalog-source-ns" + }) + It("Should create the subscription (within the ManifestWork) with proper CatalogSourceNS", func() { + Expect(operatorSubscription.Spec.CatalogSourceNamespace).To(Equal( + "my-catalog-source-ns")) + + // The rest should be defaults + Expect(operatorSubscription.Spec.Channel).To(Equal(controllers.DefaultChannel)) + Expect(string(operatorSubscription.Spec.InstallPlanApproval)).To(Equal( + controllers.DefaultInstallPlanApproval)) + Expect(operatorSubscription.Spec.CatalogSource).To(Equal(controllers.DefaultCatalogSource)) + Expect(operatorSubscription.Spec.StartingCSV).To(Equal(controllers.DefaultStartingCSV)) + }) + }) + + Context("When the annotation to override the InstallPlanApproval is on the managedclusteraddon", func() { + BeforeEach(func() { + mcAddon.Annotations[controllers.AnnotationInstallPlanApprovalOverride] = "Manual" + }) + It("Should create the subscription (within the ManifestWork) with proper CatalogSourceNS", func() { + Expect(string(operatorSubscription.Spec.InstallPlanApproval)).To(Equal("Manual")) + + // The rest should be defaults + Expect(operatorSubscription.Spec.Channel).To(Equal(controllers.DefaultChannel)) + Expect(operatorSubscription.Spec.CatalogSource).To(Equal(controllers.DefaultCatalogSource)) + Expect(operatorSubscription.Spec.CatalogSourceNamespace).To(Equal( + controllers.DefaultCatalogSourceNamespace)) + Expect(operatorSubscription.Spec.StartingCSV).To(Equal(controllers.DefaultStartingCSV)) + }) + }) + + Context("When the annotation to override the Channel is on the managedclusteraddon", func() { + BeforeEach(func() { + mcAddon.Annotations[controllers.AnnotationChannelOverride] = "special-channel-1.2.3" + }) + It("Should create the subscription (within the ManifestWork) with proper CatalogSourceNS", func() { + Expect(operatorSubscription.Spec.Channel).To(Equal("special-channel-1.2.3")) + + // The rest should be defaults + Expect(string(operatorSubscription.Spec.InstallPlanApproval)).To(Equal( + controllers.DefaultInstallPlanApproval)) + Expect(operatorSubscription.Spec.CatalogSource).To(Equal(controllers.DefaultCatalogSource)) + Expect(operatorSubscription.Spec.CatalogSourceNamespace).To(Equal( + controllers.DefaultCatalogSourceNamespace)) + Expect(operatorSubscription.Spec.StartingCSV).To(Equal(controllers.DefaultStartingCSV)) + }) + }) + + Context("When the annotation to override the StartingCSV is on the managedclusteraddon", func() { + BeforeEach(func() { + mcAddon.Annotations[controllers.AnnotationStartingCSVOverride] = "volsync.v1.2.3.doesnotexist" + }) + It("Should create the subscription (within the ManifestWork) with proper CatalogSourceNS", func() { + Expect(operatorSubscription.Spec.StartingCSV).To(Equal("volsync.v1.2.3.doesnotexist")) + + // The rest should be defaults + Expect(operatorSubscription.Spec.Channel).To(Equal(controllers.DefaultChannel)) + Expect(string(operatorSubscription.Spec.InstallPlanApproval)).To(Equal( + controllers.DefaultInstallPlanApproval)) + Expect(operatorSubscription.Spec.CatalogSource).To(Equal(controllers.DefaultCatalogSource)) + Expect(operatorSubscription.Spec.CatalogSourceNamespace).To(Equal( + controllers.DefaultCatalogSourceNamespace)) + }) + }) + }) + }) + + Context("When the manifestwork already exists", func() { + // Make sure the addon-framework will tolerate upgrades where the managedclusteraddon previously + // created the manifestwork with the name "addon-volsync-deploy". Newer versions of the addon-framework + // name the manifestwork "addon-volsync-deploy-0". These tests ensure a migration from older behavior + // to the new work ok. + var fakeOlderMw *workv1.ManifestWork + BeforeEach(func() { + // First pre-create the manifestwork with the old name "addon-volsync-deploy" and to make it look + // like it was deployed from an older version of volsync-addon-controller using the older + // addon-framework. + fakeOlderMw = &workv1.ManifestWork{ + ObjectMeta: metav1.ObjectMeta{ + Name: "addon-volsync-deploy", // old name generated by addon-framework < 0.5.0 + Namespace: testManagedCluster.GetName(), + Labels: map[string]string{ + "open-cluster-management.io/addon-name": "volsync", + }, + }, + Spec: workv1.ManifestWorkSpec{}, + } + Expect(testK8sClient.Create(testCtx, fakeOlderMw)).To(Succeed()) + + // Make sure cache loads this manifestwork before proceeding + Eventually(func() error { + return testK8sClient.Get(testCtx, client.ObjectKeyFromObject(fakeOlderMw), fakeOlderMw) + }, timeout, interval).Should(Succeed()) + }) + + It("Should use the existing manifestwork", func() { + // Create a ManagedClusterAddon for the mgd cluster + mcAddon := &addonv1alpha1.ManagedClusterAddOn{ + ObjectMeta: metav1.ObjectMeta{ + Name: "volsync", + Namespace: testManagedCluster.GetName(), + Annotations: map[string]string{ + // Need to set special annotation to use OLM mode + //nolint: lll + controllers.AnnotationVolSyncAddonDeployTypeOverride: controllers.AnnotationVolSyncAddonDeployTypeOverrideOLMValue, + }, + }, + Spec: addonv1alpha1.ManagedClusterAddOnSpec{}, // Setting spec to empty + } + + Expect(testK8sClient.Create(testCtx, mcAddon)).To(Succeed()) + + // Need to have the CMA as owner on the managedclusteraddon or the registration controller + // will ignore it (and therefore addondeploy controller won't call our Manifests() func) + // This step is normally done by a global controller on the hub - so simulate for our tests + Eventually(func() error { + err := addCMAOwnership(clusterManagementAddon, mcAddon) + if err != nil { + // Reload the mcAddOn before we try again in case there was a conflict with updating + reloadErr := testK8sClient.Get(testCtx, client.ObjectKeyFromObject(mcAddon), mcAddon) + if reloadErr != nil { + return reloadErr + } + return err + } + return nil + }, timeout, interval).Should(Succeed()) + + Eventually(func() bool { + // List manifestworks - pre-existing manifestwork should still be there and be updated + allMwList := &workv1.ManifestWorkList{} + Expect(testK8sClient.List(testCtx, allMwList, + client.InNamespace(testManagedCluster.GetName()))).To(Succeed()) + + if len(allMwList.Items) != 1 { + // it's either created another manifestwork (bad) or deleted the existing one (also bad) + return false + } + + myMw := &allMwList.Items[0] + Expect(myMw.GetName()).To(Equal(fakeOlderMw.GetName())) + + if len(myMw.Spec.Workload.Manifests) != 1 { + // Manifestwork hasn't been updated with the subscription yet + return false + } + + Expect(myMw.Spec.Workload.Manifests[0]) + subObj, _, err := genericCodec.Decode(myMw.Spec.Workload.Manifests[0].Raw, nil, nil) + Expect(err).NotTo(HaveOccurred()) + operatorSubscription, ok := subObj.(*operatorsv1alpha1.Subscription) + + return ok && operatorSubscription != nil + }, timeout, interval).Should(BeTrue()) + }) + }) + + Describe("Node Selector/Tolerations tests", func() { + Context("When a ManagedClusterAddOn is created with node selectors and tolerations", func() { + var mcAddon *addonv1alpha1.ManagedClusterAddOn + var manifestWork *workv1.ManifestWork + var operatorSubscription *operatorsv1alpha1.Subscription + + BeforeEach(func() { + // Create a ManagedClusterAddon for the mgd cluster using an addonDeploymentconfig + mcAddon = &addonv1alpha1.ManagedClusterAddOn{ + ObjectMeta: metav1.ObjectMeta{ + Name: "volsync", + Namespace: testManagedCluster.GetName(), + Annotations: map[string]string{ + // Need to set special annotation to use OLM mode + //nolint: lll + controllers.AnnotationVolSyncAddonDeployTypeOverride: controllers.AnnotationVolSyncAddonDeployTypeOverrideOLMValue, + }, + }, + Spec: addonv1alpha1.ManagedClusterAddOnSpec{}, // Setting spec to empty + } + }) + JustBeforeEach(func() { + // Create the managed cluster addon + Expect(testK8sClient.Create(testCtx, mcAddon)).To(Succeed()) + + // Need to have the CMA as owner on the managedclusteraddon or the registration controller + // will ignore it (and therefore addondeploy controller won't call our Manifests() func) + // This step is normally done by a global controller on the hub - so simulate for our tests + Eventually(func() error { + err := addCMAOwnership(clusterManagementAddon, mcAddon) + if err != nil { + // Reload the mcAddOn before we try again in case there was a conflict with updating + reloadErr := testK8sClient.Get(testCtx, client.ObjectKeyFromObject(mcAddon), mcAddon) + if reloadErr != nil { + return reloadErr + } + return err + } + return nil + }, timeout, interval).Should(Succeed()) + + manifestWork = &workv1.ManifestWork{} + // The controller should create a ManifestWork for this ManagedClusterAddon + Eventually(func() bool { + allMwList := &workv1.ManifestWorkList{} + Expect(testK8sClient.List(testCtx, allMwList, + client.InNamespace(testManagedCluster.GetName()))).To(Succeed()) + + for _, mw := range allMwList.Items { + // addon-framework now creates manifestwork with "-0" prefix (to allow for + // creating multiple manifestworks if the content is large - will not be the case + // for VolSync - so we could alternatively just search for addon-volsync-deploy-0) + if strings.HasPrefix(mw.GetName(), "addon-volsync-deploy") == true { + manifestWork = &mw + return true /* found the manifestwork */ + } + } + return false + }, timeout, interval).Should(BeTrue()) + + Expect(manifestWork).ToNot(BeNil()) + + // Subscription + subMF := manifestWork.Spec.Workload.Manifests[0] + subObj, _, err := genericCodec.Decode(subMF.Raw, nil, nil) + Expect(err).NotTo(HaveOccurred()) + var ok bool + operatorSubscription, ok = subObj.(*operatorsv1alpha1.Subscription) + Expect(ok).To(BeTrue()) + Expect(operatorSubscription).NotTo(BeNil()) + Expect(operatorSubscription.GetNamespace()).To(Equal("openshift-operators")) + Expect(operatorSubscription.Spec.Package).To(Equal("volsync-product")) // This is the "name" in json + }) + + Context("When no addonDeploymentConfig is referenced", func() { + It("Should create the sub in the manifestwork with no tolerations or selectors", func() { + Expect(operatorSubscription.Spec.Config).To(BeNil()) + }) + + Context("When the managedclusteraddon is updated later with a addondeploymentconfig", func() { + var addonDeploymentConfig *addonv1alpha1.AddOnDeploymentConfig + nodePlacement := &addonv1alpha1.NodePlacement{ + NodeSelector: map[string]string{ + "place": "here", + }, + Tolerations: []corev1.Toleration{ + { + Key: "node.kubernetes.io/unreachable", + Operator: corev1.TolerationOpExists, + Effect: corev1.TaintEffectNoSchedule, + }, + }, + } + + BeforeEach(func() { + addonDeploymentConfig = createAddonDeploymentConfig(nodePlacement) + }) + AfterEach(func() { + cleanupAddonDeploymentConfig(addonDeploymentConfig, true) + }) + + It("Should update the existing manifestwork with the addondeploymentconfig", func() { + Expect(operatorSubscription.Spec.Config).To(BeNil()) + + // Update the managedclusteraddon to reference the addonDeploymentConfig + Eventually(func() error { + err := testK8sClient.Get(testCtx, client.ObjectKeyFromObject(mcAddon), mcAddon) + if err != nil { + return err + } + + // Update the managedclusteraddon - doing this in eventually loop to avoid update issues if + // the controller is also updating the resource + mcAddon.Spec.Configs = []addonv1alpha1.AddOnConfig{ + { + ConfigGroupResource: addonv1alpha1.ConfigGroupResource{ + Group: "addon.open-cluster-management.io", + Resource: "addondeploymentconfigs", + }, + ConfigReferent: addonv1alpha1.ConfigReferent{ + Name: addonDeploymentConfig.GetName(), + Namespace: addonDeploymentConfig.GetNamespace(), + }, + }, + } + + return testK8sClient.Update(testCtx, mcAddon) + }, timeout, interval).Should(Succeed()) + + // The controller that used to update the managedClusterAddOn status with the deploymentconfig + // has been moved to a common controller in the ocm hub - so simulate status update so our + // code can proceed + Eventually(func() error { + err := addDeploymentConfigStatusEntry(mcAddon, addonDeploymentConfig) + if err != nil { + // Reload the mcAddOn before we try again in case there was a conflict with updating + reloadErr := testK8sClient.Get(testCtx, client.ObjectKeyFromObject(mcAddon), mcAddon) + if reloadErr != nil { + return reloadErr + } + return err + } + return nil + }, timeout, interval).Should(Succeed()) + + // Now reload the manifestwork, it should eventually be updated with the nodeselector + // and tolerations + + var manifestWorkReloaded *workv1.ManifestWork + var operatorSubscriptionReloaded *operatorsv1alpha1.Subscription + + Eventually(func() bool { + allMwList := &workv1.ManifestWorkList{} + Expect(testK8sClient.List(testCtx, allMwList, + client.InNamespace(testManagedCluster.GetName()))).To(Succeed()) + + for _, mw := range allMwList.Items { + // addon-framework now creates manifestwork with "-0" prefix (to allow for + // creating multiple manifestworks if the content is large - will not be the case + // for VolSync - so we could alternatively just search for addon-volsync-deploy-0) + if strings.HasPrefix(mw.GetName(), "addon-volsync-deploy") == true { + manifestWorkReloaded = &mw + break + } + } + + logger.Info(">>>>> ManifestWorkreloaded <<<", "manifestWorkReloaded", &manifestWorkReloaded) + if manifestWorkReloaded == nil { + return false + } + + // Subscription + subMF := manifestWorkReloaded.Spec.Workload.Manifests[0] + subObj, _, err := genericCodec.Decode(subMF.Raw, nil, nil) + Expect(err).NotTo(HaveOccurred()) + var ok bool + operatorSubscriptionReloaded, ok = subObj.(*operatorsv1alpha1.Subscription) + Expect(ok).To(BeTrue()) + Expect(operatorSubscriptionReloaded).NotTo(BeNil()) + + // If spec.config has been set, then it's been updated + return operatorSubscriptionReloaded.Spec.Config != nil + }, timeout, interval).Should(BeTrue()) + + Expect(operatorSubscriptionReloaded.Spec.Config.NodeSelector).To(Equal(nodePlacement.NodeSelector)) + Expect(operatorSubscriptionReloaded.Spec.Config.Tolerations).To(Equal(nodePlacement.Tolerations)) + }) + }) + }) + + Context("When the addonDeploymentconfig has nodeSelector and no tolerations", func() { + var addonDeploymentConfig *addonv1alpha1.AddOnDeploymentConfig + nodePlacement := &addonv1alpha1.NodePlacement{ + NodeSelector: map[string]string{ + "a": "b", + "1234": "5678", + }, + } + BeforeEach(func() { + addonDeploymentConfig = createAddonDeploymentConfig(nodePlacement) + + // Update the managedclusteraddon before we create it to add the addondeploymentconfig + mcAddon.Spec.Configs = []addonv1alpha1.AddOnConfig{ + { + ConfigGroupResource: addonv1alpha1.ConfigGroupResource{ + Group: "addon.open-cluster-management.io", + Resource: "addondeploymentconfigs", + }, + ConfigReferent: addonv1alpha1.ConfigReferent{ + Name: addonDeploymentConfig.GetName(), + Namespace: addonDeploymentConfig.GetNamespace(), + }, + }, + } + }) + AfterEach(func() { + cleanupAddonDeploymentConfig(addonDeploymentConfig, true) + }) + + JustBeforeEach(func() { + // The controller that used to update the managedClusterAddOn status with the deploymentconfig + // has been moved to a common controller in the ocm hub - so simulate status update so our + // code can proceed + Eventually(func() error { + err := addDeploymentConfigStatusEntry(mcAddon, addonDeploymentConfig) + if err != nil { + // Reload the mcAddOn before we try again in case there was a conflict with updating + reloadErr := testK8sClient.Get(testCtx, client.ObjectKeyFromObject(mcAddon), mcAddon) + if reloadErr != nil { + return reloadErr + } + return err + } + return nil + }, timeout, interval).Should(Succeed()) + + // Now re-load the manifestwork, should get updated + Eventually(func() bool { + reloadErr := testK8sClient.Get(testCtx, client.ObjectKeyFromObject(manifestWork), manifestWork) + if reloadErr != nil { + return false + } + + // get Subscription from the manifestwork + subMF := manifestWork.Spec.Workload.Manifests[0] + subObj, _, err := genericCodec.Decode(subMF.Raw, nil, nil) + Expect(err).NotTo(HaveOccurred()) + var ok bool + operatorSubscription, ok = subObj.(*operatorsv1alpha1.Subscription) + if !ok { + return false + } + return operatorSubscription.Spec.Config != nil + }, timeout, interval).Should(BeTrue()) + }) + + It("Should create the sub in the manifestwork wiith the node selector", func() { + Expect(operatorSubscription.Spec.Config).ToNot(BeNil()) + Expect(operatorSubscription.Spec.Config.NodeSelector).To(Equal(nodePlacement.NodeSelector)) + Expect(operatorSubscription.Spec.Config.Tolerations).To(BeNil()) // No tolerations set + }) + }) + + Context("When the addonDeployment config has tolerations and no nodeSelector", func() { + var addonDeploymentConfig *addonv1alpha1.AddOnDeploymentConfig + nodePlacement := &addonv1alpha1.NodePlacement{ + Tolerations: []corev1.Toleration{ + { + Key: "node.kubernetes.io/unreachable", + Operator: corev1.TolerationOpExists, + Effect: corev1.TaintEffectNoSchedule, + }, + }, + } + BeforeEach(func() { + addonDeploymentConfig = createAddonDeploymentConfig(nodePlacement) + + // Update the managedclusteraddon before we create it to add the addondeploymentconfig + mcAddon.Spec.Configs = []addonv1alpha1.AddOnConfig{ + { + ConfigGroupResource: addonv1alpha1.ConfigGroupResource{ + Group: "addon.open-cluster-management.io", + Resource: "addondeploymentconfigs", + }, + ConfigReferent: addonv1alpha1.ConfigReferent{ + Name: addonDeploymentConfig.GetName(), + Namespace: addonDeploymentConfig.GetNamespace(), + }, + }, + } + }) + AfterEach(func() { + cleanupAddonDeploymentConfig(addonDeploymentConfig, true) + }) + + JustBeforeEach(func() { + // The controller that used to update the managedClusterAddOn status with the deploymentconfig + // has been moved to a common controller in the ocm hub - so simulate status update so our + // code can proceed + Eventually(func() error { + err := addDeploymentConfigStatusEntry(mcAddon, addonDeploymentConfig) + if err != nil { + // Reload the mcAddOn before we try again in case there was a conflict with updating + reloadErr := testK8sClient.Get(testCtx, client.ObjectKeyFromObject(mcAddon), mcAddon) + if reloadErr != nil { + return reloadErr + } + return err + } + return nil + }, timeout, interval).Should(Succeed()) + + // Now re-load the manifestwork, should get updated + Eventually(func() bool { + reloadErr := testK8sClient.Get(testCtx, client.ObjectKeyFromObject(manifestWork), manifestWork) + if reloadErr != nil { + return false + } + + // get Subscription from the manifestwork + subMF := manifestWork.Spec.Workload.Manifests[0] + subObj, _, err := genericCodec.Decode(subMF.Raw, nil, nil) + Expect(err).NotTo(HaveOccurred()) + var ok bool + operatorSubscription, ok = subObj.(*operatorsv1alpha1.Subscription) + if !ok { + return false + } + return operatorSubscription.Spec.Config != nil + }, timeout, interval).Should(BeTrue()) + }) + + It("Should create the sub in the manifestwork wiith the node selector", func() { + Expect(operatorSubscription.Spec.Config).ToNot(BeNil()) + Expect(operatorSubscription.Spec.Config.Tolerations).To(Equal(nodePlacement.Tolerations)) + Expect(operatorSubscription.Spec.Config.NodeSelector).To(BeNil()) // No selectors set + }) + }) + + Context("When the addonDeployment config has nodeSelector and tolerations and nodeSelector", func() { + var addonDeploymentConfig *addonv1alpha1.AddOnDeploymentConfig + nodePlacement := &addonv1alpha1.NodePlacement{ + NodeSelector: map[string]string{ + "apples": "oranges", + }, + Tolerations: []corev1.Toleration{ + { + Key: "node.kubernetes.io/unreachable", + Operator: corev1.TolerationOpExists, + Effect: corev1.TaintEffectNoSchedule, + }, + { + Key: "fakekey", + Value: "somevalue", + Operator: corev1.TolerationOpEqual, + Effect: corev1.TaintEffectNoExecute, + }, + }, + } + BeforeEach(func() { + addonDeploymentConfig = createAddonDeploymentConfig(nodePlacement) + + // Update the managedclusteraddon before we create it to add the addondeploymentconfig + mcAddon.Spec.Configs = []addonv1alpha1.AddOnConfig{ + { + ConfigGroupResource: addonv1alpha1.ConfigGroupResource{ + Group: "addon.open-cluster-management.io", + Resource: "addondeploymentconfigs", + }, + ConfigReferent: addonv1alpha1.ConfigReferent{ + Name: addonDeploymentConfig.GetName(), + Namespace: addonDeploymentConfig.GetNamespace(), + }, + }, + } + }) + AfterEach(func() { + cleanupAddonDeploymentConfig(addonDeploymentConfig, true) + }) + + JustBeforeEach(func() { + // The controller that used to update the managedClusterAddOn status with the deploymentconfig + // has been moved to a common controller in the ocm hub - so simulate status update so our + // code can proceed + Eventually(func() error { + err := addDeploymentConfigStatusEntry(mcAddon, addonDeploymentConfig) + if err != nil { + // Reload the mcAddOn before we try again in case there was a conflict with updating + reloadErr := testK8sClient.Get(testCtx, client.ObjectKeyFromObject(mcAddon), mcAddon) + if reloadErr != nil { + return reloadErr + } + return err + } + return nil + }, timeout, interval).Should(Succeed()) + + // Now re-load the manifestwork, should get updated + Eventually(func() bool { + reloadErr := testK8sClient.Get(testCtx, client.ObjectKeyFromObject(manifestWork), manifestWork) + if reloadErr != nil { + return false + } + + // get Subscription from the manifestwork + subMF := manifestWork.Spec.Workload.Manifests[0] + subObj, _, err := genericCodec.Decode(subMF.Raw, nil, nil) + Expect(err).NotTo(HaveOccurred()) + var ok bool + operatorSubscription, ok = subObj.(*operatorsv1alpha1.Subscription) + if !ok { + return false + } + return operatorSubscription.Spec.Config != nil + }, timeout, interval).Should(BeTrue()) + }) + + It("Should create the sub in the manifestwork wiith the node selector", func() { + Expect(operatorSubscription.Spec.Config).ToNot(BeNil()) + Expect(operatorSubscription.Spec.Config.NodeSelector).To(Equal(nodePlacement.NodeSelector)) + Expect(operatorSubscription.Spec.Config.Tolerations).To(Equal(nodePlacement.Tolerations)) + }) + }) + }) + + Context("When the volsync ClusterManagementAddOn has a default deployment config w/ node "+ + "selectors/tolerations", func() { + var defaultAddonDeploymentConfig *addonv1alpha1.AddOnDeploymentConfig + var mcAddon *addonv1alpha1.ManagedClusterAddOn + var operatorSubscription *operatorsv1alpha1.Subscription + var defaultNodePlacement *addonv1alpha1.NodePlacement + var manifestWork *workv1.ManifestWork + + myTolerationSeconds := int64(25) + + BeforeEach(func() { + defaultNodePlacement = &addonv1alpha1.NodePlacement{ + NodeSelector: map[string]string{ + "testing": "123", + "specialnode": "very", + "abcd": "efgh", + }, + Tolerations: []corev1.Toleration{ + { + Key: "node.kubernetes.io/unreachable", + Operator: corev1.TolerationOpExists, + Effect: corev1.TaintEffectPreferNoSchedule, + }, + { + Key: "aaaaa", + Operator: corev1.TolerationOpExists, + Effect: corev1.TaintEffectNoExecute, + TolerationSeconds: &myTolerationSeconds, + }, + }, + } + + defaultAddonDeploymentConfig = createAddonDeploymentConfig(defaultNodePlacement) + + // Update the ClusterManagementAddOn before we create it to set a default deployment config + clusterManagementAddon.Spec.SupportedConfigs[0].DefaultConfig = &addonv1alpha1.ConfigReferent{ + Name: defaultAddonDeploymentConfig.GetName(), + Namespace: defaultAddonDeploymentConfig.GetNamespace(), + } + + // Create a ManagedClusterAddon for the mgd cluster + mcAddon = &addonv1alpha1.ManagedClusterAddOn{ + ObjectMeta: metav1.ObjectMeta{ + Name: "volsync", + Namespace: testManagedCluster.GetName(), + Annotations: map[string]string{ + // Need to set special annotation to use OLM mode + //nolint: lll + controllers.AnnotationVolSyncAddonDeployTypeOverride: controllers.AnnotationVolSyncAddonDeployTypeOverrideOLMValue, + "operator-subscription-channel": "stable", + }, + }, + Spec: addonv1alpha1.ManagedClusterAddOnSpec{}, // Setting spec to empty + } + }) + AfterEach(func() { + cleanupAddonDeploymentConfig(defaultAddonDeploymentConfig, true) + }) + + JustBeforeEach(func() { + // Create the managed cluster addon + Expect(testK8sClient.Create(testCtx, mcAddon)).To(Succeed()) + + // Need to have the CMA as owner on the managedclusteraddon or the registration controller + // will ignore it (and therefore addondeploy controller won't call our Manifests() func) + // This step is normally done by a global controller on the hub - so simulate for our tests + Eventually(func() error { + err := addCMAOwnership(clusterManagementAddon, mcAddon) + if err != nil { + // Reload the mcAddOn before we try again in case there was a conflict with updating + reloadErr := testK8sClient.Get(testCtx, client.ObjectKeyFromObject(mcAddon), mcAddon) + if reloadErr != nil { + return reloadErr + } + return err + } + return nil + }, timeout, interval).Should(Succeed()) + + // Do extra updates on the CMA because no controllers run from the addon-framework itself + // update the clustermanagement addon (CMA) status with defaultconfigreferences + // + // Without these config references, the managedclusteraddon.status.configreferences won't get + // the desired config spechash set (they will for non-default addondeploymentconfigs, but not + // for default ones). + // + // So to work around for the sake of unit testing while we don't have these external + // controller(s) that update the CMA status, set the status.DefaultConfigReferences to the + // defaultaddonconfiguration we created earlier. The addon-framework controllers should update the + // spechash accordingly on CMA and MgdClusterAddon default. + Eventually(func() bool { + // re-load the clustermanagementaddon - Now manually update the status to simulate what + // another common controller will do (this is an external controller not started by the + // addon-framework) + err := testK8sClient.Get(testCtx, client.ObjectKeyFromObject(clusterManagementAddon), clusterManagementAddon) + if err != nil { + return false + } + // Now update the status to simulate the external controller + clusterManagementAddon.Status.DefaultConfigReferences = []addonv1alpha1.DefaultConfigReference{ + { + ConfigGroupResource: addonv1alpha1.ConfigGroupResource{ + Group: addonframeworkutils.AddOnDeploymentConfigGVR.Group, + Resource: addonframeworkutils.AddOnDeploymentConfigGVR.Resource, + }, + DesiredConfig: &addonv1alpha1.ConfigSpecHash{ + ConfigReferent: addonv1alpha1.ConfigReferent{ + Name: defaultAddonDeploymentConfig.GetName(), + Namespace: defaultAddonDeploymentConfig.GetNamespace(), + }, + // No Spec hash - should get filled in by addon-framework controllers + }, + }, + } + err = testK8sClient.Status().Update(testCtx, clusterManagementAddon) + if err != nil { + logger.Error(err, "Error updating CMA status") + return false + } + return true + }, timeout, interval).Should(BeTrue()) + + // Now reload the cma - and confirm that the specHash actually gets updated in the + // CMA.status.defaultconfigreferences + // (this part should get updated by the controllers started by the addon-framework) + // Not sure why this part is still done by addon-framework when others have been moved to the + // hub, but it seems to work + Eventually(func() bool { + err := testK8sClient.Get(testCtx, client.ObjectKeyFromObject(clusterManagementAddon), clusterManagementAddon) + if err != nil { + return false + } + if len(clusterManagementAddon.Status.DefaultConfigReferences) == 0 || + clusterManagementAddon.Status.DefaultConfigReferences[0].DesiredConfig == nil || + clusterManagementAddon.Status.DefaultConfigReferences[0].DesiredConfig.SpecHash == "" { + return false + } + return true + }, timeout, interval).Should(BeTrue()) + + // The controller that used to update the managedClusterAddOn status with the deploymentconfig + // has been moved to a common controller in the ocm hub - so simulate status update so our + // code can proceed + // + // Set the value to the default addon deployment config specified in the CMA. + // This kind of invalidates the tests below as they were testing that a controller + // would set this stuff - but since addon-framework doesn't do it anymore, we need to + // simulate it. + Eventually(func() error { + err := addDeploymentConfigStatusEntry(mcAddon, defaultAddonDeploymentConfig) + if err != nil { + // Reload the mcAddOn before we try again in case there was a conflict with updating + reloadErr := testK8sClient.Get(testCtx, client.ObjectKeyFromObject(mcAddon), mcAddon) + if reloadErr != nil { + return reloadErr + } + return err + } + return nil + }, timeout, interval).Should(Succeed()) + + manifestWork = &workv1.ManifestWork{} + // The controller should create a ManifestWork for this ManagedClusterAddon + Eventually(func() bool { + allMwList := &workv1.ManifestWorkList{} + Expect(testK8sClient.List(testCtx, allMwList, + client.InNamespace(testManagedCluster.GetName()))).To(Succeed()) + + for _, mw := range allMwList.Items { + // addon-framework now creates manifestwork with "-0" prefix (to allow for + // creating multiple manifestworks if the content is large - will not be the case + // for VolSync - so we could alternatively just search for addon-volsync-deploy-0) + if strings.HasPrefix(mw.GetName(), "addon-volsync-deploy") == true { + manifestWork = &mw + break + } + } + + if len(manifestWork.Spec.Workload.Manifests) == 0 { + return false + } + + // Subscription + subMF := manifestWork.Spec.Workload.Manifests[0] + subObj, _, err := genericCodec.Decode(subMF.Raw, nil, nil) + Expect(err).NotTo(HaveOccurred()) + var ok bool + operatorSubscription, ok = subObj.(*operatorsv1alpha1.Subscription) + if !ok { + return false + } + return operatorSubscription.Spec.Config != nil + }, timeout, interval).Should(BeTrue()) + + Expect(manifestWork).ToNot(BeNil()) + Expect(operatorSubscription).NotTo(BeNil()) + Expect(operatorSubscription.GetNamespace()).To(Equal("openshift-operators")) + Expect(operatorSubscription.Spec.Package).To(Equal("volsync-product")) // This is the "name" in json + + // Check the annotation was still honoured + Expect(operatorSubscription.Spec.Channel).To(Equal("stable")) + }) + + Context("When a ManagedClusterAddOn is created with no addonConfig specified (the default)", func() { + It("Should create the sub in the manifestwork with the default node selector and tolerations", func() { + // re-load the addon - status should be updated with details of the default deploymentConfig + Expect(testK8sClient.Get(testCtx, client.ObjectKeyFromObject(mcAddon), mcAddon)).To(Succeed()) + // Should be 1 config ref (our default addondeploymentconfig) + Expect(len(mcAddon.Status.ConfigReferences)).To(Equal(1)) + defaultConfigRef := mcAddon.Status.ConfigReferences[0] + Expect(defaultConfigRef.DesiredConfig).NotTo(BeNil()) + Expect(defaultConfigRef.DesiredConfig.Name).To(Equal(defaultAddonDeploymentConfig.GetName())) + Expect(defaultConfigRef.DesiredConfig.Namespace).To(Equal(defaultAddonDeploymentConfig.GetNamespace())) + Expect(defaultConfigRef.DesiredConfig.SpecHash).NotTo(Equal("")) // SpecHash should be set by controller + + Expect(operatorSubscription.Spec.Config).ToNot(BeNil()) + Expect(operatorSubscription.Spec.Config.NodeSelector).To(Equal(defaultNodePlacement.NodeSelector)) + Expect(operatorSubscription.Spec.Config.Tolerations).To(Equal(defaultNodePlacement.Tolerations)) + }) + }) + + Context("When a ManagedClusterAddOn is created with addonConfig (node selectors and tolerations)", func() { + var addonDeploymentConfig *addonv1alpha1.AddOnDeploymentConfig + nodePlacement := &addonv1alpha1.NodePlacement{ + NodeSelector: map[string]string{ + "key1": "value1", + "key2": "value2", + }, + Tolerations: []corev1.Toleration{ + { + Key: "node.kubernetes.io/unreachable", + Operator: corev1.TolerationOpExists, + Effect: corev1.TaintEffectNoSchedule, + }, + { + Key: "mykey", + Value: "myvalue", + Operator: corev1.TolerationOpEqual, + Effect: corev1.TaintEffectNoExecute, + }, + }, + } + BeforeEach(func() { + addonDeploymentConfig = createAddonDeploymentConfig(nodePlacement) + + // Update the managedclusteraddon before we create it to add the addondeploymentconfig + mcAddon.Spec.Configs = []addonv1alpha1.AddOnConfig{ + { + ConfigGroupResource: addonv1alpha1.ConfigGroupResource{ + Group: "addon.open-cluster-management.io", + Resource: "addondeploymentconfigs", + }, + ConfigReferent: addonv1alpha1.ConfigReferent{ + Name: addonDeploymentConfig.GetName(), + Namespace: addonDeploymentConfig.GetNamespace(), + }, + }, + } + }) + AfterEach(func() { + cleanupAddonDeploymentConfig(addonDeploymentConfig, true) + }) + + JustBeforeEach(func() { + // Need to override the managedclusteraddonstatus to instead use the + // addondeploymentconfig instead of the default one from the CMA + // (would be done by a common controller on the ocm hub). + // Unfortunately we're not really testing which addondeployconfig gets picked + // anymore, as the controllers that do this are no longer part of the addon-framework. + // + // The controller that used to update the managedClusterAddOn status with the deploymentconfig + // has been moved to a common controller in the ocm hub - so simulate status update so our + // code can proceed + Eventually(func() error { + err := addDeploymentConfigStatusEntry(mcAddon, addonDeploymentConfig) + if err != nil { + // Reload the mcAddOn before we try again in case there was a conflict with updating + reloadErr := testK8sClient.Get(testCtx, client.ObjectKeyFromObject(mcAddon), mcAddon) + if reloadErr != nil { + return reloadErr + } + return err + } + return nil + }, timeout, interval).Should(Succeed()) + + }) + + It("Should create the sub in the manifestwork with the node selector and tolerations from "+ + " the managedclusteraddon, not the defaults", func() { + // Now re-load the manifestwork, based on timing it could haver originally + // been updated with the defaults from the CMA - eventually should get updated properly + Eventually(func() bool { + reloadErr := testK8sClient.Get(testCtx, client.ObjectKeyFromObject(manifestWork), manifestWork) + if reloadErr != nil { + return false + } + + // get Subscription from the manifestwork + subMF := manifestWork.Spec.Workload.Manifests[0] + subObj, _, err := genericCodec.Decode(subMF.Raw, nil, nil) + Expect(err).NotTo(HaveOccurred()) + var ok bool + operatorSubscription, ok = subObj.(*operatorsv1alpha1.Subscription) + if !ok { + return false + } + if operatorSubscription.Spec.Config == nil { + return false + } + + // Check that the node selector matches the # of keys from the addondeploymentconfig + // It won't match if the subscription is still using the default addondeploymentconfig + // as it has different nodeSelector + return len(operatorSubscription.Spec.Config.NodeSelector) == len(nodePlacement.NodeSelector) + }, timeout, interval).Should(BeTrue()) + + // re-load the addon - status should be updated with details of the default deploymentConfig + Expect(testK8sClient.Get(testCtx, client.ObjectKeyFromObject(mcAddon), mcAddon)).To(Succeed()) + // Should be 1 config ref (our custom addondeploymentconfig) + Expect(len(mcAddon.Status.ConfigReferences)).To(Equal(1)) + defaultConfigRef := mcAddon.Status.ConfigReferences[0] + Expect(defaultConfigRef.DesiredConfig).NotTo(BeNil()) + Expect(defaultConfigRef.DesiredConfig.Name).To(Equal(addonDeploymentConfig.GetName())) + Expect(defaultConfigRef.DesiredConfig.Namespace).To(Equal(addonDeploymentConfig.GetNamespace())) + Expect(defaultConfigRef.DesiredConfig.SpecHash).NotTo(Equal("")) // SpecHash should be set by controller + + Expect(operatorSubscription.Spec.Config).ToNot(BeNil()) + Expect(operatorSubscription.Spec.Config.NodeSelector).To(Equal(nodePlacement.NodeSelector)) + Expect(operatorSubscription.Spec.Config.Tolerations).To(Equal(nodePlacement.Tolerations)) + }) + }) + }) + }) + }) + + /* + Context("When a ManagedClusterExists with the install volsync addon label", func() { + var testManagedCluster *clusterv1.ManagedCluster + var testManagedClusterNamespace *corev1.Namespace + + BeforeEach(func() { + // Create a managed cluster CR to use for this test - with volsync addon install label + testManagedCluster = &clusterv1.ManagedCluster{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "addon-mgdcluster-", + Labels: map[string]string{ + "vendor": "OpenShift", + controllers.ManagedClusterInstallVolSyncLabel: controllers.ManagedClusterInstallVolSyncLabelValue, + }, + }, + } + + Expect(testK8sClient.Create(testCtx, testManagedCluster)).To(Succeed()) + Expect(testManagedCluster.Name).NotTo(BeEmpty()) + + // Fake the status of the mgd cluster to be available + Eventually(func() error { + err := testK8sClient.Get(testCtx, client.ObjectKeyFromObject(testManagedCluster), testManagedCluster) + if err != nil { + return err + } + + clusterAvailableCondition := metav1.Condition{ + Type: clusterv1.ManagedClusterConditionAvailable, + Status: metav1.ConditionTrue, + Reason: "testupdate", + Message: "faking cluster available for test", + } + meta.SetStatusCondition(&testManagedCluster.Status.Conditions, clusterAvailableCondition) + + return testK8sClient.Status().Update(testCtx, testManagedCluster) + }, timeout, interval).Should(Succeed()) + + // Create a matching namespace for this managed cluster + // (namespace with name=managedclustername is expected to exist on the hub) + testManagedClusterNamespace = &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: testManagedCluster.GetName(), + }, + } + Expect(testK8sClient.Create(testCtx, testManagedClusterNamespace)).To(Succeed()) + }) + + It("Should automatically create a ManagedClusterAddon for volsync in the managedcluster namespace", func() { + vsAddon := &addonv1alpha1.ManagedClusterAddOn{} + + // The controller should create a volsync ManagedClusterAddOn in the ManagedCluster NS + Eventually(func() error { + return testK8sClient.Get(testCtx, types.NamespacedName{ + Name: "volsync", + Namespace: testManagedCluster.GetName(), + }, vsAddon) + }, timeout, interval).Should(Succeed()) + + // This ns is now the default in the mcao crd so will be used since we don't set it - note we ignore + // this and use openshift-operators (see the created subscription) + Expect(vsAddon.Spec.InstallNamespace).To(Equal("open-cluster-management-agent-addon")) + }) + }) + */ +}) + +var _ = Describe("Addon Status Update Tests", func() { + logger := zap.New(zap.UseDevMode(true), zap.WriteTo(GinkgoWriter)) + + // Make sure a ClusterManagementAddOn exists for volsync or addon-framework will not reconcile + // VolSync ManagedClusterAddOns + var clusterManagementAddon *addonv1alpha1.ClusterManagementAddOn + + BeforeEach(func() { + // clustermanagementaddon (this is a global resource) + clusterManagementAddon = &addonv1alpha1.ClusterManagementAddOn{ + ObjectMeta: metav1.ObjectMeta{ + Name: "volsync", + }, + Spec: addonv1alpha1.ClusterManagementAddOnSpec{ + AddOnMeta: addonv1alpha1.AddOnMeta{ + DisplayName: "VolSync", + Description: "VolSync", + }, + SupportedConfigs: []addonv1alpha1.ConfigMeta{ + { + ConfigGroupResource: addonv1alpha1.ConfigGroupResource{ + Group: "addon.open-cluster-management.io", + Resource: "addondeploymentconfigs", + }, + }, + }, + InstallStrategy: addonv1alpha1.InstallStrategy{ + Type: addonv1alpha1.AddonInstallStrategyManual, + }, + }, + } + }) + AfterEach(func() { + Expect(testK8sClient.Delete(testCtx, clusterManagementAddon)).To(Succeed()) + }) + + JustBeforeEach(func() { + // Create the clustermanagementaddon here so tests can modify it in their BeforeEach() + // before we create it + Expect(testK8sClient.Create(testCtx, clusterManagementAddon)).To(Succeed()) + }) + + Context("When a ManagedClusterExists", func() { + var testManagedCluster *clusterv1.ManagedCluster + var testManagedClusterNamespace *corev1.Namespace + + BeforeEach(func() { + // Create a managed cluster CR to use for this test + testManagedCluster = &clusterv1.ManagedCluster{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "addon-inst-mgdcluster-", + Labels: map[string]string{ + "vendor": "OpenShift", + }, + }, + } + }) + + JustBeforeEach(func() { + Expect(testK8sClient.Create(testCtx, testManagedCluster)).To(Succeed()) + Expect(testManagedCluster.Name).NotTo(BeEmpty()) + + // Fake the status of the mgd cluster to be available + Eventually(func() error { + err := testK8sClient.Get(testCtx, client.ObjectKeyFromObject(testManagedCluster), testManagedCluster) + if err != nil { + return err + } + + clusterAvailableCondition := metav1.Condition{ + Type: clusterv1.ManagedClusterConditionAvailable, + Status: metav1.ConditionTrue, + Reason: "testupdate", + Message: "faking cluster available for test", + } + meta.SetStatusCondition(&testManagedCluster.Status.Conditions, clusterAvailableCondition) + + return testK8sClient.Status().Update(testCtx, testManagedCluster) + }, timeout, interval).Should(Succeed()) + + // Create a matching namespace for this managed cluster + // (namespace with name=managedclustername is expected to exist on the hub) + testManagedClusterNamespace = &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: testManagedCluster.GetName(), + }, + } + Expect(testK8sClient.Create(testCtx, testManagedClusterNamespace)).To(Succeed()) + }) + + Context("When a ManagedClusterAddon for this addon is created", func() { + var mcAddon *addonv1alpha1.ManagedClusterAddOn + JustBeforeEach(func() { + // Create a ManagedClusterAddon for the mgd cluster + mcAddon = &addonv1alpha1.ManagedClusterAddOn{ + ObjectMeta: metav1.ObjectMeta{ + Name: "volsync", + Namespace: testManagedClusterNamespace.GetName(), + Annotations: map[string]string{ + // Need to set special annotation to use OLM mode + //nolint: lll + controllers.AnnotationVolSyncAddonDeployTypeOverride: controllers.AnnotationVolSyncAddonDeployTypeOverrideOLMValue, + }, + }, + Spec: addonv1alpha1.ManagedClusterAddOnSpec{}, + } + Expect(testK8sClient.Create(testCtx, mcAddon)).To(Succeed()) + + // Need to have the CMA as owner on the managedclusteraddon or the registration controller + // will ignore it (and therefore addondeploy controller won't call our Manifests() func) + // This step is normally done by a global controller on the hub - so simulate for our tests + Eventually(func() error { + err := addCMAOwnership(clusterManagementAddon, mcAddon) + if err != nil { + // Reload the mcAddOn before we try again in case there was a conflict with updating + reloadErr := testK8sClient.Get(testCtx, client.ObjectKeyFromObject(mcAddon), mcAddon) + if reloadErr != nil { + return reloadErr + } + return err + } + return nil + }, timeout, interval).Should(Succeed()) + }) + + Context("When the managed cluster is an OpenShiftCluster and manifestwork is available", func() { + JustBeforeEach(func() { + // The controller should create a ManifestWork for this ManagedClusterAddon + // Fake out that the ManifestWork is applied and available + Eventually(func() error { + var manifestWork *workv1.ManifestWork + + allMwList := &workv1.ManifestWorkList{} + Expect(testK8sClient.List(testCtx, allMwList, + client.InNamespace(testManagedCluster.GetName()))).To(Succeed()) + + for _, mw := range allMwList.Items { + if strings.HasPrefix(mw.GetName(), "addon-volsync-deploy") == true { + manifestWork = &mw + break + } + } + + if manifestWork == nil { + return fmt.Errorf("Did not find the manifestwork with prefix addon-volsync-deploy") + } + + workAppliedCondition := metav1.Condition{ + Type: workv1.WorkApplied, + Status: metav1.ConditionTrue, + Reason: "testupdate", + Message: "faking applied for test", + } + meta.SetStatusCondition(&manifestWork.Status.Conditions, workAppliedCondition) + + workAvailableCondition := metav1.Condition{ + Type: workv1.WorkAvailable, + Status: metav1.ConditionTrue, + Reason: "testupdate", + Message: "faking available for test", + } + meta.SetStatusCondition(&manifestWork.Status.Conditions, workAvailableCondition) + + return testK8sClient.Status().Update(testCtx, manifestWork) + }, timeout, interval).Should(Succeed()) + }) + + Context("When the manifestwork statusFeedback is not available", func() { + It("Should set the ManagedClusterAddon status to unavailable", func() { + var statusCondition *metav1.Condition + Eventually(func() bool { + err := testK8sClient.Get(testCtx, types.NamespacedName{ + Name: "volsync", + Namespace: testManagedClusterNamespace.GetName(), + }, mcAddon) + if err != nil { + return false + } + + statusCondition = meta.FindStatusCondition(mcAddon.Status.Conditions, + addonv1alpha1.ManagedClusterAddOnConditionAvailable) + return statusCondition != nil + }, timeout, interval).Should(BeTrue()) + + Expect(statusCondition.Reason).To(Equal("ProbeUnavailable")) + Expect(statusCondition.Status).To(Equal(metav1.ConditionFalse)) + }) + }) + + Context("When the manifestwork statusFeedback is returned with a bad value", func() { + JustBeforeEach(func() { + Eventually(func() error { + // Update the manifestwork to set the statusfeedback to a bad value + var manifestWork *workv1.ManifestWork + + allMwList := &workv1.ManifestWorkList{} + Expect(testK8sClient.List(testCtx, allMwList, + client.InNamespace(testManagedCluster.GetName()))).To(Succeed()) + + for _, mw := range allMwList.Items { + if strings.HasPrefix(mw.GetName(), "addon-volsync-deploy") == true { + manifestWork = &mw + break + } + } + + if manifestWork == nil { + return fmt.Errorf("Did not find the manifestwork with prefix addon-volsync-deploy") + } + + manifestWork.Status.ResourceStatus = manifestWorkResourceStatusWithSubscriptionInstalledCSVFeedBack( + "notinstalled") + + return testK8sClient.Status().Update(testCtx, manifestWork) + }, timeout, interval).Should(Succeed()) + }) + + It("Should set the ManagedClusterAddon status to unavailable", func() { + var statusCondition *metav1.Condition + Eventually(func() bool { + err := testK8sClient.Get(testCtx, types.NamespacedName{ + Name: "volsync", + Namespace: testManagedClusterNamespace.GetName(), + }, mcAddon) + if err != nil { + return false + } + + statusCondition = meta.FindStatusCondition(mcAddon.Status.Conditions, + addonv1alpha1.ManagedClusterAddOnConditionAvailable) + if statusCondition == nil { + return false + } + logger.Info("statusCondition", "statusCondition", &statusCondition) + return statusCondition.Reason == "ProbeUnavailable" + }, timeout, interval).Should(BeTrue()) + + Expect(statusCondition.Reason).To(Equal("ProbeUnavailable")) + Expect(statusCondition.Status).To(Equal(metav1.ConditionFalse)) + Expect(statusCondition.Message).To(ContainSubstring("Probe addon unavailable with err")) + Expect(statusCondition.Message).To(ContainSubstring("addon subscription not found")) + }) + }) + + Context("When the manifestwork statusFeedback is returned with a correct installed value", func() { + JustBeforeEach(func() { + Eventually(func() error { + // Update the manifestwork to set the statusfeedback to a bad value + var manifestWork *workv1.ManifestWork + + allMwList := &workv1.ManifestWorkList{} + Expect(testK8sClient.List(testCtx, allMwList, + client.InNamespace(testManagedCluster.GetName()))).To(Succeed()) + + for _, mw := range allMwList.Items { + if strings.HasPrefix(mw.GetName(), "addon-volsync-deploy") == true { + manifestWork = &mw + break + } + } + + if manifestWork == nil { + return fmt.Errorf("Did not find the manifestwork with prefix addon-volsync-deploy") + } + + manifestWork.Status.ResourceStatus = manifestWorkResourceStatusWithSubscriptionInstalledCSVFeedBack( + "volsync-product.v0.4.0") + + return testK8sClient.Status().Update(testCtx, manifestWork) + }, timeout, interval).Should(Succeed()) + }) + + It("Should set the ManagedClusterAddon status to available", func() { + var statusCondition *metav1.Condition + Eventually(func() bool { + err := testK8sClient.Get(testCtx, types.NamespacedName{ + Name: "volsync", + Namespace: testManagedClusterNamespace.GetName(), + }, mcAddon) + if err != nil { + return false + } + + statusCondition = meta.FindStatusCondition(mcAddon.Status.Conditions, + addonv1alpha1.ManagedClusterAddOnConditionAvailable) + if statusCondition == nil { + return false + } + return statusCondition.Reason == "ProbeAvailable" + }, timeout, interval).Should(BeTrue()) + + logger.Info("#### status condition", "statusCondition", statusCondition) + + Expect(statusCondition.Reason).To(Equal("ProbeAvailable")) + Expect(statusCondition.Status).To(Equal(metav1.ConditionTrue)) + Expect(statusCondition.Message).To(ContainSubstring("volsync add-on is available")) + }) + }) + }) + }) + }) +}) + +func manifestWorkResourceStatusWithSubscriptionInstalledCSVFeedBack( + installedCSVValue string, +) workv1.ManifestResourceStatus { + return workv1.ManifestResourceStatus{ + Manifests: []workv1.ManifestCondition{ + { + ResourceMeta: workv1.ManifestResourceMeta{ + Group: "operators.coreos.com", + Kind: "Subscription", + Name: "volsync-product", + Namespace: "openshift-operators", + Resource: "subscriptions", + Version: "v1alpha1", + }, + StatusFeedbacks: workv1.StatusFeedbackResult{ + Values: []workv1.FeedbackValue{ + { + Name: "installedCSV", + Value: workv1.FieldValue{ + Type: "String", + String: &installedCSVValue, + }, + }, + }, + }, + Conditions: []metav1.Condition{}, + }, + }, + } +} diff --git a/controllers/addoncontroller_test.go b/controllers/addoncontroller_test.go index d3dcf0b..b2b05f6 100644 --- a/controllers/addoncontroller_test.go +++ b/controllers/addoncontroller_test.go @@ -6,26 +6,35 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/serializer" "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/yaml" "k8s.io/client-go/kubernetes/scheme" "sigs.k8s.io/controller-runtime/pkg/client" ctrlutil "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/log/zap" - operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" addonframeworkutils "open-cluster-management.io/addon-framework/pkg/utils" addonv1alpha1 "open-cluster-management.io/api/addon/v1alpha1" clusterv1 "open-cluster-management.io/api/cluster/v1" workv1 "open-cluster-management.io/api/work/v1" + policyv1 "open-cluster-management.io/config-policy-controller/api/v1" + policyv1beta1 "open-cluster-management.io/config-policy-controller/api/v1beta1" "github.com/stolostron/volsync-addon-controller/controllers" + "github.com/stolostron/volsync-addon-controller/controllers/helmutils/helmutilstest" ) -var _ = Describe("Addoncontroller", func() { +// These tests are for deployment of VolSync as an OLM subscription +// This is the old behavior and will not be used by default +// (Only enabled if annotation is set on the managedclusteraddon) +var _ = Describe("Addoncontroller - helm deployment tests", func() { logger := zap.New(zap.UseDevMode(true), zap.WriteTo(GinkgoWriter)) genericCodecs := serializer.NewCodecFactory(scheme.Scheme) @@ -70,33 +79,6 @@ var _ = Describe("Addoncontroller", func() { Expect(testK8sClient.Create(testCtx, clusterManagementAddon)).To(Succeed()) }) - /* - Describe("addon-framework checks - ClusterManagementAddon updated correctly", func() { - It("Should update the ClusterManagementAddon with addon.open-cluster-management.io/lifecycle annotation "+ - "set to 'self'", func() { - // Addon controller should be updating the CMA (via addon-framework) - Eventually(func() bool { - // re-load ClusterManagementAddon and check that it gets updated - err := testK8sClient.Get(testCtx, client.ObjectKeyFromObject(clusterManagementAddon), clusterManagementAddon) - if err != nil { - return false - } - - v, ok := clusterManagementAddon.GetAnnotations()[addonv1alpha1.AddonLifecycleAnnotationKey] - if !ok { - return false - } - logger.Info("CMA", "clusterManagementAddon", &clusterManagementAddon) - - // Annotation value should be set to "self" - Expect(v).To(Equal(addonv1alpha1.AddonLifecycleSelfManageAnnotationValue)) - - return true - }, timeout, interval).Should(BeTrue()) - }) - }) - */ - Context("When a ManagedClusterExists", func() { var testManagedCluster *clusterv1.ManagedCluster var testManagedClusterNamespace *corev1.Namespace @@ -147,7 +129,7 @@ var _ = Describe("Addoncontroller", func() { var mcAddon *addonv1alpha1.ManagedClusterAddOn var manifestWork *workv1.ManifestWork BeforeEach(func() { - // Create a ManagedClusterAddon for the mgd cluster + // ManagedClusterAddon for the mgd cluster mcAddon = &addonv1alpha1.ManagedClusterAddOn{ ObjectMeta: metav1.ObjectMeta{ Name: "volsync", @@ -198,155 +180,156 @@ var _ = Describe("Addoncontroller", func() { Expect(manifestWork).ToNot(BeNil()) }) - Context("When installing into openshift-operators namespace (the default)", func() { - var operatorSubscription *operatorsv1alpha1.Subscription + testMgdClusterIsOpenShift := []bool{ + true, + false, + } - JustBeforeEach(func() { - // When installing into the global operator namespace (openshift-operators) - // we should expect the manifestwork to contain only: - // - the operator subscription - Expect(len(manifestWork.Spec.Workload.Manifests)).To(Equal(1)) - - // Subscription - subMF := manifestWork.Spec.Workload.Manifests[0] - subObj, _, err := genericCodec.Decode(subMF.Raw, nil, nil) - Expect(err).NotTo(HaveOccurred()) - var ok bool - operatorSubscription, ok = subObj.(*operatorsv1alpha1.Subscription) - Expect(ok).To(BeTrue()) - Expect(operatorSubscription).NotTo(BeNil()) - Expect(operatorSubscription.GetNamespace()).To(Equal("openshift-operators")) - Expect(operatorSubscription.Spec.Package).To(Equal("volsync-product")) // This is the "name" in json + for i := range testMgdClusterIsOpenShift { + mgdClusterIsOpenShift := testMgdClusterIsOpenShift[i] - // No addonDeploymentConfig in these tests, so the operatorSub should not have any Config specified - Expect(operatorSubscription.Spec.Config).To(BeNil()) + whenText := "is OpenShift" + if !mgdClusterIsOpenShift { + whenText = "is NOT OpenShift" + } - // More specific checks done in tests - }) + Context(fmt.Sprintf("When the managed cluster %s", whenText), func() { + expectedNamespace := controllers.DefaultHelmInstallNamespace + + var namespaceObj *corev1.Namespace + var operatorPolicyObj *policyv1beta1.OperatorPolicy + var operatorPolicyAggregateClusterRoleObj *rbacv1.ClusterRole + var helmChartObjs []runtime.Object - Context("When the ManagedClusterAddOn spec set an installNamespace", func() { BeforeEach(func() { - // Override to specifically set the ns in the spec - all the tests above in JustBeforeEach - // should still be valid here - mcAddon.Spec.InstallNamespace = "test1234" - }) - It("Should still install to the default openshift-operators namespace", func() { - // Code shouldn't have alterted the spec - but tests above will confirm that the - // operatorgroup/subscription were created in volsync-system - Expect(mcAddon.Spec.InstallNamespace).To(Equal("test1234")) - }) - }) + namespaceObj = nil + operatorPolicyObj = nil + operatorPolicyAggregateClusterRoleObj = nil + helmChartObjs = nil - Context("When no annotations are on the managedclusteraddon", func() { - It("Should create the subscription (within the ManifestWork) with proper defaults", func() { - // This ns is now the default in the mcao crd so will be used - note we ignore this - // and use openshift-operators (see the created subscription) - Expect(mcAddon.Spec.InstallNamespace).To(Equal("open-cluster-management-agent-addon")) - - Expect(operatorSubscription.Spec.Channel).To(Equal(controllers.DefaultChannel)) - Expect(string(operatorSubscription.Spec.InstallPlanApproval)).To(Equal( - controllers.DefaultInstallPlanApproval)) - Expect(operatorSubscription.Spec.CatalogSource).To(Equal(controllers.DefaultCatalogSource)) - Expect(operatorSubscription.Spec.CatalogSourceNamespace).To(Equal( - controllers.DefaultCatalogSourceNamespace)) - Expect(operatorSubscription.Spec.StartingCSV).To(Equal(controllers.DefaultStartingCSV)) - }) - }) + logger.Info("BeforeEach", "mgdClusterIsOpenShift", mgdClusterIsOpenShift) + if !mgdClusterIsOpenShift { + Eventually(func() error { + // Test managed cluster was already created in parent BeforeEach(), reload it and + // update to remove the label that shows that it's an Openshift cluster + err := testK8sClient.Get(testCtx, client.ObjectKeyFromObject(testManagedCluster), testManagedCluster) + if err != nil { + return err + } - Context("When the annotation to override the CatalogSource is on the managedclusteraddon", func() { - BeforeEach(func() { - mcAddon.Annotations = map[string]string{ - controllers.AnnotationCatalogSourceOverride: "customcatalog-source", + // Delete label that indicates the mgd cluster is openshift + delete(testManagedCluster.Labels, "vendor") + + return testK8sClient.Update(testCtx, testManagedCluster) + }, timeout, interval).Should(Succeed()) } }) - It("Should create the subscription (within the ManifestWork) with proper CatalogSource", func() { - Expect(operatorSubscription.Spec.CatalogSource).To(Equal("customcatalog-source")) - - // The rest should be defaults - Expect(operatorSubscription.Spec.Channel).To(Equal(controllers.DefaultChannel)) - Expect(string(operatorSubscription.Spec.InstallPlanApproval)).To(Equal( - controllers.DefaultInstallPlanApproval)) - Expect(operatorSubscription.Spec.CatalogSourceNamespace).To(Equal( - controllers.DefaultCatalogSourceNamespace)) - Expect(operatorSubscription.Spec.StartingCSV).To(Equal(controllers.DefaultStartingCSV)) - }) - }) - Context("When the annotation to override the CatalogSourceNS is on the managedclusteraddon", func() { - BeforeEach(func() { - mcAddon.Annotations = map[string]string{ - controllers.AnnotationCatalogSourceNamespaceOverride: "my-catalog-source-ns", + JustBeforeEach(func() { + if mgdClusterIsOpenShift { + // 2 additional objects in manifest for OpenShift clusters, + // an OperatorPolicy to make sure OLM operator is uninstalled in the mgd cluster + // and also an aggregateclusterrole for the operatorpolicy + Expect(len(manifestWork.Spec.Workload.Manifests)).To(Equal(15)) + } else { + Expect(len(manifestWork.Spec.Workload.Manifests)).To(Equal(13)) } - }) - It("Should create the subscription (within the ManifestWork) with proper CatalogSourceNS", func() { - Expect(operatorSubscription.Spec.CatalogSourceNamespace).To(Equal( - "my-catalog-source-ns")) - - // The rest should be defaults - Expect(operatorSubscription.Spec.Channel).To(Equal(controllers.DefaultChannel)) - Expect(string(operatorSubscription.Spec.InstallPlanApproval)).To(Equal( - controllers.DefaultInstallPlanApproval)) - Expect(operatorSubscription.Spec.CatalogSource).To(Equal(controllers.DefaultCatalogSource)) - Expect(operatorSubscription.Spec.StartingCSV).To(Equal(controllers.DefaultStartingCSV)) - }) - }) - Context("When the annotation to override the InstallPlanApproval is on the managedclusteraddon", func() { - BeforeEach(func() { - mcAddon.Annotations = map[string]string{ - controllers.AnnotationInstallPlanApprovalOverride: "Manual", + // Get objects from our manifest that are not part of the helm chart + for _, m := range manifestWork.Spec.Workload.Manifests { + obj, _, err := genericCodec.Decode(m.Raw, nil, nil) + Expect(err).NotTo(HaveOccurred()) + objKind := obj.GetObjectKind().GroupVersionKind().Kind + + switch objKind { + case "OperatorPolicy": + op, ok := obj.(*policyv1beta1.OperatorPolicy) + Expect(ok).To(BeTrue()) + operatorPolicyObj = op + case "ClusterRole": + cr, ok := obj.(*rbacv1.ClusterRole) + Expect(ok).To(BeTrue()) + if strings.Contains(cr.GetName(), "operatorpolicy-aggregate") { + // This is our operator policy clusterrole + operatorPolicyAggregateClusterRoleObj = cr + } else { + // This is a clusterrole from the helm chart + helmChartObjs = append(helmChartObjs, obj) + } + case "Namespace": + ns, ok := obj.(*corev1.Namespace) + Expect(ok).To(BeTrue()) + namespaceObj = ns + default: + // This object came from the helm chart + helmChartObjs = append(helmChartObjs, obj) + } } - }) - It("Should create the subscription (within the ManifestWork) with proper CatalogSourceNS", func() { - Expect(string(operatorSubscription.Spec.InstallPlanApproval)).To(Equal("Manual")) - - // The rest should be defaults - Expect(operatorSubscription.Spec.Channel).To(Equal(controllers.DefaultChannel)) - Expect(operatorSubscription.Spec.CatalogSource).To(Equal(controllers.DefaultCatalogSource)) - Expect(operatorSubscription.Spec.CatalogSourceNamespace).To(Equal( - controllers.DefaultCatalogSourceNamespace)) - Expect(operatorSubscription.Spec.StartingCSV).To(Equal(controllers.DefaultStartingCSV)) - }) - }) - Context("When the annotation to override the Channel is on the managedclusteraddon", func() { - BeforeEach(func() { - mcAddon.Annotations = map[string]string{ - controllers.AnnotationChannelOverride: "special-channel-1.2.3", + Expect(namespaceObj).NotTo(BeNil()) + + if mgdClusterIsOpenShift { + Expect(operatorPolicyObj).NotTo(BeNil()) + Expect(operatorPolicyAggregateClusterRoleObj).NotTo(BeNil()) + + // OperatorPolicy (on the mgd cluster) needs to be in the ns named the same as the mgd cluster + Expect(operatorPolicyObj.GetNamespace()).To(Equal(testManagedCluster.GetName())) + Expect(strings.EqualFold( + string(operatorPolicyObj.Spec.ComplianceType), string(policyv1.MustNotHave))).To(BeTrue()) + Expect(strings.EqualFold( + string(operatorPolicyObj.Spec.RemediationAction), string(policyv1.Enforce))).To(BeTrue()) + Expect(operatorPolicyObj.Spec.RemovalBehavior).To(Equal( + policyv1beta1.RemovalBehavior{ + CSVs: policyv1beta1.Delete, + CRDs: policyv1beta1.Keep, // this is important! + OperatorGroups: policyv1beta1.Keep, + Subscriptions: policyv1beta1.Delete, + })) + + type nameAndNamspace struct { + Name string `yaml:"name"` + Namespace string `yaml:"namespace"` + } + objSubNameAndNamespace := nameAndNamspace{} + Expect(yaml.Unmarshal(operatorPolicyObj.Spec.Subscription.Raw, &objSubNameAndNamespace)).To(Succeed()) + + Expect(objSubNameAndNamespace.Name).To(Equal("volsync-product")) + Expect(objSubNameAndNamespace.Namespace).To(Equal("openshift-operators")) + } else { + // No operatorpolicy or aggregate cluster role needed for non-OpenShift + Expect(operatorPolicyObj).To(BeNil()) + Expect(operatorPolicyAggregateClusterRoleObj).To(BeNil()) } + + // In all cases here we expect the namespace to be the default + Expect(namespaceObj.GetName()).To(Equal(expectedNamespace)) }) - It("Should create the subscription (within the ManifestWork) with proper CatalogSourceNS", func() { - Expect(operatorSubscription.Spec.Channel).To(Equal("special-channel-1.2.3")) - - // The rest should be defaults - Expect(string(operatorSubscription.Spec.InstallPlanApproval)).To(Equal( - controllers.DefaultInstallPlanApproval)) - Expect(operatorSubscription.Spec.CatalogSource).To(Equal(controllers.DefaultCatalogSource)) - Expect(operatorSubscription.Spec.CatalogSourceNamespace).To(Equal( - controllers.DefaultCatalogSourceNamespace)) - Expect(operatorSubscription.Spec.StartingCSV).To(Equal(controllers.DefaultStartingCSV)) - }) - }) - Context("When the annotation to override the StartingCSV is on the managedclusteraddon", func() { - BeforeEach(func() { - mcAddon.Annotations = map[string]string{ - controllers.AnnotationStartingCSVOverride: "volsync.v1.2.3.doesnotexist", - } + Context("When the ManagedClusterAddOn spec does not set an installNamespace", func() { + It("Should install to default namespace", func() { + // should this get set in the managedclusteraddon.spec.InstallNamespace as well? + helmutilstest.VerifyHelmRenderedVolSyncObjects(helmChartObjs, + expectedNamespace, mgdClusterIsOpenShift) + }) }) - It("Should create the subscription (within the ManifestWork) with proper CatalogSourceNS", func() { - Expect(operatorSubscription.Spec.StartingCSV).To(Equal("volsync.v1.2.3.doesnotexist")) - - // The rest should be defaults - Expect(operatorSubscription.Spec.Channel).To(Equal(controllers.DefaultChannel)) - Expect(string(operatorSubscription.Spec.InstallPlanApproval)).To(Equal( - controllers.DefaultInstallPlanApproval)) - Expect(operatorSubscription.Spec.CatalogSource).To(Equal(controllers.DefaultCatalogSource)) - Expect(operatorSubscription.Spec.CatalogSourceNamespace).To(Equal( - controllers.DefaultCatalogSourceNamespace)) + + Context("When the ManagedClusterAddOn spec sets an installNamespace", func() { + BeforeEach(func() { + // Override to specifically set the ns in the spec - all the tests above in JustBeforeEach + // should still be valid here + mcAddon.Spec.InstallNamespace = "test1234" + }) + It("Should still install to the default namespace", func() { + // Code shouldn't have alterted the spec - but tests above will confirm that the + // operatorgroup/subscription were created in volsync-system + Expect(mcAddon.Spec.InstallNamespace).To(Equal("test1234")) + + helmutilstest.VerifyHelmRenderedVolSyncObjects(helmChartObjs, + expectedNamespace, mgdClusterIsOpenShift) + }) }) }) - }) + } }) Context("When the manifestwork already exists", func() { @@ -419,17 +402,9 @@ var _ = Describe("Addoncontroller", func() { myMw := &allMwList.Items[0] Expect(myMw.GetName()).To(Equal(fakeOlderMw.GetName())) - if len(myMw.Spec.Workload.Manifests) != 1 { - // Manifestwork hasn't been updated with the subscription yet - return false - } - - Expect(myMw.Spec.Workload.Manifests[0]) - subObj, _, err := genericCodec.Decode(myMw.Spec.Workload.Manifests[0].Raw, nil, nil) - Expect(err).NotTo(HaveOccurred()) - operatorSubscription, ok := subObj.(*operatorsv1alpha1.Subscription) - - return ok && operatorSubscription != nil + // Default test above simulates an openshift cluster, + // so expect 15 manifests in the manifestwork + return len(myMw.Spec.Workload.Manifests) == 15 }, timeout, interval).Should(BeTrue()) }) }) @@ -438,9 +413,13 @@ var _ = Describe("Addoncontroller", func() { Context("When a ManagedClusterAddOn is created with node selectors and tolerations", func() { var mcAddon *addonv1alpha1.ManagedClusterAddOn var manifestWork *workv1.ManifestWork - var operatorSubscription *operatorsv1alpha1.Subscription + // var operatorSubscription *operatorsv1alpha1.Subscription + + var volsyncDeployment *appsv1.Deployment BeforeEach(func() { + volsyncDeployment = nil + // Create a ManagedClusterAddon for the mgd cluster using an addonDeploymentconfig mcAddon = &addonv1alpha1.ManagedClusterAddOn{ ObjectMeta: metav1.ObjectMeta{ @@ -491,21 +470,18 @@ var _ = Describe("Addoncontroller", func() { Expect(manifestWork).ToNot(BeNil()) - // Subscription - subMF := manifestWork.Spec.Workload.Manifests[0] - subObj, _, err := genericCodec.Decode(subMF.Raw, nil, nil) + // Find the deployment in the manifestwork + var err error + volsyncDeployment, err = getVolSyncDeploymentFromManifestWork(manifestWork, genericCodec) Expect(err).NotTo(HaveOccurred()) - var ok bool - operatorSubscription, ok = subObj.(*operatorsv1alpha1.Subscription) - Expect(ok).To(BeTrue()) - Expect(operatorSubscription).NotTo(BeNil()) - Expect(operatorSubscription.GetNamespace()).To(Equal("openshift-operators")) - Expect(operatorSubscription.Spec.Package).To(Equal("volsync-product")) // This is the "name" in json + Expect(volsyncDeployment.GetNamespace()).To(Equal("volsync-system")) + Expect(volsyncDeployment.GetName()).To(Equal("volsync")) }) Context("When no addonDeploymentConfig is referenced", func() { - It("Should create the sub in the manifestwork with no tolerations or selectors", func() { - Expect(operatorSubscription.Spec.Config).To(BeNil()) + It("Should create deployment in the manifestwork with no tolerations or selectors", func() { + Expect(volsyncDeployment.Spec.Template.Spec.Tolerations).To(BeNil()) + Expect(volsyncDeployment.Spec.Template.Spec.NodeSelector).To(BeNil()) }) Context("When the managedclusteraddon is updated later with a addondeploymentconfig", func() { @@ -531,7 +507,8 @@ var _ = Describe("Addoncontroller", func() { }) It("Should update the existing manifestwork with the addondeploymentconfig", func() { - Expect(operatorSubscription.Spec.Config).To(BeNil()) + Expect(volsyncDeployment.Spec.Template.Spec.Tolerations).To(BeNil()) + Expect(volsyncDeployment.Spec.Template.Spec.NodeSelector).To(BeNil()) // Update the managedclusteraddon to reference the addonDeploymentConfig Eventually(func() error { @@ -578,7 +555,7 @@ var _ = Describe("Addoncontroller", func() { // and tolerations var manifestWorkReloaded *workv1.ManifestWork - var operatorSubscriptionReloaded *operatorsv1alpha1.Subscription + var volsyncDeploymentReloaded *appsv1.Deployment Eventually(func() bool { allMwList := &workv1.ManifestWorkList{} @@ -594,27 +571,25 @@ var _ = Describe("Addoncontroller", func() { break } } - - logger.Info(">>>>> ManifestWorkreloaded <<<", "manifestWorkReloaded", &manifestWorkReloaded) if manifestWorkReloaded == nil { return false } - // Subscription - subMF := manifestWorkReloaded.Spec.Workload.Manifests[0] - subObj, _, err := genericCodec.Decode(subMF.Raw, nil, nil) - Expect(err).NotTo(HaveOccurred()) - var ok bool - operatorSubscriptionReloaded, ok = subObj.(*operatorsv1alpha1.Subscription) - Expect(ok).To(BeTrue()) - Expect(operatorSubscriptionReloaded).NotTo(BeNil()) + // Find the deployment in the manifestwork + var err error + volsyncDeploymentReloaded, err = getVolSyncDeploymentFromManifestWork( + manifestWorkReloaded, genericCodec) + if err != nil { + return false + } - // If spec.config has been set, then it's been updated - return operatorSubscriptionReloaded.Spec.Config != nil + // If the deployment nodeSelector and tolerations have been set, then it's been updated + return volsyncDeploymentReloaded.Spec.Template.Spec.Tolerations != nil && + volsyncDeploymentReloaded.Spec.Template.Spec.NodeSelector != nil }, timeout, interval).Should(BeTrue()) - Expect(operatorSubscriptionReloaded.Spec.Config.NodeSelector).To(Equal(nodePlacement.NodeSelector)) - Expect(operatorSubscriptionReloaded.Spec.Config.Tolerations).To(Equal(nodePlacement.Tolerations)) + Expect(volsyncDeploymentReloaded.Spec.Template.Spec.NodeSelector).To(Equal(nodePlacement.NodeSelector)) + Expect(volsyncDeploymentReloaded.Spec.Template.Spec.Tolerations).To(Equal(nodePlacement.Tolerations)) }) }) }) @@ -672,23 +647,22 @@ var _ = Describe("Addoncontroller", func() { return false } - // get Subscription from the manifestwork - subMF := manifestWork.Spec.Workload.Manifests[0] - subObj, _, err := genericCodec.Decode(subMF.Raw, nil, nil) - Expect(err).NotTo(HaveOccurred()) - var ok bool - operatorSubscription, ok = subObj.(*operatorsv1alpha1.Subscription) - if !ok { + // Find the deployment in the manifestwork + var err error + volsyncDeployment, err = getVolSyncDeploymentFromManifestWork( + manifestWork, genericCodec) + if err != nil { return false } - return operatorSubscription.Spec.Config != nil + + // If the deployment nodeSelector has been set, then it's been updated + return volsyncDeployment.Spec.Template.Spec.NodeSelector != nil }, timeout, interval).Should(BeTrue()) }) - It("Should create the sub in the manifestwork wiith the node selector", func() { - Expect(operatorSubscription.Spec.Config).ToNot(BeNil()) - Expect(operatorSubscription.Spec.Config.NodeSelector).To(Equal(nodePlacement.NodeSelector)) - Expect(operatorSubscription.Spec.Config.Tolerations).To(BeNil()) // No tolerations set + It("Should create the deployment in the manifestwork wiith the node selector", func() { + Expect(volsyncDeployment.Spec.Template.Spec.NodeSelector).To(Equal(nodePlacement.NodeSelector)) + Expect(volsyncDeployment.Spec.Template.Spec.Tolerations).To(BeNil()) // No tolerations set }) }) @@ -748,27 +722,26 @@ var _ = Describe("Addoncontroller", func() { return false } - // get Subscription from the manifestwork - subMF := manifestWork.Spec.Workload.Manifests[0] - subObj, _, err := genericCodec.Decode(subMF.Raw, nil, nil) - Expect(err).NotTo(HaveOccurred()) - var ok bool - operatorSubscription, ok = subObj.(*operatorsv1alpha1.Subscription) - if !ok { + // Find the deployment in the manifestwork + var err error + volsyncDeployment, err = getVolSyncDeploymentFromManifestWork( + manifestWork, genericCodec) + if err != nil { return false } - return operatorSubscription.Spec.Config != nil + + // If the deployment nodeSelector has been set, then it's been updated + return volsyncDeployment.Spec.Template.Spec.Tolerations != nil }, timeout, interval).Should(BeTrue()) }) - It("Should create the sub in the manifestwork wiith the node selector", func() { - Expect(operatorSubscription.Spec.Config).ToNot(BeNil()) - Expect(operatorSubscription.Spec.Config.Tolerations).To(Equal(nodePlacement.Tolerations)) - Expect(operatorSubscription.Spec.Config.NodeSelector).To(BeNil()) // No selectors set + It("Should create the deployment in the manifestwork wiith the node selector", func() { + Expect(volsyncDeployment.Spec.Template.Spec.Tolerations).To(Equal(nodePlacement.Tolerations)) + Expect(volsyncDeployment.Spec.Template.Spec.NodeSelector).To(BeNil()) // No selectors set }) }) - Context("When the addonDeployment config has nodeSelector and tolerations and nodeSelector", func() { + Context("When the addonDeployment config has nodeSelector and tolerations", func() { var addonDeploymentConfig *addonv1alpha1.AddOnDeploymentConfig nodePlacement := &addonv1alpha1.NodePlacement{ NodeSelector: map[string]string{ @@ -833,23 +806,23 @@ var _ = Describe("Addoncontroller", func() { return false } - // get Subscription from the manifestwork - subMF := manifestWork.Spec.Workload.Manifests[0] - subObj, _, err := genericCodec.Decode(subMF.Raw, nil, nil) - Expect(err).NotTo(HaveOccurred()) - var ok bool - operatorSubscription, ok = subObj.(*operatorsv1alpha1.Subscription) - if !ok { + // Find the deployment in the manifestwork + var err error + volsyncDeployment, err = getVolSyncDeploymentFromManifestWork( + manifestWork, genericCodec) + if err != nil { return false } - return operatorSubscription.Spec.Config != nil + + // If the deployment nodeSelector has been set, then it's been updated + return volsyncDeployment.Spec.Template.Spec.Tolerations != nil && + volsyncDeployment.Spec.Template.Spec.NodeSelector != nil }, timeout, interval).Should(BeTrue()) }) - It("Should create the sub in the manifestwork wiith the node selector", func() { - Expect(operatorSubscription.Spec.Config).ToNot(BeNil()) - Expect(operatorSubscription.Spec.Config.NodeSelector).To(Equal(nodePlacement.NodeSelector)) - Expect(operatorSubscription.Spec.Config.Tolerations).To(Equal(nodePlacement.Tolerations)) + It("Should create the deployment in the manifestwork with the node selector", func() { + Expect(volsyncDeployment.Spec.Template.Spec.NodeSelector).To(Equal(nodePlacement.NodeSelector)) + Expect(volsyncDeployment.Spec.Template.Spec.Tolerations).To(Equal(nodePlacement.Tolerations)) }) }) }) @@ -858,10 +831,11 @@ var _ = Describe("Addoncontroller", func() { "selectors/tolerations", func() { var defaultAddonDeploymentConfig *addonv1alpha1.AddOnDeploymentConfig var mcAddon *addonv1alpha1.ManagedClusterAddOn - var operatorSubscription *operatorsv1alpha1.Subscription var defaultNodePlacement *addonv1alpha1.NodePlacement var manifestWork *workv1.ManifestWork + var volsyncDeployment *appsv1.Deployment + myTolerationSeconds := int64(25) BeforeEach(func() { @@ -899,9 +873,6 @@ var _ = Describe("Addoncontroller", func() { ObjectMeta: metav1.ObjectMeta{ Name: "volsync", Namespace: testManagedCluster.GetName(), - Annotations: map[string]string{ - "operator-subscription-channel": "stable", - }, }, Spec: addonv1alpha1.ManagedClusterAddOnSpec{}, // Setting spec to empty } @@ -1033,29 +1004,26 @@ var _ = Describe("Addoncontroller", func() { return false } - // Subscription - subMF := manifestWork.Spec.Workload.Manifests[0] - subObj, _, err := genericCodec.Decode(subMF.Raw, nil, nil) - Expect(err).NotTo(HaveOccurred()) - var ok bool - operatorSubscription, ok = subObj.(*operatorsv1alpha1.Subscription) - if !ok { + // Find the deployment in the manifestwork + var err error + volsyncDeployment, err = getVolSyncDeploymentFromManifestWork( + manifestWork, genericCodec) + if err != nil { return false } - return operatorSubscription.Spec.Config != nil + + // If the deployment nodeSelector has been set, then it's been updated + return volsyncDeployment.Spec.Template.Spec.Tolerations != nil && + volsyncDeployment.Spec.Template.Spec.NodeSelector != nil }, timeout, interval).Should(BeTrue()) Expect(manifestWork).ToNot(BeNil()) - Expect(operatorSubscription).NotTo(BeNil()) - Expect(operatorSubscription.GetNamespace()).To(Equal("openshift-operators")) - Expect(operatorSubscription.Spec.Package).To(Equal("volsync-product")) // This is the "name" in json - - // Check the annotation was still honoured - Expect(operatorSubscription.Spec.Channel).To(Equal("stable")) + Expect(volsyncDeployment).NotTo(BeNil()) + Expect(volsyncDeployment.GetNamespace()).To(Equal("volsync-system")) }) Context("When a ManagedClusterAddOn is created with no addonConfig specified (the default)", func() { - It("Should create the sub in the manifestwork with the default node selector and tolerations", func() { + It("Should create the deployment in the manifestwork with the default node selector and tolerations", func() { // re-load the addon - status should be updated with details of the default deploymentConfig Expect(testK8sClient.Get(testCtx, client.ObjectKeyFromObject(mcAddon), mcAddon)).To(Succeed()) // Should be 1 config ref (our default addondeploymentconfig) @@ -1066,9 +1034,8 @@ var _ = Describe("Addoncontroller", func() { Expect(defaultConfigRef.DesiredConfig.Namespace).To(Equal(defaultAddonDeploymentConfig.GetNamespace())) Expect(defaultConfigRef.DesiredConfig.SpecHash).NotTo(Equal("")) // SpecHash should be set by controller - Expect(operatorSubscription.Spec.Config).ToNot(BeNil()) - Expect(operatorSubscription.Spec.Config.NodeSelector).To(Equal(defaultNodePlacement.NodeSelector)) - Expect(operatorSubscription.Spec.Config.Tolerations).To(Equal(defaultNodePlacement.Tolerations)) + Expect(volsyncDeployment.Spec.Template.Spec.NodeSelector).To(Equal(defaultNodePlacement.NodeSelector)) + Expect(volsyncDeployment.Spec.Template.Spec.Tolerations).To(Equal(defaultNodePlacement.Tolerations)) }) }) @@ -1139,7 +1106,7 @@ var _ = Describe("Addoncontroller", func() { }) - It("Should create the sub in the manifestwork with the node selector and tolerations from "+ + It("Should create the deployment in the manifestwork with the node selector and tolerations from "+ " the managedclusteraddon, not the defaults", func() { // Now re-load the manifestwork, based on timing it could haver originally // been updated with the defaults from the CMA - eventually should get updated properly @@ -1149,23 +1116,18 @@ var _ = Describe("Addoncontroller", func() { return false } - // get Subscription from the manifestwork - subMF := manifestWork.Spec.Workload.Manifests[0] - subObj, _, err := genericCodec.Decode(subMF.Raw, nil, nil) - Expect(err).NotTo(HaveOccurred()) - var ok bool - operatorSubscription, ok = subObj.(*operatorsv1alpha1.Subscription) - if !ok { - return false - } - if operatorSubscription.Spec.Config == nil { + // Find the deployment in the manifestwork + var err error + volsyncDeployment, err = getVolSyncDeploymentFromManifestWork( + manifestWork, genericCodec) + if err != nil { return false } // Check that the node selector matches the # of keys from the addondeploymentconfig // It won't match if the subscription is still using the default addondeploymentconfig // as it has different nodeSelector - return len(operatorSubscription.Spec.Config.NodeSelector) == len(nodePlacement.NodeSelector) + return len(volsyncDeployment.Spec.Template.Spec.NodeSelector) == len(nodePlacement.NodeSelector) }, timeout, interval).Should(BeTrue()) // re-load the addon - status should be updated with details of the default deploymentConfig @@ -1178,9 +1140,8 @@ var _ = Describe("Addoncontroller", func() { Expect(defaultConfigRef.DesiredConfig.Namespace).To(Equal(addonDeploymentConfig.GetNamespace())) Expect(defaultConfigRef.DesiredConfig.SpecHash).NotTo(Equal("")) // SpecHash should be set by controller - Expect(operatorSubscription.Spec.Config).ToNot(BeNil()) - Expect(operatorSubscription.Spec.Config.NodeSelector).To(Equal(nodePlacement.NodeSelector)) - Expect(operatorSubscription.Spec.Config.Tolerations).To(Equal(nodePlacement.Tolerations)) + Expect(volsyncDeployment.Spec.Template.Spec.NodeSelector).To(Equal(nodePlacement.NodeSelector)) + Expect(volsyncDeployment.Spec.Template.Spec.Tolerations).To(Equal(nodePlacement.Tolerations)) }) }) }) @@ -1372,7 +1333,7 @@ var _ = Describe("Addon Status Update Tests", func() { }, timeout, interval).Should(Succeed()) }) - Context("When the managed cluster is an OpenShiftCluster and manifestwork is available", func() { + Context("When the manifestwork is available", func() { JustBeforeEach(func() { // The controller should create a ManifestWork for this ManagedClusterAddon // Fake out that the ManifestWork is applied and available @@ -1415,7 +1376,7 @@ var _ = Describe("Addon Status Update Tests", func() { }) Context("When the manifestwork statusFeedback is not available", func() { - It("Should set the ManagedClusterAddon status to unknown", func() { + It("Should set the ManagedClusterAddon status to unavailable", func() { var statusCondition *metav1.Condition Eventually(func() bool { err := testK8sClient.Get(testCtx, types.NamespacedName{ @@ -1431,12 +1392,12 @@ var _ = Describe("Addon Status Update Tests", func() { return statusCondition != nil }, timeout, interval).Should(BeTrue()) - Expect(statusCondition.Reason).To(Equal("NoProbeResult")) - Expect(statusCondition.Status).To(Equal(metav1.ConditionUnknown)) + Expect(statusCondition.Reason).To(Equal("ProbeUnavailable")) + Expect(statusCondition.Status).To(Equal(metav1.ConditionFalse)) }) }) - Context("When the manifestwork statusFeedback is returned with a bad value", func() { + Context("When the manifestwork statusFeedback for the deployment does not have ready replicas", func() { JustBeforeEach(func() { Eventually(func() error { // Update the manifestwork to set the statusfeedback to a bad value @@ -1457,14 +1418,16 @@ var _ = Describe("Addon Status Update Tests", func() { return fmt.Errorf("Did not find the manifestwork with prefix addon-volsync-deploy") } - manifestWork.Status.ResourceStatus = manifestWorkResourceStatusWithSubscriptionInstalledCSVFeedBack( - "notinstalled") + // Set status feedback to indicate desired replicas = 1 but no ready replicas + replicas := int64(1) + manifestWork.Status.ResourceStatus = + manifestWorkResourceStatusWithVolSyncDeploymentFeedBack(&replicas, nil) return testK8sClient.Status().Update(testCtx, manifestWork) }, timeout, interval).Should(Succeed()) }) - It("Should set the ManagedClusterAddon status to unknown", func() { + It("Should set the ManagedClusterAddon status to unavailable", func() { var statusCondition *metav1.Condition Eventually(func() bool { err := testK8sClient.Get(testCtx, types.NamespacedName{ @@ -1477,17 +1440,20 @@ var _ = Describe("Addon Status Update Tests", func() { statusCondition = meta.FindStatusCondition(mcAddon.Status.Conditions, addonv1alpha1.ManagedClusterAddOnConditionAvailable) + if statusCondition == nil { + return false + } return statusCondition.Reason == "ProbeUnavailable" }, timeout, interval).Should(BeTrue()) Expect(statusCondition.Reason).To(Equal("ProbeUnavailable")) Expect(statusCondition.Status).To(Equal(metav1.ConditionFalse)) Expect(statusCondition.Message).To(ContainSubstring("Probe addon unavailable with err")) - Expect(statusCondition.Message).To(ContainSubstring("unexpected installedCSV value")) + Expect(statusCondition.Message).To(ContainSubstring("readyReplicas is not probed")) }) }) - Context("When the manifestwork statusFeedback is returned with a correct installed value", func() { + Context("When the manifestwork statusFeedback is returned with incorrect deployment ready replicas", func() { JustBeforeEach(func() { Eventually(func() error { // Update the manifestwork to set the statusfeedback to a bad value @@ -1508,14 +1474,17 @@ var _ = Describe("Addon Status Update Tests", func() { return fmt.Errorf("Did not find the manifestwork with prefix addon-volsync-deploy") } - manifestWork.Status.ResourceStatus = manifestWorkResourceStatusWithSubscriptionInstalledCSVFeedBack( - "volsync-product.v0.4.0") + // Set status feedback to indicate desired replicas = 1 and ready replicas = 0 + replicas := int64(1) + readyReplicas := int64(0) + manifestWork.Status.ResourceStatus = + manifestWorkResourceStatusWithVolSyncDeploymentFeedBack(&replicas, &readyReplicas) return testK8sClient.Status().Update(testCtx, manifestWork) }, timeout, interval).Should(Succeed()) }) - It("Should set the ManagedClusterAddon status to available", func() { + It("Should set the ManagedClusterAddon status to unavailable", func() { var statusCondition *metav1.Condition Eventually(func() bool { err := testK8sClient.Get(testCtx, types.NamespacedName{ @@ -1528,72 +1497,104 @@ var _ = Describe("Addon Status Update Tests", func() { statusCondition = meta.FindStatusCondition(mcAddon.Status.Conditions, addonv1alpha1.ManagedClusterAddOnConditionAvailable) - return statusCondition.Reason == "ProbeAvailable" + if statusCondition == nil { + return false + } + return statusCondition.Reason == "ProbeUnavailable" }, timeout, interval).Should(BeTrue()) logger.Info("#### status condition", "statusCondition", statusCondition) - Expect(statusCondition.Reason).To(Equal("ProbeAvailable")) - Expect(statusCondition.Status).To(Equal(metav1.ConditionTrue)) - Expect(statusCondition.Message).To(ContainSubstring("volsync add-on is available")) + Expect(statusCondition.Reason).To(Equal("ProbeUnavailable")) + Expect(statusCondition.Status).To(Equal(metav1.ConditionFalse)) + Expect(statusCondition.Message).To(ContainSubstring("Probe addon unavailable with err")) + Expect(statusCondition.Message).To(ContainSubstring("desiredNumberReplicas is 1 but readyReplica is 0")) }) }) - }) - Context("When the managed cluster is not an OpenShift cluster", func() { - BeforeEach(func() { - // remove labels from the managedcluster resource before it's created - // to simulate a "non-OpenShift" cluster - testManagedCluster.Labels = map[string]string{} - }) + Context("When the manifestwork statusFeedback is returned with correct deployment ready replicas", func() { + JustBeforeEach(func() { + Eventually(func() error { + // Update the manifestwork to set the statusfeedback to a bad value + var manifestWork *workv1.ManifestWork - It("ManagedClusterAddOn status should not be successful", func() { - var statusCondition *metav1.Condition - Eventually(func() *metav1.Condition { - err := testK8sClient.Get(testCtx, types.NamespacedName{ - Name: "volsync", - Namespace: testManagedClusterNamespace.GetName(), - }, mcAddon) - if err != nil { - return nil - } + allMwList := &workv1.ManifestWorkList{} + Expect(testK8sClient.List(testCtx, allMwList, + client.InNamespace(testManagedCluster.GetName()))).To(Succeed()) + + for _, mw := range allMwList.Items { + if strings.HasPrefix(mw.GetName(), "addon-volsync-deploy") == true { + manifestWork = &mw + break + } + } + + if manifestWork == nil { + return fmt.Errorf("Did not find the manifestwork with prefix addon-volsync-deploy") + } - logger.Info("### status should not be successful", "mcAddon.Status.Conditions", mcAddon.Status.Conditions) - statusCondition = meta.FindStatusCondition(mcAddon.Status.Conditions, - addonv1alpha1.ManagedClusterAddOnConditionAvailable) - return statusCondition - // addon-framework sets condition to Unknown - }, timeout, interval).Should(Not(BeNil())) + // Set status feedback to indicate desired replicas = 1 and ready replicas = 1 + replicas := int64(1) + readyReplicas := int64(1) + manifestWork.Status.ResourceStatus = + manifestWorkResourceStatusWithVolSyncDeploymentFeedBack(&replicas, &readyReplicas) - Expect(statusCondition.Reason).To(Equal("WorkNotFound")) // We didn't deploy any manifests - Expect(statusCondition.Status).To(Equal(metav1.ConditionUnknown)) + return testK8sClient.Status().Update(testCtx, manifestWork) + }, timeout, interval).Should(Succeed()) + }) + + It("Should set the ManagedClusterAddon status to available", func() { + var statusCondition *metav1.Condition + Eventually(func() bool { + err := testK8sClient.Get(testCtx, types.NamespacedName{ + Name: "volsync", + Namespace: testManagedClusterNamespace.GetName(), + }, mcAddon) + if err != nil { + return false + } + + statusCondition = meta.FindStatusCondition(mcAddon.Status.Conditions, + addonv1alpha1.ManagedClusterAddOnConditionAvailable) + if statusCondition == nil { + return false + } + return statusCondition.Reason == "ProbeAvailable" + }, timeout, interval).Should(BeTrue()) + + logger.Info("#### status condition", "statusCondition", statusCondition) + + Expect(statusCondition.Reason).To(Equal("ProbeAvailable")) + Expect(statusCondition.Status).To(Equal(metav1.ConditionTrue)) + Expect(statusCondition.Message).To(ContainSubstring("volsync add-on is available")) + }) }) }) }) }) }) -func manifestWorkResourceStatusWithSubscriptionInstalledCSVFeedBack( - installedCSVValue string, +func manifestWorkResourceStatusWithVolSyncDeploymentFeedBack( + replicas, readyReplicas *int64, ) workv1.ManifestResourceStatus { - return workv1.ManifestResourceStatus{ + mrStatus := workv1.ManifestResourceStatus{ Manifests: []workv1.ManifestCondition{ { ResourceMeta: workv1.ManifestResourceMeta{ - Group: "operators.coreos.com", - Kind: "Subscription", - Name: "volsync-product", - Namespace: "openshift-operators", - Resource: "subscriptions", - Version: "v1alpha1", + Group: "apps", + Kind: "Deployment", + Name: "volsync", + Namespace: "volsync-system", + Resource: "deployments", + Version: "v1", }, StatusFeedbacks: workv1.StatusFeedbackResult{ Values: []workv1.FeedbackValue{ { - Name: "installedCSV", + Name: "Replicas", Value: workv1.FieldValue{ - Type: "String", - String: &installedCSVValue, + Type: "Integer", + Integer: replicas, }, }, }, @@ -1602,6 +1603,20 @@ func manifestWorkResourceStatusWithSubscriptionInstalledCSVFeedBack( }, }, } + + if readyReplicas != nil { + mrStatus.Manifests[0].StatusFeedbacks.Values = append(mrStatus.Manifests[0].StatusFeedbacks.Values, + workv1.FeedbackValue{ + Name: "ReadyReplicas", + Value: workv1.FieldValue{ + Type: "Integer", + Integer: readyReplicas, + }, + }, + ) + } + + return mrStatus } func createAddonDeploymentConfig(nodePlacement *addonv1alpha1.NodePlacement) *addonv1alpha1.AddOnDeploymentConfig { @@ -1681,3 +1696,32 @@ func addDeploymentConfigStatusEntry(managedClusterAddOn *addonv1alpha1.ManagedCl return testK8sClient.Status().Update(testCtx, managedClusterAddOn) } + +func getVolSyncDeploymentFromManifestWork(manifestWork *workv1.ManifestWork, + decoder runtime.Decoder) (*appsv1.Deployment, error) { + var volsyncDeployment *appsv1.Deployment + + // Find the volsync deployment in the manifestwork + for _, workObj := range manifestWork.Spec.Workload.Manifests { + obj, _, err := decoder.Decode(workObj.Raw, nil, nil) + if err != nil { + return nil, err + } + + // This assumes there should be only 1 deployment in the manifestwork + if obj.GetObjectKind().GroupVersionKind().Kind == "Deployment" { + var ok bool + volsyncDeployment, ok = obj.(*appsv1.Deployment) + if !ok { + return nil, fmt.Errorf("Unable to decode Deployment from manifestwork") + } + break + } + } + + if volsyncDeployment == nil || volsyncDeployment.GetName() != "volsync" { + return nil, fmt.Errorf("Unable to find volsync deployment in manifestwork") + } + + return volsyncDeployment, nil +} diff --git a/controllers/controllers_suite_test.go b/controllers/controllers_suite_test.go index aef0561..0be6093 100644 --- a/controllers/controllers_suite_test.go +++ b/controllers/controllers_suite_test.go @@ -2,6 +2,7 @@ package controllers_test import ( "context" + "os" "path/filepath" "testing" @@ -20,8 +21,10 @@ import ( operatorsv1 "github.com/operator-framework/api/pkg/operators/v1" operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + policyv1beta1 "open-cluster-management.io/config-policy-controller/api/v1beta1" "github.com/stolostron/volsync-addon-controller/controllers" + "github.com/stolostron/volsync-addon-controller/controllers/helmutils" ) var testEnv *envtest.Environment @@ -46,6 +49,20 @@ var _ = BeforeSuite(func() { testCtx, cancel = context.WithCancel(context.TODO()) By("bootstrapping test environment") + + // Load embedded charts + // Find the location of where we have the test charts + wd, err := os.Getwd() // This should be our helmutils pkg dir + Expect(err).NotTo(HaveOccurred()) + // Charts located in /helmcharts + testChartsDir := filepath.Join(wd, "..", "helmcharts") + + klog.InfoS("Loading charts", "testChartsDir", testChartsDir) + // Load our test charts (these charts in testcharts are for test only and different from + // the charts that we'll bundle with the actual controller). + Expect(helmutils.InitEmbeddedCharts(testChartsDir)).To(Succeed()) + + // Startup testenv testEnv = &envtest.Environment{ CRDDirectoryPaths: []string{ // CRDs @@ -73,6 +90,8 @@ var _ = BeforeSuite(func() { Expect(err).ToNot(HaveOccurred()) err = operatorsv1alpha1.AddToScheme(scheme.Scheme) Expect(err).ToNot(HaveOccurred()) + err = policyv1beta1.AddToScheme(scheme.Scheme) + Expect(err).ToNot(HaveOccurred()) testK8sClient, err = client.New(cfg, client.Options{}) Expect(err).ToNot(HaveOccurred()) diff --git a/controllers/helmutils/helmutils.go b/controllers/helmutils/helmutils.go new file mode 100644 index 0000000..76f6768 --- /dev/null +++ b/controllers/helmutils/helmutils.go @@ -0,0 +1,188 @@ +package helmutils + +import ( + "fmt" + "os" + "path/filepath" + "slices" + "sort" + "sync" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/klog/v2" + + "helm.sh/helm/v3/pkg/chart" + "helm.sh/helm/v3/pkg/chart/loader" + "helm.sh/helm/v3/pkg/chartutil" + "helm.sh/helm/v3/pkg/engine" + + addonapiv1alpha1 "open-cluster-management.io/api/addon/v1alpha1" + clusterv1 "open-cluster-management.io/api/cluster/v1" +) + +const ( + defaultEmbeddedChartsDir = "/helmcharts" + crdKind = "CustomResourceDefinition" +) + +// List of kinds of objects in the manifestwork - anything in this list will not have +// the namespace updated before adding to the manifestwork +var globalKinds = []string{ + "CustomResourceDefinition", + "ClusterRole", + "ClusterRoleBinding", +} + +// key will be stable or dev +// value is the loaded *chart.Chart +var loadedChartsMap sync.Map + +// New - only load helm charts directly from embedded dirs +func InitEmbeddedCharts(embeddedChartsDir string) error { + if embeddedChartsDir == "" { + embeddedChartsDir = defaultEmbeddedChartsDir + } + + // Embedded Charts dir contains subdirectories - each subdir should contain 1 chart + subDirs, err := os.ReadDir(embeddedChartsDir) + if err != nil { + klog.ErrorS(err, "error loading embedded charts", "embeddedChartsDir", embeddedChartsDir) + return err + } + + for _, subDir := range subDirs { + if subDir.IsDir() { + chartsPath := filepath.Join(embeddedChartsDir, subDir.Name(), "volsync") + klog.InfoS("Loading charts", "chartsPath", chartsPath) + + chart, err := loader.Load(chartsPath) + if err != nil { + klog.ErrorS(err, "Error loading chart", "chartsPath", chartsPath) + return err + } + chartKey := subDir.Name() + klog.InfoS("Successfully loaded chart", "chartKey", chartKey, "Name", chart.Name(), "AppVersion", chart.AppVersion()) + + // Save chart into memory + loadedChartsMap.Store(chartKey, chart) + } + } + + return nil +} + +func GetEmbeddedChart(chartKey string) (*chart.Chart, error) { + loadedChart, ok := loadedChartsMap.Load(chartKey) + if !ok { + return nil, fmt.Errorf("Unable to find chart %s", chartKey) + } + return loadedChart.(*chart.Chart), nil +} + +//nolint:funlen +func RenderManifestsFromChart( + chart *chart.Chart, + namespace string, + cluster *clusterv1.ManagedCluster, + clusterIsOpenShift bool, + chartValues map[string]interface{}, + runtimeDecoder runtime.Decoder, +) ([]runtime.Object, error) { + helmObjs := []runtime.Object{} + + /* + // This only loads crds from the crds/ dir - consider putting them in that format upstream? + // OTherwise, maybe we don't need this section getting CRDs, just process them with the rest + crds := chart.CRDObjects() + for _, crd := range crds { + crdObj, _, err := runtimeDecoder.Decode(crd.File.Data, nil, nil) + if err != nil { + klog.Error(err, "Unable to decode CRD", "crd.Name", crd.Name) + return nil, err + } + helmObjs = append(helmObjs, crdObj) + } + */ + + helmEngine := engine.Engine{ + Strict: true, + LintMode: false, + } + + releaseOptions := chartutil.ReleaseOptions{ + Name: chart.Name(), + Namespace: namespace, + } + + capabilities := &chartutil.Capabilities{ + KubeVersion: chartutil.KubeVersion{Version: cluster.Status.Version.Kubernetes}, + APIVersions: chartutil.DefaultVersionSet, + } + + if clusterIsOpenShift { + // Add openshift scc to apiversions so capabilities in our helm charts that check this will work + capabilities.APIVersions = append(capabilities.APIVersions, "security.openshift.io/v1/SecurityContextConstraints") + } + + renderedChartValues, err := chartutil.ToRenderValues(chart, chartValues, releaseOptions, capabilities) + if err != nil { + klog.Error(err, "Unable to render values for chart", "chart.Name()", chart.Name()) + return nil, err + } + + templates, err := helmEngine.Render(chart, renderedChartValues) + if err != nil { + klog.Error(err, "Unable to render chart", "chart.Name()", chart.Name()) + return nil, err + } + + // sort the filenames of the templates so the manifests are ordered consistently + keys := make([]string, len(templates)) + i := 0 + for k := range templates { + keys[i] = k + i++ + } + sort.Strings(keys) + + // VolSync CRDs are going to be last (start with volsync.backube_), so go through our sorted keys in reverse order + for j := len(keys) - 1; j >= 0; j-- { + fileName := keys[j] + // skip files that are not .yaml or empty + fileExt := filepath.Ext(fileName) + + templateData := templates[fileName] + if (fileExt != ".yaml" && fileExt != ".yml") || len(templateData) == 0 || templateData == "\n" { + klog.V(4).InfoS("Skipping template", "fileName", fileName) + continue + } + + templateObj, gvk, err := runtimeDecoder.Decode([]byte(templateData), nil, nil) + if err != nil { + klog.Error(err, "Error decoding rendered template", "fileName", fileName) + return nil, err + } + + if gvk != nil { + if !slices.Contains(globalKinds, gvk.Kind) { + // Helm rendering does not set namespace on the templates, it will rely on the kubectl install/apply + // to do it (which does not happen since these objects end up directly in our manifestwork). + // So set the namespace ourselves for any object with kind not in our globalKinds list + templateObj.(metav1.Object).SetNamespace(releaseOptions.Namespace) + } + + if gvk.Kind == crdKind { + // Add annotation to indicate we do not want the CRD deleted when the manifestwork is deleted + // (i.e. when the managedclusteraddon is deleted) + crdAnnotations := templateObj.(metav1.Object).GetAnnotations() + crdAnnotations[addonapiv1alpha1.DeletionOrphanAnnotationKey] = "" + templateObj.(metav1.Object).SetAnnotations(crdAnnotations) + } + } + + helmObjs = append(helmObjs, templateObj) + } + + return helmObjs, nil +} diff --git a/controllers/helmutils/helmutils_suite_test.go b/controllers/helmutils/helmutils_suite_test.go new file mode 100644 index 0000000..da2304a --- /dev/null +++ b/controllers/helmutils/helmutils_suite_test.go @@ -0,0 +1,55 @@ +package helmutils_test + +import ( + "os" + "path/filepath" + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + operatorsv1 "github.com/operator-framework/api/pkg/operators/v1" + operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/klog/v2" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + + "github.com/stolostron/volsync-addon-controller/controllers/helmutils" +) + +var ( + genericScheme = runtime.NewScheme() + genericCodecs = serializer.NewCodecFactory(genericScheme) + genericCodec = genericCodecs.UniversalDeserializer() +) + +func init() { + utilruntime.Must(scheme.AddToScheme(genericScheme)) + utilruntime.Must(operatorsv1.AddToScheme(genericScheme)) + utilruntime.Must(operatorsv1alpha1.AddToScheme(genericScheme)) + utilruntime.Must(apiextensionsv1.AddToScheme(genericScheme)) +} + +func TestUtils(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "HelmUtils Suite") +} + +var _ = BeforeSuite(func() { + klog.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) + + // Find the location of where we have the test charts + wd, err := os.Getwd() // This should be our helmutils pkg dir + Expect(err).NotTo(HaveOccurred()) + // Charts located in /helmcharts + testChartsDir := filepath.Join(wd, "..", "..", "helmcharts") + + klog.InfoS("Loading charts", "testChartsDir", testChartsDir) + // Load our test charts (these charts in testcharts are for test only and different from + // the charts that we'll bundle with the actual controller). + Expect(helmutils.InitEmbeddedCharts(testChartsDir)).To(Succeed()) +}) diff --git a/controllers/helmutils/helmutils_test.go b/controllers/helmutils/helmutils_test.go new file mode 100644 index 0000000..a85da9e --- /dev/null +++ b/controllers/helmutils/helmutils_test.go @@ -0,0 +1,121 @@ +package helmutils_test + +import ( + "strings" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + clusterv1 "open-cluster-management.io/api/cluster/v1" + + "github.com/stolostron/volsync-addon-controller/controllers" + "github.com/stolostron/volsync-addon-controller/controllers/helmutils" + "github.com/stolostron/volsync-addon-controller/controllers/helmutils/helmutilstest" +) + +var _ = Describe("Helmutils", func() { + logger := zap.New(zap.UseDevMode(true), zap.WriteTo(GinkgoWriter)) + + Context("Load embedded helm charts", func() { + // see the test suite BeforeSuite() for initing the charts with our test charts + It("Should have stable-X.Y chart loaded", func() { + // Stable chart should always exist + chart, err := helmutils.GetEmbeddedChart(controllers.DefaultHelmChartKey) + Expect(err).NotTo(HaveOccurred()) + Expect(chart).NotTo(BeNil()) + + // Charts for acm 2.13 should be volsync v0.12.z + Expect(strings.HasPrefix(chart.AppVersion(), "0.12.")).To(BeTrue()) + }) + + It("Should not have other charts loaded", func() { + _, err := helmutils.GetEmbeddedChart("nothere") + Expect(err).To(HaveOccurred()) + }) + }) + + Context("Rendering helm charts into objects", func() { + var testNamespace string + var clusterIsOpenShift bool + var renderedObjs []runtime.Object + //var chartKey string + + var chartValues map[string]interface{} + + BeforeEach(func() { + chartValues = map[string]interface{}{} + }) + + JustBeforeEach(func() { + chart, err := helmutils.GetEmbeddedChart(controllers.DefaultHelmChartKey) + Expect(err).NotTo(HaveOccurred()) + Expect(chart).NotTo(BeNil()) + + testCluster := &clusterv1.ManagedCluster{ + ObjectMeta: metav1.ObjectMeta{}, + } + + renderedObjs, err = helmutils.RenderManifestsFromChart(chart, testNamespace, testCluster, clusterIsOpenShift, + chartValues, genericCodec) + Expect(err).NotTo(HaveOccurred()) + Expect(renderedObjs).NotTo(BeNil()) + }) + + When("The cluster is OpenShift", func() { + BeforeEach(func() { + clusterIsOpenShift = true + testNamespace = "my-test-ns" + }) + + It("Should render the helm chart", func() { + helmutilstest.VerifyHelmRenderedVolSyncObjects(renderedObjs, testNamespace, clusterIsOpenShift) + }) + }) + + When("The cluster is Not OpenShift", func() { + BeforeEach(func() { + clusterIsOpenShift = false + testNamespace = "my-test-ns-2" + }) + + It("Should render the helm chart", func() { + helmutilstest.VerifyHelmRenderedVolSyncObjects(renderedObjs, testNamespace, clusterIsOpenShift) + }) + + When("custom chart values are provided", func() { + myNodeSelector := map[string]string{ + "selecta": "selectorvaluea", + "selectb": "selectorvalueb", + } + + myTolerations := []corev1.Toleration{ + { + Key: "node.kubernetes.io/unreachable", + Operator: corev1.TolerationOpExists, + Effect: corev1.TaintEffectNoSchedule, + }, + } + + BeforeEach(func() { + // Set some chart values + chartValues["nodeSelector"] = myNodeSelector + chartValues["tolerations"] = myTolerations + }) + + It("Should render the helm chart using the values", func() { + volsyncDeploy := helmutilstest.VerifyHelmRenderedVolSyncObjects(renderedObjs, testNamespace, clusterIsOpenShift) + logger.Info("deployment", "volsyncDeploy", &volsyncDeploy) + Expect(volsyncDeploy.Spec.Template.Spec.NodeSelector).NotTo(BeNil()) + Expect(volsyncDeploy.Spec.Template.Spec.NodeSelector).To(Equal(myNodeSelector)) + + Expect(volsyncDeploy.Spec.Template.Spec.Tolerations).NotTo(BeNil()) + Expect(volsyncDeploy.Spec.Template.Spec.Tolerations).To(Equal(myTolerations)) + }) + }) + }) + }) +}) diff --git a/controllers/helmutils/helmutilstest/testhelper.go b/controllers/helmutils/helmutilstest/testhelper.go new file mode 100644 index 0000000..08f3823 --- /dev/null +++ b/controllers/helmutils/helmutilstest/testhelper.go @@ -0,0 +1,136 @@ +package helmutilstest + +import ( + . "github.com/onsi/gomega" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/klog/v2" +) + +//nolint:funlen +func VerifyHelmRenderedVolSyncObjects(objs []runtime.Object, + testNamespace string, clusterIsOpenShift bool) *appsv1.Deployment { + // Check objects + // There should be: + // - 2 CRDs (replicationsource, replicationdestination) + // - 3 clusterroles + // - 1 for the manager controller + // - 1 for metrics reader + // - 1 for proxy + // - 2 clusterrolebindings + // - 1 for the manager controller + // - 1 for proxy + // - 1 role (leader election) + // - 1 rolebinding (leader election) + // - 1 deployment (volsync) + // - 1 service (metrics) + // - 1 serviceaccount (volsync) + Expect(len(objs)).To(Equal(12)) + + crds := []*apiextensionsv1.CustomResourceDefinition{} + clusterRoles := []*rbacv1.ClusterRole{} + clusterRoleBindings := []*rbacv1.ClusterRoleBinding{} + var role *rbacv1.Role + var roleBinding *rbacv1.RoleBinding + var deployment *appsv1.Deployment + var service *corev1.Service + var serviceAccount *corev1.ServiceAccount + + for _, obj := range objs { + objKind := obj.GetObjectKind().GroupVersionKind().Kind + + klog.InfoS("Object kind", "objKind", objKind) + + switch objKind { + case "CustomResourceDefinition": + crd, ok := obj.(*apiextensionsv1.CustomResourceDefinition) + Expect(ok).To(BeTrue()) + crds = append(crds, crd) + case "ClusterRole": + clusterRole, ok := obj.(*rbacv1.ClusterRole) + Expect(ok).To(BeTrue()) + clusterRoles = append(clusterRoles, clusterRole) + case "ClusterRoleBinding": + clusterRoleBinding, ok := obj.(*rbacv1.ClusterRoleBinding) + Expect(ok).To(BeTrue()) + clusterRoleBindings = append(clusterRoleBindings, clusterRoleBinding) + case "Role": + r, ok := obj.(*rbacv1.Role) + Expect(ok).To(BeTrue()) + role = r + case "RoleBinding": + rb, ok := obj.(*rbacv1.RoleBinding) + Expect(ok).To(BeTrue()) + roleBinding = rb + case "Deployment": + d, ok := obj.(*appsv1.Deployment) + Expect(ok).To(BeTrue()) + deployment = d + case "Service": + s, ok := obj.(*corev1.Service) + Expect(ok).To(BeTrue()) + service = s + case "ServiceAccount": + sa, ok := obj.(*corev1.ServiceAccount) + Expect(ok).To(BeTrue()) + serviceAccount = sa + } + } + + Expect(len(crds)).To(Equal(2)) + Expect(len(clusterRoles)).To(Equal(3)) + Expect(len(clusterRoleBindings)).To(Equal(2)) + Expect(role).NotTo(BeNil()) + Expect(roleBinding).NotTo(BeNil()) + Expect(deployment).NotTo(BeNil()) + Expect(service).NotTo(BeNil()) + Expect(serviceAccount).NotTo(BeNil()) + + // Check CRDs + foundReplicationSourceCRD := false + foundReplicationDestinationCRD := false + for _, crd := range crds { + if crd.GetName() == "replicationsources.volsync.backube" { + foundReplicationSourceCRD = true + } else if crd.GetName() == "replicationdestinations.volsync.backube" { + foundReplicationDestinationCRD = true + } + } + Expect(foundReplicationSourceCRD).To(BeTrue()) + Expect(foundReplicationDestinationCRD).To(BeTrue()) + + // Check namespace on namespaced resources is set correctly + namespacedObjs := []metav1.Object{ + role, + roleBinding, + deployment, + service, + serviceAccount, + } + for _, nsObj := range namespacedObjs { + Expect(nsObj.GetNamespace()).To(Equal(testNamespace)) + } + + // Check deployment + Expect(deployment.GetName()).To(Equal("volsync")) + Expect(len(deployment.Spec.Template.Spec.Containers)).To(Equal(2)) + Expect(deployment.Spec.Template.Spec.Containers[0].Name).To(Equal("kube-rbac-proxy")) + Expect(deployment.Spec.Template.Spec.Containers[1].Name).To(Equal("manager")) + + Expect(deployment.Spec.Template.Spec.ServiceAccountName).To(Equal(serviceAccount.GetName())) + if clusterIsOpenShift { + // RunAsUser should not be set for OpenShift, openshift will set this + Expect(deployment.Spec.Template.Spec.SecurityContext.RunAsUser).To(BeNil()) + } else { + Expect(deployment.Spec.Template.Spec.SecurityContext.RunAsUser).NotTo(BeNil()) + Expect(*deployment.Spec.Template.Spec.SecurityContext.RunAsUser).To(Equal(int64(65534))) + } + + // Return the deployment (can be checked further by tests) + return deployment +} diff --git a/controllers/manifesthelper.go b/controllers/manifesthelper.go new file mode 100644 index 0000000..fc06c20 --- /dev/null +++ b/controllers/manifesthelper.go @@ -0,0 +1,86 @@ +package controllers + +// Helper to get the objects that need to be inserted into the manifestwork +// and render them + +import ( + "embed" + + "github.com/openshift/library-go/pkg/assets" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/klog/v2" + + "open-cluster-management.io/addon-framework/pkg/addonfactory" + "open-cluster-management.io/addon-framework/pkg/agent" + addonapiv1alpha1 "open-cluster-management.io/api/addon/v1alpha1" + addonv1alpha1client "open-cluster-management.io/api/client/addon/clientset/versioned" + clusterv1 "open-cluster-management.io/api/cluster/v1" +) + +type manifestHelper interface { + loadManifests() ([]runtime.Object, error) + subHealthCheck(fieldResults []agent.FieldResult) error +} + +func getManifestHelper(embedFS embed.FS, addonClient addonv1alpha1client.Interface, + cluster *clusterv1.ManagedCluster, addon *addonapiv1alpha1.ManagedClusterAddOn, +) manifestHelper { + clusterIsOpenShift := isOpenShift(cluster) + + mhc := manifestHelperCommon{ + embedFS: embedFS, + addonClient: addonClient, + cluster: cluster, + clusterIsOpenShift: clusterIsOpenShift, + addon: addon, + } + + if shouldDeployVolSyncAsOperator(clusterIsOpenShift, addon) { + return &manifestHelperOperatorDeploy{mhc} + } + + // Default is now to deploy as a helm operator + return &manifestHelperHelmDeploy{mhc} +} + +type manifestHelperCommon struct { + embedFS embed.FS + addonClient addonv1alpha1client.Interface + cluster *clusterv1.ManagedCluster + clusterIsOpenShift bool + addon *addonapiv1alpha1.ManagedClusterAddOn +} + +func (mhc manifestHelperCommon) loadManifestsFromFiles(fileList []string, values addonfactory.Values, +) ([]runtime.Object, error) { + objects := make([]runtime.Object, len(fileList)) + + for i, file := range fileList { + template, err := mhc.embedFS.ReadFile(file) + if err != nil { + return nil, err + } + + raw := assets.MustCreateAssetFromTemplate(file, template, &values).Data + object, _, err := genericCodec.Decode(raw, nil, nil) + if err != nil { + klog.ErrorS(err, "Error decoding manifest file", "filename", file) + return nil, err + } + + objects[i] = object + } + + return objects, nil +} + +func shouldDeployVolSyncAsOperator(clusterIsOpenShift bool, addon *addonapiv1alpha1.ManagedClusterAddOn) bool { + if clusterIsOpenShift && addon.GetAnnotations()[AnnotationVolSyncAddonDeployTypeOverride] == + AnnotationVolSyncAddonDeployTypeOverrideOLMValue { + klog.InfoS("Override - deploying VolSync as OLM operator for cluster", + "clusterName", addon.GetNamespace()) + return true + } + + return false // Default, should deploy VolSync via helm charts +} diff --git a/controllers/manifesthelper_helmdeploy.go b/controllers/manifesthelper_helmdeploy.go new file mode 100644 index 0000000..1d7ff47 --- /dev/null +++ b/controllers/manifesthelper_helmdeploy.go @@ -0,0 +1,181 @@ +package controllers + +import ( + "fmt" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/klog/v2" + + "open-cluster-management.io/addon-framework/pkg/addonfactory" + "open-cluster-management.io/addon-framework/pkg/agent" + addonframeworkutils "open-cluster-management.io/addon-framework/pkg/utils" + + "github.com/stolostron/volsync-addon-controller/controllers/helmutils" +) + +type manifestHelperHelmDeploy struct { + manifestHelperCommon +} + +var _ manifestHelper = &manifestHelperHelmDeploy{} + +func (mh *manifestHelperHelmDeploy) loadManifests() ([]runtime.Object, error) { + values, err := mh.getValuesForManifest() + if err != nil { + return nil, err + } + + // Raw yaml files to be included in our manifestwork (these will be rendered into objects) + // These include any objects we need on the mgd cluster that are not in the helm charts themselves + fileList := manifestFilesHelmDeploy + if mh.clusterIsOpenShift { + fileList = manifestFilesHelmDeployOpenShift + } + objects, err := mh.loadManifestsFromFiles(fileList, values) + if err != nil { + return nil, err + } + + // Now load manifest objects rendered from our volsync helm chart + helmObjects, err := mh.loadManifestsFromHelmRepo(values) + if err != nil { + return nil, err + } + + objects = append(objects, helmObjects...) + return objects, nil +} + +func (mh *manifestHelperHelmDeploy) subHealthCheck(fieldResults []agent.FieldResult) error { + if len(fieldResults) == 0 { + return fmt.Errorf("no fieldResults found in health checker") + } + for _, fieldResult := range fieldResults { + if len(fieldResult.FeedbackResult.Values) == 0 { + continue + } + switch fieldResult.ResourceIdentifier.Resource { + case "deployments": + readyReplicas := -1 + desiredNumberReplicas := -1 + for _, value := range fieldResult.FeedbackResult.Values { + if value.Name == "ReadyReplicas" { + readyReplicas = int(*value.Value.Integer) + } + if value.Name == "Replicas" { + desiredNumberReplicas = int(*value.Value.Integer) + } + } + + if readyReplicas == -1 { + return fmt.Errorf("readyReplicas is not probed") + } + if desiredNumberReplicas == -1 { + return fmt.Errorf("desiredNumberReplicas is not probed") + } + + if desiredNumberReplicas == 0 { + return nil + } + + if desiredNumberReplicas == readyReplicas { + return nil + } + + return fmt.Errorf("desiredNumberReplicas is %d but readyReplica is %d for %s %s/%s", + desiredNumberReplicas, readyReplicas, + fieldResult.ResourceIdentifier.Resource, + fieldResult.ResourceIdentifier.Namespace, + fieldResult.ResourceIdentifier.Name) + } + } + return fmt.Errorf("volsync addon is not ready") +} + +// Now need to load and render the helm charts into objects +func (mh *manifestHelperHelmDeploy) loadManifestsFromHelmRepo(values addonfactory.Values) ([]runtime.Object, error) { + installNamespace := mh.getInstallNamespace() + + chart, err := helmutils.GetEmbeddedChart(mh.getChartKey()) + if err != nil { + klog.ErrorS(err, "unable to load chart") + return nil, err + } + + return helmutils.RenderManifestsFromChart(chart, installNamespace, + mh.cluster, mh.clusterIsOpenShift, values, genericCodec) +} + +func (mh *manifestHelperHelmDeploy) getValuesForManifest() (addonfactory.Values, error) { + manifestConfig := struct { + // OpenShift target cluster parameters - this is the same as the subscription name + // only used for cleaning up old OLM based install of VolSync (olm sub/csv will be removed + // and we will then deploy the helm chart instead on OpenShift mgd clusters) + OperatorName string + ManagedClusterName string + + // + // Helm based install parameters here + // + InstallNamespace string + }{ + OperatorName: operatorName, + ManagedClusterName: mh.cluster.GetName(), + InstallNamespace: mh.getInstallNamespace(), + } + + manifestConfigValues := addonfactory.StructToValues(manifestConfig) + + // Get values from addonDeploymentConfig + deploymentConfigValues, err := addonfactory.GetAddOnDeploymentConfigValues( + addonframeworkutils.NewAddOnDeploymentConfigGetter(mh.addonClient), + addonfactory.ToAddOnDeploymentConfigValues, + )(mh.cluster, mh.addon) + if err != nil { + return nil, err + } + + // Merge manifestConfig and deploymentConfigValues + mergedValues := addonfactory.MergeValues(manifestConfigValues, deploymentConfigValues) + + // Convert any values into the value format that VolSync expects in its charts + mh.updateChartValuesForVolSync(mergedValues) + + return mergedValues, nil +} + +func (mh *manifestHelperHelmDeploy) getInstallNamespace() string { + return DefaultHelmInstallNamespace +} + +func (mh *manifestHelperHelmDeploy) getChartKey() string { + // Which chart to deploy - will default to "stable" + // but can override with annotation to pick from a different dir + // (that dir will need to be bundled in /helmcharts/ however) + chartKey := DefaultHelmChartKey + + customChartKey := mh.addon.GetAnnotations()[AnnotationHelmChartKey] + if customChartKey != "" { + chartKey = customChartKey + } + + return chartKey +} + +// Updates values to make sure they match the correct names volsync expects in values.yaml +// (for example addon-framework uses "Tolerations" and "NodeSelectors" where Volsync values.yaml +// +// expects "tolerations" and "nodeSelectors") +func (mh *manifestHelperHelmDeploy) updateChartValuesForVolSync(values addonfactory.Values) { + convertValuesMapKey(values, "Tolerations", "tolerations") + convertValuesMapKey(values, "NodeSelector", "nodeSelector") +} + +// If oldKey exists in map, copy the value to newKey and remove oldKey +func convertValuesMapKey(values addonfactory.Values, oldKey, newKey string) { + v, ok := values[oldKey] + if ok { + values[newKey] = v + delete(values, oldKey) + } +} diff --git a/controllers/manifesthelper_operatordeploy.go b/controllers/manifesthelper_operatordeploy.go new file mode 100644 index 0000000..8983fcb --- /dev/null +++ b/controllers/manifesthelper_operatordeploy.go @@ -0,0 +1,124 @@ +package controllers + +import ( + "fmt" + "strings" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/klog/v2" + + "open-cluster-management.io/addon-framework/pkg/addonfactory" + "open-cluster-management.io/addon-framework/pkg/agent" + addonframeworkutils "open-cluster-management.io/addon-framework/pkg/utils" + workapiv1 "open-cluster-management.io/api/work/v1" +) + +type manifestHelperOperatorDeploy struct { + manifestHelperCommon +} + +var _ manifestHelper = &manifestHelperOperatorDeploy{} + +func (mh *manifestHelperOperatorDeploy) loadManifests() ([]runtime.Object, error) { + values, err := mh.getValuesForManifest() + if err != nil { + return nil, err + } + + return mh.loadManifestsFromFiles(manifestFilesOperatorDeploy, values) +} + +func (mh *manifestHelperOperatorDeploy) subHealthCheck(fieldResults []agent.FieldResult) error { + foundOLMSubscription := false + for _, fieldResult := range fieldResults { + if fieldResult.ResourceIdentifier.Resource != "subscriptions" { + continue + } + + foundOLMSubscription = true + for _, feedbackValue := range fieldResult.FeedbackResult.Values { + if feedbackValue.Name == "installedCSV" { + klog.V(4).InfoS("Addon subscription", "installedCSV", feedbackValue.Value) + if feedbackValue.Value.Type != workapiv1.String || feedbackValue.Value.String == nil || + !strings.HasPrefix(*feedbackValue.Value.String, operatorName) { + + installedCSVErr := fmt.Errorf("addon subscription has unexpected installedCSV value") + klog.ErrorS(installedCSVErr, "Sub may not have installed CSV") + return installedCSVErr + } + } + } + } + if !foundOLMSubscription { + noSubErr := fmt.Errorf("addon subscription not found in feedback results") + klog.ErrorS(noSubErr, "Sub may not have been deployed") + return noSubErr + } + return nil +} + +func (mh *manifestHelperOperatorDeploy) getValuesForManifest() (addonfactory.Values, error) { + manifestConfig := struct { + OperatorInstallNamespace string + + // OpenShift target cluster parameters - for OLM operator install of VolSync + OperatorName string + OperatorGroupSpec string + CatalogSource string + CatalogSourceNamespace string + InstallPlanApproval string + Channel string + StartingCSV string + }{ + OperatorInstallNamespace: mh.getOperatorInstallNamespace(), + + OperatorName: operatorName, + CatalogSource: mh.getCatalogSource(), + CatalogSourceNamespace: mh.getCatalogSourceNamespace(), + InstallPlanApproval: mh.getInstallPlanApproval(), + Channel: mh.getChannel(), + StartingCSV: mh.getStartingCSV(), + } + + manifestConfigValues := addonfactory.StructToValues(manifestConfig) + + // Get values from addonDeploymentConfig + deploymentConfigValues, err := addonfactory.GetAddOnDeploymentConfigValues( + addonframeworkutils.NewAddOnDeploymentConfigGetter(mh.addonClient), + addonfactory.ToAddOnDeploymentConfigValues, + )(mh.cluster, mh.addon) + if err != nil { + return nil, err + } + + // Merge manifestConfig and deploymentConfigValues + mergedValues := addonfactory.MergeValues(manifestConfigValues, deploymentConfigValues) + + return mergedValues, nil +} + +func (mh *manifestHelperOperatorDeploy) getOperatorInstallNamespace() string { + // The only namespace supported is openshift-operators, so ignore whatever is in the spec + return globalOperatorInstallNamespace +} + +func (mh *manifestHelperOperatorDeploy) getCatalogSource() string { + return getAnnotationOverrideOrDefault(mh.addon, AnnotationCatalogSourceOverride, DefaultCatalogSource) +} + +func (mh *manifestHelperOperatorDeploy) getCatalogSourceNamespace() string { + return getAnnotationOverrideOrDefault(mh.addon, AnnotationCatalogSourceNamespaceOverride, + DefaultCatalogSourceNamespace) +} + +func (mh *manifestHelperOperatorDeploy) getInstallPlanApproval() string { + return getAnnotationOverrideOrDefault(mh.addon, AnnotationInstallPlanApprovalOverride, DefaultInstallPlanApproval) +} + +func (mh *manifestHelperOperatorDeploy) getChannel() string { + return getAnnotationOverrideOrDefault(mh.addon, AnnotationChannelOverride, DefaultChannel) +} + +func (mh *manifestHelperOperatorDeploy) getStartingCSV() string { + return getAnnotationOverrideOrDefault(mh.addon, AnnotationStartingCSVOverride, DefaultStartingCSV) +} diff --git a/controllers/manifests/operator-namespace.yaml b/controllers/manifests/helm-chart/namespace.yaml similarity index 56% rename from controllers/manifests/operator-namespace.yaml rename to controllers/manifests/helm-chart/namespace.yaml index 3b074dd..88156e6 100644 --- a/controllers/manifests/operator-namespace.yaml +++ b/controllers/manifests/helm-chart/namespace.yaml @@ -1,4 +1,4 @@ apiVersion: v1 kind: Namespace metadata: - name: {{ .InstallNamespace }} \ No newline at end of file + name: {{ .InstallNamespace }} diff --git a/controllers/manifests/operatorgroup-aggregate-clusterrole.yaml b/controllers/manifests/helm-chart/volsync-operatorpolicy-aggregate-clusterrole.yaml similarity index 53% rename from controllers/manifests/operatorgroup-aggregate-clusterrole.yaml rename to controllers/manifests/helm-chart/volsync-operatorpolicy-aggregate-clusterrole.yaml index 52a5add..347b8f9 100644 --- a/controllers/manifests/operatorgroup-aggregate-clusterrole.yaml +++ b/controllers/manifests/helm-chart/volsync-operatorpolicy-aggregate-clusterrole.yaml @@ -1,10 +1,10 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - name: open-cluster-management:{{ .OperatorName }}-addon-operatorgroups-aggregate-clusterrole + name: open-cluster-management:volsync-operatorpolicy-aggregate-clusterrole labels: rbac.authorization.k8s.io/aggregate-to-admin: "true" rules: - - apiGroups: ["operators.coreos.com"] - resources: ["operatorgroups"] + - apiGroups: ["policy.open-cluster-management.io"] + resources: ["operatorpolicies"] verbs: ["get", "create", "delete", "update"] diff --git a/controllers/manifests/helm-chart/volsync-operatorpolicy-remove-operator.yaml b/controllers/manifests/helm-chart/volsync-operatorpolicy-remove-operator.yaml new file mode 100644 index 0000000..7ca7cc0 --- /dev/null +++ b/controllers/manifests/helm-chart/volsync-operatorpolicy-remove-operator.yaml @@ -0,0 +1,23 @@ +apiVersion: policy.open-cluster-management.io/v1beta1 +kind: OperatorPolicy +metadata: + name: migrate-volsync-from-operatordeploy + # OperatorPolicy needs to be in namespace named after mgd cluster (on the mgd cluster itself) + namespace: {{ .ManagedClusterName }} +spec: + #complianceConfig: + # catalogSourceUnhealthy: Compliant + # deploymentsUnavailable: NonCompliant + # upgradesAvailable: Compliant + complianceType: mustnothave + remediationAction: enforce + removalBehavior: + clusterServiceVersions: Delete + customResourceDefinitions: Keep + operatorGroups: Keep + subscriptions: Delete + severity: medium + subscription: + name: {{ .OperatorName }} + namespace: openshift-operators + upgradeApproval: Automatic diff --git a/controllers/manifests/operator-group-allnamespaces.yaml b/controllers/manifests/operator-group-allnamespaces.yaml deleted file mode 100644 index 741cd09..0000000 --- a/controllers/manifests/operator-group-allnamespaces.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: operators.coreos.com/v1 -kind: OperatorGroup -metadata: - name: {{ .OperatorName }}-operatorgroup - namespace: {{ .InstallNamespace }} -spec: {} \ No newline at end of file diff --git a/controllers/manifests/operator-group-ownnamespace.yaml b/controllers/manifests/operator-group-ownnamespace.yaml deleted file mode 100644 index 1600c37..0000000 --- a/controllers/manifests/operator-group-ownnamespace.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: operators.coreos.com/v1 -kind: OperatorGroup -metadata: - name: {{ .OperatorName }}-operatorgroup - namespace: {{ .InstallNamespace }} -spec: - targetNamespaces: - - {{ .InstallNamespace }} diff --git a/controllers/manifests/operator-subscription.yaml b/controllers/manifests/operator/operator-subscription.yaml similarity index 95% rename from controllers/manifests/operator-subscription.yaml rename to controllers/manifests/operator/operator-subscription.yaml index 77a9d52..78629ee 100644 --- a/controllers/manifests/operator-subscription.yaml +++ b/controllers/manifests/operator/operator-subscription.yaml @@ -2,7 +2,7 @@ apiVersion: operators.coreos.com/v1alpha1 kind: Subscription metadata: name: {{ .OperatorName }} - namespace: {{ .InstallNamespace }} + namespace: {{ .OperatorInstallNamespace }} spec: {{- if .Channel }} channel: {{ .Channel }} diff --git a/go.mod b/go.mod index 4a1f24f..614e7e0 100644 --- a/go.mod +++ b/go.mod @@ -5,19 +5,22 @@ go 1.22.0 require ( github.com/onsi/ginkgo/v2 v2.20.0 github.com/onsi/gomega v1.34.1 - github.com/openshift/library-go v0.0.0-20240621150525-4bb4238aef81 + github.com/openshift/library-go v0.0.0-20241021151851-4c5ecb35c294 // release-4.19 github.com/operator-framework/api v0.26.0 github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 - k8s.io/api v0.30.4 - k8s.io/apimachinery v0.30.4 - k8s.io/client-go v0.30.4 - k8s.io/component-base v0.30.4 + helm.sh/helm/v3 v3.14.4 + k8s.io/api v0.31.1 + k8s.io/apiextensions-apiserver v0.31.1 + k8s.io/apimachinery v0.31.1 + k8s.io/client-go v0.31.1 + k8s.io/component-base v0.31.1 k8s.io/klog/v2 v2.130.1 - open-cluster-management.io/addon-framework v0.11.0 - open-cluster-management.io/api v0.15.0 + open-cluster-management.io/addon-framework v0.11.1-0.20241217015347-99a171302bb4 + open-cluster-management.io/api v0.15.1-0.20241120090202-cb7ce98ab874 + open-cluster-management.io/config-policy-controller v0.15.0 open-cluster-management.io/sdk-go v0.15.0 - sigs.k8s.io/controller-runtime v0.18.5 + sigs.k8s.io/controller-runtime v0.19.0 ) require ( @@ -26,41 +29,44 @@ require ( github.com/Masterminds/semver/v3 v3.2.1 // indirect github.com/Masterminds/sprig/v3 v3.2.3 // indirect github.com/NYTimes/gziphandler v1.1.1 // indirect - github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect + github.com/antlr4-go/antlr/v4 v4.13.0 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect - github.com/cenkalti/backoff/v4 v4.2.1 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/emicklei/go-restful/v3 v3.11.2 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/emicklei/go-restful/v3 v3.12.0 // indirect github.com/evanphx/json-patch v5.7.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.9.0 // indirect github.com/fatih/structs v1.1.0 // indirect + github.com/felixge/fgprof v0.9.4 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/zapr v1.3.0 // indirect - github.com/go-openapi/jsonpointer v0.20.2 // indirect - github.com/go-openapi/jsonreference v0.20.4 // indirect - github.com/go-openapi/swag v0.22.9 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.21.0 // indirect + github.com/go-openapi/swag v0.23.0 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/google/cel-go v0.17.8 // indirect - github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/btree v1.1.2 // indirect + github.com/google/cel-go v0.20.1 // indirect + github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect github.com/google/uuid v1.6.0 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect github.com/huandu/xstrings v1.4.0 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect @@ -72,61 +78,61 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/openshift/api v0.0.0-20240527133614-ba11c1587003 // indirect - github.com/openshift/client-go v0.0.0-20240528061634-b054aa794d87 // indirect + github.com/openshift/api v0.0.0-20241001152557-e415140e5d5f // indirect + github.com/openshift/client-go v0.0.0-20241001162912-da6d55e4611f // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/pkg/profile v1.3.0 // indirect - github.com/prometheus/client_golang v1.18.0 // indirect - github.com/prometheus/client_model v0.6.0 // indirect - github.com/prometheus/common v0.47.0 // indirect - github.com/prometheus/procfs v0.12.0 // indirect - github.com/shopspring/decimal v1.3.1 // indirect + github.com/pkg/profile v1.7.0 // indirect + github.com/prometheus/client_golang v1.19.1 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect + github.com/shopspring/decimal v1.4.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/spf13/cast v1.5.0 // indirect + github.com/spf13/cast v1.6.0 // indirect github.com/stoewer/go-strcase v1.3.0 // indirect + github.com/stolostron/kubernetes-dependency-watches v0.10.0 // indirect + github.com/x448/float16 v0.8.4 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect - go.etcd.io/etcd/api/v3 v3.5.12 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.5.12 // indirect - go.etcd.io/etcd/client/v3 v3.5.12 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.48.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.23.1 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.23.1 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/sdk v1.23.1 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect - go.opentelemetry.io/proto/otlp v1.1.0 // indirect + go.etcd.io/etcd/api/v3 v3.5.14 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.5.14 // indirect + go.etcd.io/etcd/client/v3 v3.5.14 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect + go.opentelemetry.io/otel v1.28.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 // indirect + go.opentelemetry.io/otel/metric v1.28.0 // indirect + go.opentelemetry.io/otel/sdk v1.28.0 // indirect + go.opentelemetry.io/otel/trace v1.28.0 // indirect + go.opentelemetry.io/proto/otlp v1.3.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/crypto v0.31.0 // indirect golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/oauth2 v0.17.0 // indirect + golang.org/x/net v0.29.0 // indirect + golang.org/x/oauth2 v0.21.0 // indirect golang.org/x/sync v0.10.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/term v0.27.0 // indirect golang.org/x/text v0.21.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.24.0 // indirect - google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect - google.golang.org/grpc v1.62.1 // indirect - google.golang.org/protobuf v1.34.1 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect + google.golang.org/grpc v1.65.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect + gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - helm.sh/helm/v3 v3.14.3 // indirect - k8s.io/apiextensions-apiserver v0.30.4 // indirect - k8s.io/apiserver v0.30.4 // indirect - k8s.io/kms v0.30.4 // indirect - k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect - k8s.io/utils v0.0.0-20240310230437-4693a0247e57 // indirect - sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0 // indirect + k8s.io/apiserver v0.31.1 // indirect + k8s.io/kms v0.31.1 // indirect + k8s.io/kube-openapi v0.0.0-20240521193020-835d969ad83a // indirect + k8s.io/utils v0.0.0-20240921022957-49e7df575cb6 // indirect + sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/kube-storage-version-migrator v0.0.6-0.20230721195810-5c8923c5ff96 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect diff --git a/go.sum b/go.sum index cac3b73..eb1698e 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,3 @@ -cloud.google.com/go/compute v1.25.1 h1:ZRpHJedLtTpKgr3RV1Fx23NuaAEN1Zfx9hw1u4aJdjU= -cloud.google.com/go/compute v1.25.1/go.mod h1:oopOIR53ly6viBYxaDhBfJwzUAxf1zE//uf3IB011ls= -cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= -cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= @@ -13,20 +9,27 @@ github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= -github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df h1:7RFfzj4SSt6nnvCPbCqijJi1nWCd+TqAT3bYCStRC18= -github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= +github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= +github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= -github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= -github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ= -github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs= +github.com/chromedp/chromedp v0.9.2/go.mod h1:LkSXJKONWTCHAfQasKFUZI+mxqS4tZqhmtGzzhLsnLs= +github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= @@ -35,26 +38,30 @@ github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/emicklei/go-restful/v3 v3.11.2 h1:1onLa9DcsMYO9P+CXaL0dStDqQ2EHHXLiz+BtnqkLAU= -github.com/emicklei/go-restful/v3 v3.11.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= -github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= +github.com/emicklei/go-restful/v3 v3.12.0 h1:y2DdzBAURM29NFF94q6RaY4vjIH1rtwDapwQtU84iWk= +github.com/emicklei/go-restful/v3 v3.12.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ2tG6yudJd8LBksgI= github.com/evanphx/json-patch v5.7.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw= +github.com/felixge/fgprof v0.9.4 h1:ocDNwMFlnA0NU0zSB3I52xkO4sFXk80VK9lXjLClu88= +github.com/felixge/fgprof v0.9.4/go.mod h1:yKl+ERSa++RYOs32d8K6WEXCB4uXdLls4ZaZPpayhMM= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= -github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -62,16 +69,19 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= -github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q= -github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs= -github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU= -github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4= -github.com/go-openapi/swag v0.22.9 h1:XX2DssF+mQKM2DHsbgZK74y/zj4mo9I99+89xUmuZCE= -github.com/go-openapi/swag v0.22.9/go.mod h1:3/OXnFfnMAwBD099SwYRk7GD3xOrr1iL7d/XNLXVVwE= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= +github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= +github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= @@ -79,23 +89,22 @@ github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOW github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= -github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -github.com/google/cel-go v0.17.8 h1:j9m730pMZt1Fc4oKhCLUHfjj6527LuhYcYw0Rl8gqto= -github.com/google/cel-go v0.17.8/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY= -github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= -github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= +github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/cel-go v0.20.1 h1:nDx9r8S3L4pE61eDdt8igGj8rf5kjYR3ILxWIpWNi84= +github.com/google/cel-go v0.20.1/go.mod h1:kWcIzTsPX0zmQ+H3TirHstLLf9ep5QTsZBN9u4dOYLg= +github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 h1:0VpGH+cDhbDtdcweoyCVsF3fhN8kejK6rFe/2FFX2nU= +github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49/go.mod h1:BkkQ4L1KS1xMt2aWSPStnn55ChGC0DPOn2FQYj+f25M= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= +github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k= github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -109,11 +118,13 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92Bcuy github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 h1:/c3QmbOGMGTOumP2iT/rCwB7b0QDGLKzqOmktBjT+Is= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1/go.mod h1:5SN9VR2LTsRFsrEC6FHgRbTWrTHu6tqPeKxEQv15giM= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= +github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= @@ -131,6 +142,7 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= @@ -154,47 +166,51 @@ github.com/onsi/ginkgo/v2 v2.20.0 h1:PE84V2mHqoT1sglvHc8ZdQtPcwmvvt29WLEEO3xmdZw github.com/onsi/ginkgo/v2 v2.20.0/go.mod h1:lG9ey2Z29hR41WMVthyJBGUBcBhGOtoPF2VFMvBXFCI= github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= -github.com/openshift/api v0.0.0-20240527133614-ba11c1587003 h1:ewhIvyXCcvH6m3U02bMFtd/DfsmOSbOCuVzon+zGu7g= -github.com/openshift/api v0.0.0-20240527133614-ba11c1587003/go.mod h1:OOh6Qopf21pSzqNVCB5gomomBXb8o5sGKZxG2KNpaXM= -github.com/openshift/client-go v0.0.0-20240528061634-b054aa794d87 h1:JtLhaGpSEconE+1IKmIgCOof/Len5ceG6H1pk43yv5U= -github.com/openshift/client-go v0.0.0-20240528061634-b054aa794d87/go.mod h1:3IPD4U0qyovZS4EFady2kqY32m8lGcbs/Wx+yprg9z8= -github.com/openshift/library-go v0.0.0-20240621150525-4bb4238aef81 h1:cAo++YCkjrClksMEAPqK9SLMCroqlbGxNTluxeKGIGc= -github.com/openshift/library-go v0.0.0-20240621150525-4bb4238aef81/go.mod h1:PdASVamWinll2BPxiUpXajTwZxV8A1pQbWEsCN1od7I= +github.com/openshift/api v0.0.0-20241001152557-e415140e5d5f h1:ya1OmyZm3LIIxI3U9VE9Nyx3ehCHgBwxyFUPflYPWls= +github.com/openshift/api v0.0.0-20241001152557-e415140e5d5f/go.mod h1:Shkl4HanLwDiiBzakv+con/aMGnVE2MAGvoKp5oyYUo= +github.com/openshift/client-go v0.0.0-20241001162912-da6d55e4611f h1:FRc0bVNWprihWS0GqQWzb3dY4dkCwpOP3mDw5NwSoR4= +github.com/openshift/client-go v0.0.0-20241001162912-da6d55e4611f/go.mod h1:KiZi2mJRH1TOJ3FtBDYS6YvUL30s/iIXaGSUrSa36mo= +github.com/openshift/library-go v0.0.0-20241021151851-4c5ecb35c294 h1:wz02/A1CsKVqNJD+Yg4NLw9SnNpGX9JK5lEb4qxM81k= +github.com/openshift/library-go v0.0.0-20241021151851-4c5ecb35c294/go.mod h1:9B1MYPoLtP9tqjWxcbUNVpwxy68zOH/3EIP6c31dAM0= github.com/operator-framework/api v0.26.0 h1:YVntU2NkVl5zSLLwK5kFcH6P3oSvN9QDgTsY9mb4yUM= github.com/operator-framework/api v0.26.0/go.mod h1:3IxOwzVUeGxYlzfwKCcfCyS+q3EEhWA/4kv7UehbeyM= +github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/profile v1.3.0 h1:OQIvuDgm00gWVWGTf4m4mCt6W1/0YqU7Ntg0mySWgaI= -github.com/pkg/profile v1.3.0/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA= +github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= -github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= -github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos= -github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= -github.com/prometheus/common v0.47.0 h1:p5Cz0FNHo7SnWOmWmoRozVcjEp0bIVU8cV7OShpjL1k= -github.com/prometheus/common v0.47.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= -github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= -github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= +github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= +github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= -github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= -github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= +github.com/stolostron/kubernetes-dependency-watches v0.10.0 h1:brg9FCZUvd1gnm5wmsv/InfErcPUvYcZsK/LWNRr+wg= +github.com/stolostron/kubernetes-dependency-watches v0.10.0/go.mod h1:j1DBv/3JjwDX3bT/oKB4YvSwJ6DEVcrUpEzKbFLM0QM= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -209,6 +225,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE= github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -221,40 +239,40 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA= -go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= -go.etcd.io/etcd/api/v3 v3.5.12 h1:W4sw5ZoU2Juc9gBWuLk5U6fHfNVyY1WC5g9uiXZio/c= -go.etcd.io/etcd/api/v3 v3.5.12/go.mod h1:Ot+o0SWSyT6uHhA56al1oCED0JImsRiU9Dc26+C2a+4= -go.etcd.io/etcd/client/pkg/v3 v3.5.12 h1:EYDL6pWwyOsylrQyLp2w+HkQ46ATiOvoEdMarindU2A= -go.etcd.io/etcd/client/pkg/v3 v3.5.12/go.mod h1:seTzl2d9APP8R5Y2hFL3NVlD6qC/dOT+3kvrqPyTas4= -go.etcd.io/etcd/client/v2 v2.305.10 h1:MrmRktzv/XF8CvtQt+P6wLUlURaNpSDJHFZhe//2QE4= -go.etcd.io/etcd/client/v2 v2.305.10/go.mod h1:m3CKZi69HzilhVqtPDcjhSGp+kA1OmbNn0qamH80xjA= -go.etcd.io/etcd/client/v3 v3.5.12 h1:v5lCPXn1pf1Uu3M4laUE2hp/geOTc5uPcYYsNe1lDxg= -go.etcd.io/etcd/client/v3 v3.5.12/go.mod h1:tSbBCakoWmmddL+BKVAJHa9km+O/E+bumDe9mSbPiqw= -go.etcd.io/etcd/pkg/v3 v3.5.10 h1:WPR8K0e9kWl1gAhB5A7gEa5ZBTNkT9NdNWrR8Qpo1CM= -go.etcd.io/etcd/pkg/v3 v3.5.10/go.mod h1:TKTuCKKcF1zxmfKWDkfz5qqYaE3JncKKZPFf8c1nFUs= -go.etcd.io/etcd/raft/v3 v3.5.10 h1:cgNAYe7xrsrn/5kXMSaH8kM/Ky8mAdMqGOxyYwpP0LA= -go.etcd.io/etcd/raft/v3 v3.5.10/go.mod h1:odD6kr8XQXTy9oQnyMPBOr0TVe+gT0neQhElQ6jbGRc= -go.etcd.io/etcd/server/v3 v3.5.10 h1:4NOGyOwD5sUZ22PiWYKmfxqoeh72z6EhYjNosKGLmZg= -go.etcd.io/etcd/server/v3 v3.5.10/go.mod h1:gBplPHfs6YI0L+RpGkTQO7buDbHv5HJGG/Bst0/zIPo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.48.0 h1:P+/g8GpuJGYbOp2tAdKrIPUX9JO02q8Q0YNlHolpibA= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.48.0/go.mod h1:tIKj3DbO8N9Y2xo52og3irLsPI4GW02DSMtrVgNMgxg= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.23.1 h1:o8iWeVFa1BcLtVEV0LzrCxV2/55tB3xLxADr6Kyoey4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.23.1/go.mod h1:SEVfdK4IoBnbT2FXNM/k8yC08MrfbhWk3U4ljM8B3HE= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.23.1 h1:p3A5+f5l9e/kuEBwLOrnpkIDHQFlHmbiVxMURWRK6gQ= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.23.1/go.mod h1:OClrnXUjBqQbInvjJFjYSnMxBSCXBF8r3b34WqjiIrQ= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.23.1 h1:O7JmZw0h76if63LQdsBMKQDWNb5oEcOThG9IrxscV+E= -go.opentelemetry.io/otel/sdk v1.23.1/go.mod h1:LzdEVR5am1uKOOwfBWFef2DCi1nu3SA8XQxx2IerWFk= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= -go.opentelemetry.io/proto/otlp v1.1.0 h1:2Di21piLrCqJ3U3eXGCTPHE9R8Nh+0uglSnOyxikMeI= -go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY= +go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI= +go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE= +go.etcd.io/etcd/api/v3 v3.5.14 h1:vHObSCxyB9zlF60w7qzAdTcGaglbJOpSj1Xj9+WGxq0= +go.etcd.io/etcd/api/v3 v3.5.14/go.mod h1:BmtWcRlQvwa1h3G2jvKYwIQy4PkHlDej5t7uLMUdJUU= +go.etcd.io/etcd/client/pkg/v3 v3.5.14 h1:SaNH6Y+rVEdxfpA2Jr5wkEvN6Zykme5+YnbCkxvuWxQ= +go.etcd.io/etcd/client/pkg/v3 v3.5.14/go.mod h1:8uMgAokyG1czCtIdsq+AGyYQMvpIKnSvPjFMunkgeZI= +go.etcd.io/etcd/client/v2 v2.305.13 h1:RWfV1SX5jTU0lbCvpVQe3iPQeAHETWdOTb6pxhd77C8= +go.etcd.io/etcd/client/v2 v2.305.13/go.mod h1:iQnL7fepbiomdXMb3om1rHq96htNNGv2sJkEcZGDRRg= +go.etcd.io/etcd/client/v3 v3.5.14 h1:CWfRs4FDaDoSz81giL7zPpZH2Z35tbOrAJkkjMqOupg= +go.etcd.io/etcd/client/v3 v3.5.14/go.mod h1:k3XfdV/VIHy/97rqWjoUzrj9tk7GgJGH9J8L4dNXmAk= +go.etcd.io/etcd/pkg/v3 v3.5.13 h1:st9bDWNsKkBNpP4PR1MvM/9NqUPfvYZx/YXegsYEH8M= +go.etcd.io/etcd/pkg/v3 v3.5.13/go.mod h1:N+4PLrp7agI/Viy+dUYpX7iRtSPvKq+w8Y14d1vX+m0= +go.etcd.io/etcd/raft/v3 v3.5.13 h1:7r/NKAOups1YnKcfro2RvGGo2PTuizF/xh26Z2CTAzA= +go.etcd.io/etcd/raft/v3 v3.5.13/go.mod h1:uUFibGLn2Ksm2URMxN1fICGhk8Wu96EfDQyuLhAcAmw= +go.etcd.io/etcd/server/v3 v3.5.13 h1:V6KG+yMfMSqWt+lGnhFpP5z5dRUj1BDRJ5k1fQ9DFok= +go.etcd.io/etcd/server/v3 v3.5.13/go.mod h1:K/8nbsGupHqmr5MkgaZpLlH1QdX1pcNQLAkODy44XcQ= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= +go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= +go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 h1:qFffATk0X+HD+f1Z8lswGiOQYKHRlzfmdJm0wEaVrFA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0/go.mod h1:MOiCmryaYtc+V0Ei+Tx9o5S1ZjA7kzLucuVuyzBZloQ= +go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= +go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= +go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= +go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= +go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= +go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= +go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= +go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -268,6 +286,7 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -280,25 +299,31 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= -golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= -golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= +golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -309,7 +334,6 @@ golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= @@ -328,23 +352,21 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= -google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20240221002015-b0ce06bbee7c h1:Zmyn5CV/jxzKnF+3d+xzbomACPwLQqVpLTpyXN5uTaQ= google.golang.org/genproto v0.0.0-20240221002015-b0ce06bbee7c/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= -google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 h1:rIo7ocm2roD9DcFIX67Ym8icoGCKSARAiPljFhh5suQ= -google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= -google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= -google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= -google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 h1:7whR9kGa5LUwFtpLm2ArCEejtnxlGeLbAyjFY8sGNFw= +google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= +google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= +google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= +gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= @@ -359,38 +381,40 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -helm.sh/helm/v3 v3.14.3 h1:HmvRJlwyyt9HjgmAuxHbHv3PhMz9ir/XNWHyXfmnOP4= -helm.sh/helm/v3 v3.14.3/go.mod h1:v6myVbyseSBJTzhmeE39UcPLNv6cQK6qss3dvgAySaE= -k8s.io/api v0.30.4 h1:XASIELmW8w8q0i1Y4124LqPoWMycLjyQti/fdYHYjCs= -k8s.io/api v0.30.4/go.mod h1:ZqniWRKu7WIeLijbbzetF4U9qZ03cg5IRwl8YVs8mX0= -k8s.io/apiextensions-apiserver v0.30.4 h1:FwOMIk/rzZvM/Gx0IOz0+biZ+dlnlCeyfXW17uzV1qE= -k8s.io/apiextensions-apiserver v0.30.4/go.mod h1:m8cAkJ9PVU8Olb4cPW4hrUDBZGvoSJ0kY0G0CfdGQac= -k8s.io/apimachinery v0.30.4 h1:5QHQI2tInzr8LsT4kU/2+fSeibH1eIHswNx480cqIoY= -k8s.io/apimachinery v0.30.4/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= -k8s.io/apiserver v0.30.4 h1:rHkGJhxd+m4jILrgkenwSmG4X0QXk6ecGuybzS/PQak= -k8s.io/apiserver v0.30.4/go.mod h1:oyGAj9B9/0+I9huJyf4/8SMBF2mNh2bTMlu7703dkH8= -k8s.io/client-go v0.30.4 h1:eculUe+HPQoPbixfwmaSZGsKcOf7D288tH6hDAdd+wY= -k8s.io/client-go v0.30.4/go.mod h1:IBS0R/Mt0LHkNHF4E6n+SUDPG7+m2po6RZU7YHeOpzc= -k8s.io/component-base v0.30.4 h1:FlgKqazIkIIxpLA4wFXsiPiDllJn9fhsN3G4TeX7T7U= -k8s.io/component-base v0.30.4/go.mod h1:Qd3h+OJxV/LrnriXG/E15ZK83dzd306qJHW9+87S5ls= +helm.sh/helm/v3 v3.14.4 h1:6FSpEfqyDalHq3kUr4gOMThhgY55kXUEjdQoyODYnrM= +helm.sh/helm/v3 v3.14.4/go.mod h1:Tje7LL4gprZpuBNTbG34d1Xn5NmRT3OWfBRwpOSer9I= +k8s.io/api v0.31.1 h1:Xe1hX/fPW3PXYYv8BlozYqw63ytA92snr96zMW9gWTU= +k8s.io/api v0.31.1/go.mod h1:sbN1g6eY6XVLeqNsZGLnI5FwVseTrZX7Fv3O26rhAaI= +k8s.io/apiextensions-apiserver v0.31.1 h1:L+hwULvXx+nvTYX/MKM3kKMZyei+UiSXQWciX/N6E40= +k8s.io/apiextensions-apiserver v0.31.1/go.mod h1:tWMPR3sgW+jsl2xm9v7lAyRF1rYEK71i9G5dRtkknoQ= +k8s.io/apimachinery v0.31.1 h1:mhcUBbj7KUjaVhyXILglcVjuS4nYXiwC+KKFBgIVy7U= +k8s.io/apimachinery v0.31.1/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= +k8s.io/apiserver v0.31.1 h1:Sars5ejQDCRBY5f7R3QFHdqN3s61nhkpaX8/k1iEw1c= +k8s.io/apiserver v0.31.1/go.mod h1:lzDhpeToamVZJmmFlaLwdYZwd7zB+WYRYIboqA1kGxM= +k8s.io/client-go v0.31.1 h1:f0ugtWSbWpxHR7sjVpQwuvw9a3ZKLXX0u0itkFXufb0= +k8s.io/client-go v0.31.1/go.mod h1:sKI8871MJN2OyeqRlmA4W4KM9KBdBUpDLu/43eGemCg= +k8s.io/component-base v0.31.1 h1:UpOepcrX3rQ3ab5NB6g5iP0tvsgJWzxTyAo20sgYSy8= +k8s.io/component-base v0.31.1/go.mod h1:WGeaw7t/kTsqpVTaCoVEtillbqAhF2/JgvO0LDOMa0w= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kms v0.30.4 h1:Je7wR5/m+w/E7Ef9R9RY1yeMU/C2GXIvhzRFfg8H5kQ= -k8s.io/kms v0.30.4/go.mod h1:GrMurD0qk3G4yNgGcsCEmepqf9KyyIrTXYR2lyUOJC4= -k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= -k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= -k8s.io/utils v0.0.0-20240310230437-4693a0247e57 h1:gbqbevonBh57eILzModw6mrkbwM0gQBEuevE/AaBsHY= -k8s.io/utils v0.0.0-20240310230437-4693a0247e57/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -open-cluster-management.io/addon-framework v0.11.0 h1:ZJxphgHQ36VUJF0RIag+nzcEn5PNyep2rsEPdz6wT7o= -open-cluster-management.io/addon-framework v0.11.0/go.mod h1:ruMU8i/dciz3qCv2CQ46Cu1b7rkK7TpvB+W4bRwHf+I= -open-cluster-management.io/api v0.15.0 h1:lRee1KOlGHZb2scTA7ff9E9Fxt2hJc7jpkHnaCbvkOU= -open-cluster-management.io/api v0.15.0/go.mod h1:9erZEWEn4bEqh0nIX2wA7f/s3KCuFycQdBrPrRzi0QM= +k8s.io/kms v0.31.1 h1:cGLyV3cIwb0ovpP/jtyIe2mEuQ/MkbhmeBF2IYCA9Io= +k8s.io/kms v0.31.1/go.mod h1:OZKwl1fan3n3N5FFxnW5C4V3ygrah/3YXeJWS3O6+94= +k8s.io/kube-openapi v0.0.0-20240521193020-835d969ad83a h1:zD1uj3Jf+mD4zmA7W+goE5TxDkI7OGJjBNBzq5fJtLA= +k8s.io/kube-openapi v0.0.0-20240521193020-835d969ad83a/go.mod h1:UxDHUPsUwTOOxSU+oXURfFBcAS6JwiRXTYqYwfuGowc= +k8s.io/utils v0.0.0-20240921022957-49e7df575cb6 h1:MDF6h2H/h4tbzmtIKTuctcwZmY0tY9mD9fNT47QO6HI= +k8s.io/utils v0.0.0-20240921022957-49e7df575cb6/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +open-cluster-management.io/addon-framework v0.11.1-0.20241217015347-99a171302bb4 h1:U7uOHdrXlEvcszpr6MVouRy7xJLiVZirOTSBEfMWW2c= +open-cluster-management.io/addon-framework v0.11.1-0.20241217015347-99a171302bb4/go.mod h1:tsBSNs9mGfVQQjXBnjgpiX6r0UM+G3iNfmzQgKhEfw4= +open-cluster-management.io/api v0.15.1-0.20241120090202-cb7ce98ab874 h1:WgkuYXTbJV7EK+qtiMq3soa21faGUKeTG5w0C8Mn1Ok= +open-cluster-management.io/api v0.15.1-0.20241120090202-cb7ce98ab874/go.mod h1:9erZEWEn4bEqh0nIX2wA7f/s3KCuFycQdBrPrRzi0QM= +open-cluster-management.io/config-policy-controller v0.15.0 h1:tDuIVT2L/luKLvLIz7/wkbskTZqWypLkwjyVMxPqhsI= +open-cluster-management.io/config-policy-controller v0.15.0/go.mod h1:IFGPJBb+zKC7V1lavwMUApxLnbfrANpidBTohsu4z6Q= open-cluster-management.io/sdk-go v0.15.0 h1:2IAJnPfUoY6rPC5w7LhqAnvIlgekPoVW03LdZO1unIM= open-cluster-management.io/sdk-go v0.15.0/go.mod h1:fi5WBsbC5K3txKb8eRLuP0Sim/Oqz/PHX18skAEyjiA= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0 h1:/U5vjBbQn3RChhv7P11uhYvCSm5G2GaIi5AIGBS6r4c= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0/go.mod h1:z7+wmGM2dfIiLRfrC6jb5kV2Mq/sK1ZP303cxzkV5Y4= -sigs.k8s.io/controller-runtime v0.18.5 h1:nTHio/W+Q4aBlQMgbnC5hZb4IjIidyrizMai9P6n4Rk= -sigs.k8s.io/controller-runtime v0.18.5/go.mod h1:TVoGrfdpbA9VRFaRnKgk9P5/atA0pMwq+f+msb9M8Sg= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 h1:2770sDpzrjjsAtVhSeUFseziht227YAWYHLGNM8QPwY= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= +sigs.k8s.io/controller-runtime v0.19.0 h1:nWVM7aq+Il2ABxwiCizrVDSlmDcshi9llbaFbC0ji/Q= +sigs.k8s.io/controller-runtime v0.19.0/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/kube-storage-version-migrator v0.0.6-0.20230721195810-5c8923c5ff96 h1:PFWFSkpArPNJxFX4ZKWAk9NSeRoZaXschn+ULa4xVek= diff --git a/helmcharts/stable-0.12/volsync/.helmignore b/helmcharts/stable-0.12/volsync/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/helmcharts/stable-0.12/volsync/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/helmcharts/stable-0.12/volsync/Chart.yaml b/helmcharts/stable-0.12/volsync/Chart.yaml new file mode 100644 index 0000000..14fddf6 --- /dev/null +++ b/helmcharts/stable-0.12/volsync/Chart.yaml @@ -0,0 +1,71 @@ +apiVersion: v2 +name: volsync +type: application +description: Asynchronous data replication for Kubernetes +home: https://volsync.readthedocs.io/ +icon: https://raw.githubusercontent.com/backube/volsync/main/docs/media/volsync.svg?sanitize=true +sources: + - https://github.com/backube/volsync +maintainers: + - name: John Strunk + email: jstrunk@redhat.com + url: https://github.com/JohnStrunk + - name: Tesshu Flower + email: tflower@redhat.com + url: https://github.com/tesshuflower +keywords: + - backup + - csi + - data + - disaster recovery + - replication + - storage +annotations: # https://artifacthub.io/docs/topics/annotations/helm/ + # Changelog for current chart & app version + # Kinds: added, changed, deprecated, removed, fixed, and security + artifacthub.io/changes: | + - kind: changed + description: Restic updated to v0.17.0 + - kind: changed + description: Syncthing updated to v1.27.12 + - kind: added + description: moverAffinity added to spec to allow for specifying the podAffinity assigned to a VolSync mover pod + - kind: added + description: cleanupTempPVC option added for direct users to allow for deleting the dynamically provisioned destination PVC after a completed replication. + - kind: added + description: cleanupCachePVC option for restic to allow for deleting the cache PVC after a completed replication. + - kind: added + description: enableFileDeletion restic option to allow for restoring to an existing PVC (for example running multiple restores) and delete files that do not exist in the backup being restored. + artifacthub.io/crds: | + - kind: ReplicationDestination + version: v1alpha1 + name: replicationdestination.volsync.backube + displayName: Replication destination + description: Defines the destination of a replicated volume + - kind: ReplicationSource + version: v1alpha1 + name: replicationsource.volsync.backube + displayName: Replication source + description: Defines the source of a replicated volume + artifacthub.io/license: AGPL-3.0-or-later + artifacthub.io/operator: "true" + artifacthub.io/operatorCapabilities: Basic Install + artifacthub.io/signKey: | + fingerprint: 2C937ADACD4BEF921197F66EDC7556B1903A252B + url: https://keys.openpgp.org/vks/v1/by-fingerprint/2C937ADACD4BEF921197F66EDC7556B1903A252B + +# We require v1 CSI snapshots (1.20+) +# Adding "-0" at the end of the version string permits pre-release kube versions +# to match. See https://github.com/helm/helm/issues/6190 +kubeVersion: "^1.20.0-0" + +# This is the chart version. This version number should be incremented each time +# you make changes to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: "0.12.0" + +# This is the version number of the application being deployed. This version +# number should be incremented each time you make changes to the application. +# Versions are not expected to follow Semantic Versioning. They should reflect +# the version the application is using. It is recommended to use it with quotes. +appVersion: "0.12.0" diff --git a/helmcharts/stable-0.12/volsync/README.md b/helmcharts/stable-0.12/volsync/README.md new file mode 100644 index 0000000..8c50987 --- /dev/null +++ b/helmcharts/stable-0.12/volsync/README.md @@ -0,0 +1,157 @@ +# VolSync + +Asynchronous volume replication for Kubernetes CSI storage + +## About this operator + +![maturity](https://img.shields.io/static/v1?label=maturity&message=alpha&color=red) + +VolSync is a Kubernetes operator that performs asynchronous replication of +persistent volumes within, or across, clusters. VolSync supports replication +independent of the storage system. This means that replication can be used +with storage systems that do not natively support replication. Data can also be +replicated across different types (and vendors) of storage. + +VolSync supports both 1:1 replication relationships as well as 1:many +relationships. This provides the flexibility to support use cases such as: + +- Disaster recovery +- Mirroring data to a test environment +- Data distribution to a set of remote clusters from a central site +- Migrating between storage vendors (changing the StorageClass of a + persistent volume claim). +- Creating periodic data backups + +### How it works + +You specify the details of how, when, and where to replicate the data +in a ReplicationSource object in the same namespace as the persistent +volume claim (PVC). + +You create a ReplicationDestination object at the destination, which +specifies the target for the replicated data. + +VolSync uses multiple replication methods to replicate data: + +- Rclone-based replication for 1:many data distribution: + Data is replicated from the source to an intermediate cloud storage + service, which is [supported by Rclone](https://rclone.org/#providers). + The destinations retrieve the data from the intermediate location. +- Restic-based backup of PVC contents: + Data in a PVC is backed up by using the [restic](https://restic.net/) + program. This method works well when the deployment configuration of + the application is already source-controlled, and only the + preservation of its persistent state is needed. +- Rsync-based replication for one-to-one data replication: + Data is replicated directly to a remote location. The replication uses + the [Rsync](https://rsync.samba.org/) utility over an ssh connection + to securely and efficiently transfer data. + +**Please see the [📖 full documentation +📖](https://volsync.readthedocs.io/) for more details.** + +## Requirements + +- Kubernetes >= 1.17 +- The Kubernetes snapshot controller must be installed on the cluster, whether + or not clones & snapshots are used. +- CSI-based storage driver that supports snapshots and/or clones is recommended, + but not required + +## Installation + +VolSync is a cluster-level operator. A single instance of the operator will +provide replication capabilities to all namespaces in the cluster. +**Running more than one instance of VolSync at a time is not supported.** + +```console +$ helm repo add backube-helm-charts https://backube.github.io/helm-charts/ +$ helm install --create-namespace --namespace volsync-system volsync backube/volsync + +NAME: volsync +LAST DEPLOYED: Thu Jan 28 13:52:18 2021 +NAMESPACE: volsync-system +STATUS: deployed +REVISION: 1 +TEST SUITE: None +NOTES: + +The VolSync operator has been installed into the volsync-system namespace. + +Please see https://volsync.readthedocs.org for documentation. +``` + +## Configuration + +The following parameters in the chart can be configured, either by using `--set` +on the command line or via a custom `values.yaml` file. + +- `manageCRDs`: true + - Whether the chart should install/upgrade the VolSync CRDs +- `replicaCount`: `1` + - The number of replicas of the operator to run. Only one is active at a time, + controlled via leader election. +- `image.repository`: `quay.io/backube/volsync` + - The container image of the VolSync operator +- `image.pullPolicy`: `IfNotPresent` + - The image pull policy to apply to the operator's image +- `image.tag`: (current appVersion) + - The tag to use when retrieving the operator image. This defaults to the tag + for the current application version associated with this chart release. +- `image.image`: (empty) + - Allows overriding the repository & tag as a single field to support + specifying a specific container version by hash (e.g., + `quay.io/backube/volsync@sha256:XXXXXXX`). +- `rclone.repository`: `quay.io/backube/volsync-mover-rclone` + - The container image for VolSync's rclone-based data mover +- `rclone.tag`: (current appVersion) + - The tag to use for the rclone-based data mover +- `rclone.image`: (empty) + - Allows overriding the repository & tag as a single field. +- `restic.repository`: `quay.io/backube/volsync-mover-restic` + - The container image for VolSync's restic-based data mover +- `restic.tag`: (current appVersion) + - The tag to use for the restic-based data mover +- `restic.image`: (empty) + - Allows overriding the repository & tag as a single field. +- `rsync.repository`: `quay.io/backube/volsync-mover-rsync` + - The container image for VolSync's rsync-based data mover +- `rsync.tag`: (current appVersion) + - The tag to use for the rsync-based data mover +- `rsync.image`: (empty) + - Allows overriding the repository & tag as a single field. +- `rsync-tls.repository`: `quay.io/backube/volsync-mover-rsync-tls` + - The container image for VolSync's rsync-tls-based data mover +- `rsync-tls.tag`: (current appVersion) + - The tag to use for the rsync-based data mover +- `rsync-tls.image`: (empty) + - Allows overriding the repository & tag as a single field. +- `imagePullSecrets`: none + - May be set if pull secret(s) are needed to retrieve the operator image +- `serviceAccount.create`: `true` + - Whether to create the ServiceAccount for the operator +- `serviceAccount.annotations`: none + - Annotations to add to the operator's service account +- `serviceAccount.name`: none + - Override the name of the operator's ServiceAccount +- `service.ipFamilyPolicy`: (empty) + - Set the ip family policy to configure dual-stack see + [Configure dual-stack](https://kubernetes.io/docs/concepts/services-networking/dual-stack/#services) +- `service.ipFamilies`: none + - Sets the families that should be supported and the order + in which they should be applied to ClusterIP as well. Can be IPv4 and/or IPv6. +- `podSecurityContext`: none + - Allows setting the security context for the operator pod +- `podAnnotations`: none + - Annotations to add to the operator's pod +- `securityContext`: none + - Allows setting the operator container's security context +- `resources`: requests 100m CPU and 20Mi memory; limits 100m CPU and 300Mi + memory + - Allows overriding the resource requests/limits for the operator pod +- `nodeSelector`: none + - Allows applying a node selector to the operator pod +- `tolerations`: none + - Allows applying tolerations to the operator pod +- `affinity`: none + - Allows setting the operator pod's affinity diff --git a/helmcharts/stable-0.12/volsync/templates/NOTES.txt b/helmcharts/stable-0.12/volsync/templates/NOTES.txt new file mode 100644 index 0000000..a789bac --- /dev/null +++ b/helmcharts/stable-0.12/volsync/templates/NOTES.txt @@ -0,0 +1,5 @@ + +The VolSync operator has been installed into the {{ .Release.Namespace }} +namespace. + +Please see https://volsync.readthedocs.org for documentation. diff --git a/helmcharts/stable-0.12/volsync/templates/_helpers.tpl b/helmcharts/stable-0.12/volsync/templates/_helpers.tpl new file mode 100644 index 0000000..4c1110e --- /dev/null +++ b/helmcharts/stable-0.12/volsync/templates/_helpers.tpl @@ -0,0 +1,78 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "volsync.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "volsync.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "volsync.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "volsync.labels" -}} +helm.sh/chart: {{ include "volsync.chart" . }} +{{ include "volsync.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "volsync.selectorLabels" -}} +app.kubernetes.io/name: {{ include "volsync.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "volsync.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "volsync.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Determine the container image to use +Usage: {{- include "container-image" (list $ .Values.image) }} +This horrible hack from: https://blog.flant.com/advanced-helm-templating/ +*/}} +{{- define "container-image" -}} +{{- $ := index . 0 }} +{{- with index . 1 }} +{{- if .image -}} +{{ .image }} +{{- else -}} +{{ .repository }}:{{ .tag | default $.Chart.AppVersion }} +{{- end -}} +{{- end -}} +{{- end }} diff --git a/helmcharts/stable-0.12/volsync/templates/clusterrole-manager.yaml b/helmcharts/stable-0.12/volsync/templates/clusterrole-manager.yaml new file mode 100644 index 0000000..f1f01c5 --- /dev/null +++ b/helmcharts/stable-0.12/volsync/templates/clusterrole-manager.yaml @@ -0,0 +1,298 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "volsync.fullname" . }}-manager + labels: + {{- include "volsync.labels" . | nindent 4 }} +rules: +- apiGroups: + - apps + resources: + - deployments + verbs: + - create + - delete + - deletecollection + - get + - list + - patch + - update + - watch +- apiGroups: + - batch + resources: + - jobs + verbs: + - create + - delete + - deletecollection + - get + - list + - patch + - update + - watch +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch + - update +- apiGroups: + - "" + resources: + - namespaces + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - nodes + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - persistentvolumeclaims + verbs: + - create + - delete + - deletecollection + - get + - list + - patch + - update + - watch +- apiGroups: + - "" + resources: + - persistentvolumeclaims/finalizers + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - "" + resources: + - persistentvolumes + verbs: + - get + - list + - patch + - watch +- apiGroups: + - "" + resources: + - pods + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - pods/log + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - secrets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - "" + resources: + - serviceaccounts + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - "" + resources: + - services + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - events.k8s.io + resources: + - events + verbs: + - create + - patch + - update +- apiGroups: + - populator.storage.k8s.io + resources: + - volumepopulators + verbs: + - create + - get + - list + - patch + - update + - watch +- apiGroups: + - rbac.authorization.k8s.io + resources: + - rolebindings + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - rbac.authorization.k8s.io + resources: + - roles + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - security.openshift.io + resources: + - securitycontextconstraints + verbs: + - create + - get + - list + - patch + - update + - watch +- apiGroups: + - security.openshift.io + resourceNames: + - volsync-privileged-mover + resources: + - securitycontextconstraints + verbs: + - use +- apiGroups: + - snapshot.storage.k8s.io + resources: + - volumesnapshots + verbs: + - create + - delete + - deletecollection + - get + - list + - patch + - update + - watch +- apiGroups: + - storage.k8s.io + resources: + - storageclasses + verbs: + - get + - list + - watch +- apiGroups: + - volsync.backube + resources: + - replicationdestinations + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - volsync.backube + resources: + - replicationdestinations/finalizers + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - volsync.backube + resources: + - replicationdestinations/status + verbs: + - get + - patch + - update +- apiGroups: + - volsync.backube + resources: + - replicationsources + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - volsync.backube + resources: + - replicationsources/finalizers + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - volsync.backube + resources: + - replicationsources/status + verbs: + - get + - patch + - update diff --git a/helmcharts/stable-0.12/volsync/templates/clusterrole-metrics-reader.yaml b/helmcharts/stable-0.12/volsync/templates/clusterrole-metrics-reader.yaml new file mode 100644 index 0000000..5cdfc87 --- /dev/null +++ b/helmcharts/stable-0.12/volsync/templates/clusterrole-metrics-reader.yaml @@ -0,0 +1,13 @@ +{{- if not .Values.metrics.disableAuth }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "volsync.fullname" . }}-metrics-reader + labels: + {{- include "volsync.labels" . | nindent 4 }} +rules: +- nonResourceURLs: + - /metrics + verbs: + - get +{{- end }} diff --git a/helmcharts/stable-0.12/volsync/templates/clusterrole-proxy-role.yaml b/helmcharts/stable-0.12/volsync/templates/clusterrole-proxy-role.yaml new file mode 100644 index 0000000..56a52e5 --- /dev/null +++ b/helmcharts/stable-0.12/volsync/templates/clusterrole-proxy-role.yaml @@ -0,0 +1,21 @@ +{{- if not .Values.metrics.disableAuth }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "volsync.fullname" . }}-proxy + labels: + {{- include "volsync.labels" . | nindent 4 }} +rules: +- apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create +- apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create +{{- end }} diff --git a/helmcharts/stable-0.12/volsync/templates/clusterrolebinding-manager.yaml b/helmcharts/stable-0.12/volsync/templates/clusterrolebinding-manager.yaml new file mode 100644 index 0000000..4eaf6b8 --- /dev/null +++ b/helmcharts/stable-0.12/volsync/templates/clusterrolebinding-manager.yaml @@ -0,0 +1,14 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "volsync.fullname" . }}-manager + labels: + {{- include "volsync.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "volsync.fullname" . }}-manager +subjects: +- kind: ServiceAccount + name: {{ include "volsync.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} diff --git a/helmcharts/stable-0.12/volsync/templates/clusterrolebinding-proxy.yaml b/helmcharts/stable-0.12/volsync/templates/clusterrolebinding-proxy.yaml new file mode 100644 index 0000000..c3d8f8f --- /dev/null +++ b/helmcharts/stable-0.12/volsync/templates/clusterrolebinding-proxy.yaml @@ -0,0 +1,16 @@ +{{- if not .Values.metrics.disableAuth }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "volsync.fullname" . }}-proxy + labels: + {{- include "volsync.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "volsync.fullname" . }}-proxy +subjects: +- kind: ServiceAccount + name: {{ include "volsync.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/helmcharts/stable-0.12/volsync/templates/deployment-controller.yaml b/helmcharts/stable-0.12/volsync/templates/deployment-controller.yaml new file mode 100644 index 0000000..26103c7 --- /dev/null +++ b/helmcharts/stable-0.12/volsync/templates/deployment-controller.yaml @@ -0,0 +1,126 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "volsync.fullname" . }} + labels: + control-plane: {{ include "volsync.fullname" . }}-controller + {{- include "volsync.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + control-plane: {{ include "volsync.fullname" . }}-controller + {{- include "volsync.selectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + kubectl.kubernetes.io/default-container: manager + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + control-plane: {{ include "volsync.fullname" . }}-controller + {{- include "volsync.selectorLabels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "volsync.serviceAccountName" . }} + # The default for podSecurityContext is moved here so that we can probe + # the cluster and and adjust the template + securityContext: + {{- if empty .Values.podSecurityContext }} + runAsNonRoot: true + # When not OpenShift, we need to set the UID + {{- if not (.Capabilities.APIVersions.Has "security.openshift.io/v1/SecurityContextConstraints") }} + runAsUser: 65534 + {{- end }} + # seccompProfile: + # type: RuntimeDefault + {{- else }} + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- end }} + containers: + - name: kube-rbac-proxy + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - "ALL" + readOnlyRootFilesystem: true + image: "{{ include "container-image" (list . (index .Values "kube-rbac-proxy") ) }}" + args: + - --secure-listen-address=0.0.0.0:8443 + - --upstream=http://127.0.0.1:8080/ + - --logtostderr=true + - "--tls-min-version=VersionTLS12" + - --v=0 + {{- if .Values.metrics.disableAuth }} + - --ignore-paths=/metrics + {{- end }} + ports: + - containerPort: 8443 + protocol: TCP + name: https + resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 5m + memory: 64Mi + - name: manager + args: + - --health-probe-bind-address=:8081 + - --metrics-bind-address=127.0.0.1:8080 + - --leader-elect + - --rclone-container-image={{ include "container-image" (list . .Values.rclone) }} + - --restic-container-image={{ include "container-image" (list . .Values.restic) }} + - --rsync-container-image={{ include "container-image" (list . .Values.rsync) }} + - --rsync-tls-container-image={{ include "container-image" (list . (index .Values "rsync-tls") ) }} + - --syncthing-container-image={{ include "container-image" (list . .Values.syncthing) }} + - --scc-name=volsync-privileged-mover + command: + - /manager + image: "{{ include "container-image" (list . .Values.image) }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + livenessProbe: + httpGet: + path: /healthz + port: 8081 + initialDelaySeconds: 15 + periodSeconds: 20 + readinessProbe: + httpGet: + path: /readyz + port: 8081 + initialDelaySeconds: 5 + periodSeconds: 10 + resources: + {{- toYaml .Values.resources | nindent 12 }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + volumeMounts: + - name: tempdir + mountPath: /tmp + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + terminationGracePeriodSeconds: 10 + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + volumes: + - name: tempdir + emptyDir: + medium: "Memory" diff --git a/helmcharts/stable-0.12/volsync/templates/role-leader-election.yaml b/helmcharts/stable-0.12/volsync/templates/role-leader-election.yaml new file mode 100644 index 0000000..2d54875 --- /dev/null +++ b/helmcharts/stable-0.12/volsync/templates/role-leader-election.yaml @@ -0,0 +1,38 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "volsync.fullname" . }}-leader-election + labels: + {{- include "volsync.labels" . | nindent 4 }} +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch diff --git a/helmcharts/stable-0.12/volsync/templates/rolebinding-leader-election.yaml b/helmcharts/stable-0.12/volsync/templates/rolebinding-leader-election.yaml new file mode 100644 index 0000000..92b365a --- /dev/null +++ b/helmcharts/stable-0.12/volsync/templates/rolebinding-leader-election.yaml @@ -0,0 +1,14 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "volsync.fullname" . }}-leader-election + labels: + {{- include "volsync.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "volsync.fullname" . }}-leader-election +subjects: +- kind: ServiceAccount + name: {{ include "volsync.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} diff --git a/helmcharts/stable-0.12/volsync/templates/service-metrics.yaml b/helmcharts/stable-0.12/volsync/templates/service-metrics.yaml new file mode 100644 index 0000000..4f1873c --- /dev/null +++ b/helmcharts/stable-0.12/volsync/templates/service-metrics.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "volsync.fullname" . }}-metrics + labels: + control-plane: {{ include "volsync.fullname" . }}-controller + {{- include "volsync.labels" . | nindent 4 }} +spec: + {{- if .Values.service.ipFamilyPolicy }} + ipFamilyPolicy: {{ .Values.service.ipFamilyPolicy }} + {{- end }} + {{- if .Values.service.ipFamilies }} + ipFamilies: {{ .Values.service.ipFamilies | toYaml | nindent 2 }} + {{- end }} + ports: + - name: https + port: 8443 + targetPort: https + selector: + control-plane: {{ include "volsync.fullname" . }}-controller diff --git a/helmcharts/stable-0.12/volsync/templates/serviceaccount.yaml b/helmcharts/stable-0.12/volsync/templates/serviceaccount.yaml new file mode 100644 index 0000000..b69493e --- /dev/null +++ b/helmcharts/stable-0.12/volsync/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "volsync.serviceAccountName" . }} + labels: + {{- include "volsync.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/helmcharts/stable-0.12/volsync/templates/servicemonitor-volsync.yaml b/helmcharts/stable-0.12/volsync/templates/servicemonitor-volsync.yaml new file mode 100644 index 0000000..6584629 --- /dev/null +++ b/helmcharts/stable-0.12/volsync/templates/servicemonitor-volsync.yaml @@ -0,0 +1,21 @@ +{{- if .Capabilities.APIVersions.Has "monitoring.coreos.com/v1/ServiceMonitor" }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: volsync + labels: + control-plane: {{ include "volsync.fullname" . }}-controller + {{- include "volsync.labels" . | nindent 4 }} +spec: + endpoints: + - interval: 30s + path: /metrics + port: https + scheme: https + tlsConfig: + # Using self-signed cert for connection + insecureSkipVerify: true + selector: + matchLabels: + control-plane: {{ include "volsync.fullname" . }}-controller +{{- end }} diff --git a/helmcharts/stable-0.12/volsync/templates/volsync.backube_replicationdestinations.yaml b/helmcharts/stable-0.12/volsync/templates/volsync.backube_replicationdestinations.yaml new file mode 100644 index 0000000..6ea5289 --- /dev/null +++ b/helmcharts/stable-0.12/volsync/templates/volsync.backube_replicationdestinations.yaml @@ -0,0 +1,4208 @@ +{{- if .Values.manageCRDs }} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.3 + helm.sh/resource-policy: keep + name: replicationdestinations.volsync.backube +spec: + group: volsync.backube + names: + kind: ReplicationDestination + listKind: ReplicationDestinationList + plural: replicationdestinations + singular: replicationdestination + scope: Namespaced + versions: + - additionalPrinterColumns: + - format: date-time + jsonPath: .status.lastSyncTime + name: Last sync + type: string + - jsonPath: .status.lastSyncDuration + name: Duration + type: string + - format: date-time + jsonPath: .status.nextSyncTime + name: Next sync + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + A ReplicationDestination is a VolSync resource that you can use to define the destination of a VolSync replication + or synchronization. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + spec is the desired state of the ReplicationDestination, including the + replication method to use and its configuration. + properties: + external: + description: |- + external defines the configuration when using an external replication + provider. + properties: + parameters: + additionalProperties: + type: string + description: |- + parameters are provider-specific key/value configuration parameters. For + more information, please see the documentation of the specific + replication provider being used. + type: object + provider: + description: |- + provider is the name of the external replication provider. The name + should be of the form: domain.com/provider. + type: string + type: object + paused: + description: paused can be used to temporarily stop replication. Defaults to "false". + type: boolean + rclone: + description: rclone defines the configuration when using Rclone-based replication. + properties: + accessModes: + description: accessModes specifies the access modes for the destination volume. + items: + type: string + minItems: 1 + type: array + capacity: + anyOf: + - type: integer + - type: string + description: capacity is the size of the destination volume to create. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + cleanupTempPVC: + description: |- + Set this to true to delete the temp destination PVC (dynamically provisioned + by VolSync) at the end of each successful ReplicationDestination sync iteration. + If destinationPVC is set, this will have no effect, VolSync will only + cleanup temp PVCs that it deployed. + Note that if this is set to true, every sync this ReplicationDestination + makes will re-provision a new temp destination PVC and all data + will need to be sent again during the sync. + Dynamically provisioned destination PVCs will always be deleted if the + owning ReplicationDestination is removed, even if this setting is false. + The default is false. + type: boolean + copyMethod: + description: |- + copyMethod describes how a point-in-time (PiT) image of the destination + volume should be created. + enum: + - Direct + - None + - Clone + - Snapshot + type: string + customCA: + description: customCA is a custom CA that will be used to verify the remote + properties: + configMapName: + description: |- + The name of a ConfigMap that contains the custom CA certificate + If ConfigMapName is used then SecretName should not be set + type: string + key: + description: The key within the Secret or ConfigMap containing the CA certificate + type: string + secretName: + description: |- + The name of a Secret that contains the custom CA certificate + If SecretName is used then ConfigMapName should not be set + type: string + type: object + destinationPVC: + description: |- + destinationPVC is a PVC to use as the transfer destination instead of + automatically provisioning one. Either this field or both capacity and + accessModes must be specified. + type: string + moverAffinity: + description: MoverAffinity allows specifying the PodAffinity that will be used by the data mover + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + moverPodLabels: + additionalProperties: + type: string + description: |- + Labels that should be added to data mover pods + These will be in addition to any labels that VolSync may add + type: object + moverResources: + description: |- + Resources represents compute resources required by the data mover container. + Immutable. + More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ + This should only be used by advanced users as this can result in a mover + pod being unschedulable or crashing due to limited resources. + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + moverSecurityContext: + description: |- + MoverSecurityContext allows specifying the PodSecurityContext that will + be used by the data mover + properties: + appArmorProfile: + description: |- + appArmorProfile is the AppArmor options to use by the containers in this pod. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile loaded on the node that should be used. + The profile must be preconfigured on the node to work. + Must match the loaded name of the profile. + Must be set if and only if type is "Localhost". + type: string + type: + description: |- + type indicates which kind of AppArmor profile will be applied. + Valid options are: + Localhost - a profile pre-loaded on the node. + RuntimeDefault - the container runtime's default profile. + Unconfined - no AppArmor enforcement. + type: string + required: + - type + type: object + fsGroup: + description: |- + A special supplemental group that applies to all containers in a pod. + Some volume types allow the Kubelet to change the ownership of that volume + to be owned by the pod: + + 1. The owning GID will be the FSGroup + 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) + 3. The permission bits are OR'd with rw-rw---- + + If unset, the Kubelet will not modify the ownership and permissions of any volume. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + fsGroupChangePolicy: + description: |- + fsGroupChangePolicy defines behavior of changing ownership and permission of the volume + before being exposed inside Pod. This field will only apply to + volume types which support fsGroup based ownership(and permissions). + It will have no effect on ephemeral volume types such as: secret, configmaps + and emptydir. + Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. + Note that this field cannot be set when spec.os.name is windows. + type: string + runAsGroup: + description: |- + The GID to run the entrypoint of the container process. + Uses runtime default if unset. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: |- + Indicates that the container must run as a non-root user. + If true, the Kubelet will validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start the container if it does. + If unset or false, no such validation will be performed. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: |- + The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: |- + The SELinux context to be applied to all containers. + If unspecified, the container runtime will allocate a random SELinux context for each + container. May also be set in SecurityContext. If set in + both SecurityContext and PodSecurityContext, the value specified in SecurityContext + takes precedence for that container. + Note that this field cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that applies to the container. + type: string + role: + description: Role is a SELinux role label that applies to the container. + type: string + type: + description: Type is a SELinux type label that applies to the container. + type: string + user: + description: User is a SELinux user label that applies to the container. + type: string + type: object + seccompProfile: + description: |- + The seccomp options to use by the containers in this pod. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + supplementalGroups: + description: |- + A list of groups applied to the first process run in each container, in + addition to the container's primary GID and fsGroup (if specified). If + the SupplementalGroupsPolicy feature is enabled, the + supplementalGroupsPolicy field determines whether these are in addition + to or instead of any group memberships defined in the container image. + If unspecified, no additional groups are added, though group memberships + defined in the container image may still be used, depending on the + supplementalGroupsPolicy field. + Note that this field cannot be set when spec.os.name is windows. + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + description: |- + Defines how supplemental groups of the first container processes are calculated. + Valid values are "Merge" and "Strict". If not specified, "Merge" is used. + (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled + and the container runtime must implement support for this feature. + Note that this field cannot be set when spec.os.name is windows. + type: string + sysctls: + description: |- + Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported + sysctls (by the container runtime) might fail to launch. + Note that this field cannot be set when spec.os.name is windows. + items: + description: Sysctl defines a kernel parameter to be set + properties: + name: + description: Name of a property to set + type: string + value: + description: Value of a property to set + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + description: |- + The Windows specific settings applied to all containers. + If unspecified, the options within a container's SecurityContext will be used. + If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: |- + GMSACredentialSpec is where the GMSA admission webhook + (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the + GMSA credential spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of the GMSA credential spec to use. + type: string + hostProcess: + description: |- + HostProcess determines if a container should be run as a 'Host Process' container. + All of a Pod's containers must have the same effective HostProcess value + (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). + In addition, if HostProcess is true then HostNetwork must also be set to true. + type: boolean + runAsUserName: + description: |- + The UserName in Windows to run the entrypoint of the container process. + Defaults to the user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: string + type: object + type: object + moverServiceAccount: + description: |- + MoverServiceAccount allows specifying the name of the service account + that will be used by the data mover. This should only be used by advanced + users who want to override the service account normally used by the mover. + The service account needs to exist in the same namespace as this CR. + type: string + rcloneConfig: + description: RcloneConfig is the rclone secret name + type: string + rcloneConfigSection: + description: RcloneConfigSection is the section in rclone_config file to use for the current job. + type: string + rcloneDestPath: + description: RcloneDestPath is the remote path to sync to. + type: string + storageClassName: + description: |- + storageClassName can be used to specify the StorageClass of the + destination volume. If not set, the default StorageClass will be used. + type: string + volumeSnapshotClassName: + description: |- + volumeSnapshotClassName can be used to specify the VSC to be used if + copyMethod is Snapshot. If not set, the default VSC is used. + type: string + type: object + restic: + description: restic defines the configuration when using Restic-based replication. + properties: + accessModes: + description: accessModes specifies the access modes for the destination volume. + items: + type: string + minItems: 1 + type: array + cacheAccessModes: + description: accessModes can be used to set the accessModes of restic metadata cache volume + items: + type: string + type: array + cacheCapacity: + anyOf: + - type: integer + - type: string + description: cacheCapacity can be used to set the size of the restic metadata cache volume + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + cacheStorageClassName: + description: |- + cacheStorageClassName can be used to set the StorageClass of the restic + metadata cache volume + type: string + capacity: + anyOf: + - type: integer + - type: string + description: capacity is the size of the destination volume to create. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + cleanupCachePVC: + description: |- + Set this to true to delete the restic cache PVC (dynamically provisioned + by VolSync) at the end of each successful ReplicationDestination sync iteration. + Cache PVCs will always be deleted if the owning ReplicationDestination is + removed, even if this setting is false. + The default is false. + type: boolean + cleanupTempPVC: + description: |- + Set this to true to delete the temp destination PVC (dynamically provisioned + by VolSync) at the end of each successful ReplicationDestination sync iteration. + If destinationPVC is set, this will have no effect, VolSync will only + cleanup temp PVCs that it deployed. + Note that if this is set to true, every sync this ReplicationDestination + makes will re-provision a new temp destination PVC and all data + will need to be sent again during the sync. + Dynamically provisioned destination PVCs will always be deleted if the + owning ReplicationDestination is removed, even if this setting is false. + The default is false. + type: boolean + copyMethod: + description: |- + copyMethod describes how a point-in-time (PiT) image of the destination + volume should be created. + enum: + - Direct + - None + - Clone + - Snapshot + type: string + customCA: + description: customCA is a custom CA that will be used to verify the remote + properties: + configMapName: + description: |- + The name of a ConfigMap that contains the custom CA certificate + If ConfigMapName is used then SecretName should not be set + type: string + key: + description: The key within the Secret or ConfigMap containing the CA certificate + type: string + secretName: + description: |- + The name of a Secret that contains the custom CA certificate + If SecretName is used then ConfigMapName should not be set + type: string + type: object + destinationPVC: + description: |- + destinationPVC is a PVC to use as the transfer destination instead of + automatically provisioning one. Either this field or both capacity and + accessModes must be specified. + type: string + enableFileDeletion: + description: |- + enableFileDeletion will pass the --delete flag to the restic restore command. + This will remove files and directories in the pvc that do not exist in the snapshot being restored. + Defaults to false. + type: boolean + moverAffinity: + description: MoverAffinity allows specifying the PodAffinity that will be used by the data mover + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + moverPodLabels: + additionalProperties: + type: string + description: |- + Labels that should be added to data mover pods + These will be in addition to any labels that VolSync may add + type: object + moverResources: + description: |- + Resources represents compute resources required by the data mover container. + Immutable. + More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ + This should only be used by advanced users as this can result in a mover + pod being unschedulable or crashing due to limited resources. + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + moverSecurityContext: + description: |- + MoverSecurityContext allows specifying the PodSecurityContext that will + be used by the data mover + properties: + appArmorProfile: + description: |- + appArmorProfile is the AppArmor options to use by the containers in this pod. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile loaded on the node that should be used. + The profile must be preconfigured on the node to work. + Must match the loaded name of the profile. + Must be set if and only if type is "Localhost". + type: string + type: + description: |- + type indicates which kind of AppArmor profile will be applied. + Valid options are: + Localhost - a profile pre-loaded on the node. + RuntimeDefault - the container runtime's default profile. + Unconfined - no AppArmor enforcement. + type: string + required: + - type + type: object + fsGroup: + description: |- + A special supplemental group that applies to all containers in a pod. + Some volume types allow the Kubelet to change the ownership of that volume + to be owned by the pod: + + 1. The owning GID will be the FSGroup + 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) + 3. The permission bits are OR'd with rw-rw---- + + If unset, the Kubelet will not modify the ownership and permissions of any volume. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + fsGroupChangePolicy: + description: |- + fsGroupChangePolicy defines behavior of changing ownership and permission of the volume + before being exposed inside Pod. This field will only apply to + volume types which support fsGroup based ownership(and permissions). + It will have no effect on ephemeral volume types such as: secret, configmaps + and emptydir. + Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. + Note that this field cannot be set when spec.os.name is windows. + type: string + runAsGroup: + description: |- + The GID to run the entrypoint of the container process. + Uses runtime default if unset. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: |- + Indicates that the container must run as a non-root user. + If true, the Kubelet will validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start the container if it does. + If unset or false, no such validation will be performed. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: |- + The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: |- + The SELinux context to be applied to all containers. + If unspecified, the container runtime will allocate a random SELinux context for each + container. May also be set in SecurityContext. If set in + both SecurityContext and PodSecurityContext, the value specified in SecurityContext + takes precedence for that container. + Note that this field cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that applies to the container. + type: string + role: + description: Role is a SELinux role label that applies to the container. + type: string + type: + description: Type is a SELinux type label that applies to the container. + type: string + user: + description: User is a SELinux user label that applies to the container. + type: string + type: object + seccompProfile: + description: |- + The seccomp options to use by the containers in this pod. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + supplementalGroups: + description: |- + A list of groups applied to the first process run in each container, in + addition to the container's primary GID and fsGroup (if specified). If + the SupplementalGroupsPolicy feature is enabled, the + supplementalGroupsPolicy field determines whether these are in addition + to or instead of any group memberships defined in the container image. + If unspecified, no additional groups are added, though group memberships + defined in the container image may still be used, depending on the + supplementalGroupsPolicy field. + Note that this field cannot be set when spec.os.name is windows. + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + description: |- + Defines how supplemental groups of the first container processes are calculated. + Valid values are "Merge" and "Strict". If not specified, "Merge" is used. + (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled + and the container runtime must implement support for this feature. + Note that this field cannot be set when spec.os.name is windows. + type: string + sysctls: + description: |- + Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported + sysctls (by the container runtime) might fail to launch. + Note that this field cannot be set when spec.os.name is windows. + items: + description: Sysctl defines a kernel parameter to be set + properties: + name: + description: Name of a property to set + type: string + value: + description: Value of a property to set + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + description: |- + The Windows specific settings applied to all containers. + If unspecified, the options within a container's SecurityContext will be used. + If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: |- + GMSACredentialSpec is where the GMSA admission webhook + (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the + GMSA credential spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of the GMSA credential spec to use. + type: string + hostProcess: + description: |- + HostProcess determines if a container should be run as a 'Host Process' container. + All of a Pod's containers must have the same effective HostProcess value + (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). + In addition, if HostProcess is true then HostNetwork must also be set to true. + type: boolean + runAsUserName: + description: |- + The UserName in Windows to run the entrypoint of the container process. + Defaults to the user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: string + type: object + type: object + moverServiceAccount: + description: |- + MoverServiceAccount allows specifying the name of the service account + that will be used by the data mover. This should only be used by advanced + users who want to override the service account normally used by the mover. + The service account needs to exist in the same namespace as this CR. + type: string + previous: + description: Previous specifies the number of image to skip before selecting one to restore from + format: int32 + type: integer + repository: + description: Repository is the secret name containing repository info + type: string + restoreAsOf: + description: RestoreAsOf refers to the backup that is most recent as of that time. + format: date-time + type: string + storageClassName: + description: |- + storageClassName can be used to specify the StorageClass of the + destination volume. If not set, the default StorageClass will be used. + type: string + volumeSnapshotClassName: + description: |- + volumeSnapshotClassName can be used to specify the VSC to be used if + copyMethod is Snapshot. If not set, the default VSC is used. + type: string + type: object + rsync: + description: rsync defines the configuration when using Rsync-based replication. + properties: + accessModes: + description: accessModes specifies the access modes for the destination volume. + items: + type: string + minItems: 1 + type: array + address: + description: address is the remote address to connect to for replication. + type: string + capacity: + anyOf: + - type: integer + - type: string + description: capacity is the size of the destination volume to create. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + cleanupTempPVC: + description: |- + Set this to true to delete the temp destination PVC (dynamically provisioned + by VolSync) at the end of each successful ReplicationDestination sync iteration. + If destinationPVC is set, this will have no effect, VolSync will only + cleanup temp PVCs that it deployed. + Note that if this is set to true, every sync this ReplicationDestination + makes will re-provision a new temp destination PVC and all data + will need to be sent again during the sync. + Dynamically provisioned destination PVCs will always be deleted if the + owning ReplicationDestination is removed, even if this setting is false. + The default is false. + type: boolean + copyMethod: + description: |- + copyMethod describes how a point-in-time (PiT) image of the destination + volume should be created. + enum: + - Direct + - None + - Clone + - Snapshot + type: string + destinationPVC: + description: |- + destinationPVC is a PVC to use as the transfer destination instead of + automatically provisioning one. Either this field or both capacity and + accessModes must be specified. + type: string + moverPodLabels: + additionalProperties: + type: string + description: |- + Labels that should be added to data mover pods + These will be in addition to any labels that VolSync may add + type: object + moverResources: + description: |- + Resources represents compute resources required by the data mover container. + Immutable. + More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ + This should only be used by advanced users as this can result in a mover + pod being unschedulable or crashing due to limited resources. + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + moverServiceAccount: + description: |- + MoverServiceAccount allows specifying the name of the service account + that will be used by the data mover. This should only be used by advanced + users who want to override the service account normally used by the mover. + The service account needs to exist in the same namespace as the ReplicationDestination. + type: string + path: + description: path is the remote path to rsync from. Defaults to "/" + type: string + port: + description: port is the SSH port to connect to for replication. Defaults to 22. + format: int32 + maximum: 65535 + minimum: 0 + type: integer + serviceAnnotations: + additionalProperties: + type: string + description: |- + serviceAnnotations defines annotations that will be added to the + service created for incoming SSH connections. If set, these annotations + will be used instead of any VolSync default values. + type: object + serviceType: + description: |- + serviceType determines the Service type that will be created for incoming + SSH connections. + type: string + sshKeys: + description: |- + sshKeys is the name of a Secret that contains the SSH keys to be used for + authentication. If not provided, the keys will be generated. + type: string + sshUser: + description: sshUser is the username for outgoing SSH connections. Defaults to "root". + type: string + storageClassName: + description: |- + storageClassName can be used to specify the StorageClass of the + destination volume. If not set, the default StorageClass will be used. + type: string + volumeMode: + description: |- + Will be used for the dynamic destination PVC created by VolSync. + Defaults to "Filesystem" + type: string + volumeSnapshotClassName: + description: |- + volumeSnapshotClassName can be used to specify the VSC to be used if + copyMethod is Snapshot. If not set, the default VSC is used. + type: string + type: object + rsyncTLS: + description: rsyncTLS defines the configuration when using Rsync-based replication over TLS. + properties: + accessModes: + description: accessModes specifies the access modes for the destination volume. + items: + type: string + minItems: 1 + type: array + capacity: + anyOf: + - type: integer + - type: string + description: capacity is the size of the destination volume to create. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + cleanupTempPVC: + description: |- + Set this to true to delete the temp destination PVC (dynamically provisioned + by VolSync) at the end of each successful ReplicationDestination sync iteration. + If destinationPVC is set, this will have no effect, VolSync will only + cleanup temp PVCs that it deployed. + Note that if this is set to true, every sync this ReplicationDestination + makes will re-provision a new temp destination PVC and all data + will need to be sent again during the sync. + Dynamically provisioned destination PVCs will always be deleted if the + owning ReplicationDestination is removed, even if this setting is false. + The default is false. + type: boolean + copyMethod: + description: |- + copyMethod describes how a point-in-time (PiT) image of the destination + volume should be created. + enum: + - Direct + - None + - Clone + - Snapshot + type: string + destinationPVC: + description: |- + destinationPVC is a PVC to use as the transfer destination instead of + automatically provisioning one. Either this field or both capacity and + accessModes must be specified. + type: string + keySecret: + description: |- + keySecret is the name of a Secret that contains the TLS pre-shared key to + be used for authentication. If not provided, the key will be generated. + type: string + moverAffinity: + description: MoverAffinity allows specifying the PodAffinity that will be used by the data mover + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + moverPodLabels: + additionalProperties: + type: string + description: |- + Labels that should be added to data mover pods + These will be in addition to any labels that VolSync may add + type: object + moverResources: + description: |- + Resources represents compute resources required by the data mover container. + Immutable. + More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ + This should only be used by advanced users as this can result in a mover + pod being unschedulable or crashing due to limited resources. + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + moverSecurityContext: + description: |- + MoverSecurityContext allows specifying the PodSecurityContext that will + be used by the data mover + properties: + appArmorProfile: + description: |- + appArmorProfile is the AppArmor options to use by the containers in this pod. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile loaded on the node that should be used. + The profile must be preconfigured on the node to work. + Must match the loaded name of the profile. + Must be set if and only if type is "Localhost". + type: string + type: + description: |- + type indicates which kind of AppArmor profile will be applied. + Valid options are: + Localhost - a profile pre-loaded on the node. + RuntimeDefault - the container runtime's default profile. + Unconfined - no AppArmor enforcement. + type: string + required: + - type + type: object + fsGroup: + description: |- + A special supplemental group that applies to all containers in a pod. + Some volume types allow the Kubelet to change the ownership of that volume + to be owned by the pod: + + 1. The owning GID will be the FSGroup + 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) + 3. The permission bits are OR'd with rw-rw---- + + If unset, the Kubelet will not modify the ownership and permissions of any volume. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + fsGroupChangePolicy: + description: |- + fsGroupChangePolicy defines behavior of changing ownership and permission of the volume + before being exposed inside Pod. This field will only apply to + volume types which support fsGroup based ownership(and permissions). + It will have no effect on ephemeral volume types such as: secret, configmaps + and emptydir. + Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. + Note that this field cannot be set when spec.os.name is windows. + type: string + runAsGroup: + description: |- + The GID to run the entrypoint of the container process. + Uses runtime default if unset. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: |- + Indicates that the container must run as a non-root user. + If true, the Kubelet will validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start the container if it does. + If unset or false, no such validation will be performed. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: |- + The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: |- + The SELinux context to be applied to all containers. + If unspecified, the container runtime will allocate a random SELinux context for each + container. May also be set in SecurityContext. If set in + both SecurityContext and PodSecurityContext, the value specified in SecurityContext + takes precedence for that container. + Note that this field cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that applies to the container. + type: string + role: + description: Role is a SELinux role label that applies to the container. + type: string + type: + description: Type is a SELinux type label that applies to the container. + type: string + user: + description: User is a SELinux user label that applies to the container. + type: string + type: object + seccompProfile: + description: |- + The seccomp options to use by the containers in this pod. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + supplementalGroups: + description: |- + A list of groups applied to the first process run in each container, in + addition to the container's primary GID and fsGroup (if specified). If + the SupplementalGroupsPolicy feature is enabled, the + supplementalGroupsPolicy field determines whether these are in addition + to or instead of any group memberships defined in the container image. + If unspecified, no additional groups are added, though group memberships + defined in the container image may still be used, depending on the + supplementalGroupsPolicy field. + Note that this field cannot be set when spec.os.name is windows. + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + description: |- + Defines how supplemental groups of the first container processes are calculated. + Valid values are "Merge" and "Strict". If not specified, "Merge" is used. + (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled + and the container runtime must implement support for this feature. + Note that this field cannot be set when spec.os.name is windows. + type: string + sysctls: + description: |- + Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported + sysctls (by the container runtime) might fail to launch. + Note that this field cannot be set when spec.os.name is windows. + items: + description: Sysctl defines a kernel parameter to be set + properties: + name: + description: Name of a property to set + type: string + value: + description: Value of a property to set + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + description: |- + The Windows specific settings applied to all containers. + If unspecified, the options within a container's SecurityContext will be used. + If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: |- + GMSACredentialSpec is where the GMSA admission webhook + (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the + GMSA credential spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of the GMSA credential spec to use. + type: string + hostProcess: + description: |- + HostProcess determines if a container should be run as a 'Host Process' container. + All of a Pod's containers must have the same effective HostProcess value + (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). + In addition, if HostProcess is true then HostNetwork must also be set to true. + type: boolean + runAsUserName: + description: |- + The UserName in Windows to run the entrypoint of the container process. + Defaults to the user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: string + type: object + type: object + moverServiceAccount: + description: |- + MoverServiceAccount allows specifying the name of the service account + that will be used by the data mover. This should only be used by advanced + users who want to override the service account normally used by the mover. + The service account needs to exist in the same namespace as this CR. + type: string + serviceAnnotations: + additionalProperties: + type: string + description: |- + serviceAnnotations defines annotations that will be added to the + service created for incoming SSH connections. If set, these annotations + will be used instead of any VolSync default values. + type: object + serviceType: + description: |- + serviceType determines the Service type that will be created for incoming + TLS connections. + type: string + storageClassName: + description: |- + storageClassName can be used to specify the StorageClass of the + destination volume. If not set, the default StorageClass will be used. + type: string + volumeMode: + description: |- + Will be used for the dynamic destination PVC created by VolSync. + Defaults to "Filesystem" + type: string + volumeSnapshotClassName: + description: |- + volumeSnapshotClassName can be used to specify the VSC to be used if + copyMethod is Snapshot. If not set, the default VSC is used. + type: string + type: object + trigger: + description: |- + trigger determines if/when the destination should attempt to synchronize + data with the source. + properties: + manual: + description: |- + manual is a string value that schedules a manual trigger. + Once a sync completes then status.lastManualSync is set to the same string value. + A consumer of a manual trigger should set spec.trigger.manual to a known value + and then wait for lastManualSync to be updated by the operator to the same value, + which means that the manual trigger will then pause and wait for further + updates to the trigger. + type: string + schedule: + description: |- + schedule is a cronspec (https://en.wikipedia.org/wiki/Cron#Overview) that + can be used to schedule replication to occur at regular, time-based + intervals. + nolint:lll + pattern: ^(@(annually|yearly|monthly|weekly|daily|hourly))|((((\d+,)*\d+|(\d+(\/|-)\d+)|\*(\/\d+)?)\s?){5})$ + type: string + type: object + type: object + status: + description: |- + status is the observed state of the ReplicationDestination as determined + by the controller. + properties: + conditions: + description: |- + conditions represent the latest available observations of the + destination's state. + items: + description: Condition contains details for one aspect of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + external: + additionalProperties: + type: string + description: |- + external contains provider-specific status information. For more details, + please see the documentation of the specific replication provider being + used. + type: object + lastManualSync: + description: lastManualSync is set to the last spec.trigger.manual when the manual sync is done. + type: string + lastSyncDuration: + description: |- + lastSyncDuration is the amount of time required to send the most recent + update. + type: string + lastSyncStartTime: + description: lastSyncStartTime is the time the most recent synchronization started. + format: date-time + type: string + lastSyncTime: + description: lastSyncTime is the time of the most recent successful synchronization. + format: date-time + type: string + latestImage: + description: |- + latestImage in the object holding the most recent consistent replicated + image. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + latestMoverStatus: + description: Logs/Summary from latest mover job + properties: + logs: + type: string + result: + type: string + type: object + nextSyncTime: + description: |- + nextSyncTime is the time when the next volume synchronization is + scheduled to start (for schedule-based synchronization). + format: date-time + type: string + rsync: + description: rsync contains status information for Rsync-based replication. + properties: + address: + description: |- + address is the address to connect to for incoming SSH replication + connections. + type: string + port: + description: |- + port is the SSH port to connect to for incoming SSH replication + connections. + format: int32 + type: integer + sshKeys: + description: |- + sshKeys is the name of a Secret that contains the SSH keys to be used for + authentication. If not provided in .spec.rsync.sshKeys, SSH keys will be + generated and the appropriate keys for the remote side will be placed + here. + type: string + type: object + rsyncTLS: + description: rsyncTLS contains status information for Rsync-based replication over TLS. + properties: + address: + description: address is the address to connect to for incoming TLS connections. + type: string + keySecret: + description: |- + keySecret is the name of a Secret that contains the TLS pre-shared key to + be used for authentication. If not provided in .spec.rsyncTLS.keySecret, + the key Secret will be generated and named here. + type: string + port: + description: port is the port to connect to for incoming replication connections. + format: int32 + type: integer + type: object + type: object + type: object + served: true + storage: true + subresources: + status: {} +{{- end }} diff --git a/helmcharts/stable-0.12/volsync/templates/volsync.backube_replicationsources.yaml b/helmcharts/stable-0.12/volsync/templates/volsync.backube_replicationsources.yaml new file mode 100644 index 0000000..c29fda6 --- /dev/null +++ b/helmcharts/stable-0.12/volsync/templates/volsync.backube_replicationsources.yaml @@ -0,0 +1,5372 @@ +{{- if .Values.manageCRDs }} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.3 + helm.sh/resource-policy: keep + name: replicationsources.volsync.backube +spec: + group: volsync.backube + names: + kind: ReplicationSource + listKind: ReplicationSourceList + plural: replicationsources + singular: replicationsource + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.sourcePVC + name: Source + type: string + - format: date-time + jsonPath: .status.lastSyncTime + name: Last sync + type: string + - jsonPath: .status.lastSyncDuration + name: Duration + type: string + - format: date-time + jsonPath: .status.nextSyncTime + name: Next sync + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + A ReplicationSource is a VolSync resource that you can use to define the source PVC and replication mover type, + enabling you to replicate or synchronize PVC data to a remote location. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + spec is the desired state of the ReplicationSource, including the + replication method to use and its configuration. + properties: + external: + description: |- + external defines the configuration when using an external replication + provider. + properties: + parameters: + additionalProperties: + type: string + description: |- + parameters are provider-specific key/value configuration parameters. For + more information, please see the documentation of the specific + replication provider being used. + type: object + provider: + description: |- + provider is the name of the external replication provider. The name + should be of the form: domain.com/provider. + type: string + type: object + paused: + description: paused can be used to temporarily stop replication. Defaults to "false". + type: boolean + rclone: + description: rclone defines the configuration when using Rclone-based replication. + properties: + accessModes: + description: accessModes can be used to override the accessModes of the PiT image. + items: + type: string + minItems: 1 + type: array + capacity: + anyOf: + - type: integer + - type: string + description: capacity can be used to override the capacity of the PiT image. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + copyMethod: + description: |- + copyMethod describes how a point-in-time (PiT) image of the source volume + should be created. + enum: + - Direct + - None + - Clone + - Snapshot + type: string + customCA: + description: customCA is a custom CA that will be used to verify the remote + properties: + configMapName: + description: |- + The name of a ConfigMap that contains the custom CA certificate + If ConfigMapName is used then SecretName should not be set + type: string + key: + description: The key within the Secret or ConfigMap containing the CA certificate + type: string + secretName: + description: |- + The name of a Secret that contains the custom CA certificate + If SecretName is used then ConfigMapName should not be set + type: string + type: object + moverAffinity: + description: MoverAffinity allows specifying the PodAffinity that will be used by the data mover + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + moverPodLabels: + additionalProperties: + type: string + description: |- + Labels that should be added to data mover pods + These will be in addition to any labels that VolSync may add + type: object + moverResources: + description: |- + Resources represents compute resources required by the data mover container. + Immutable. + More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ + This should only be used by advanced users as this can result in a mover + pod being unschedulable or crashing due to limited resources. + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + moverSecurityContext: + description: |- + MoverSecurityContext allows specifying the PodSecurityContext that will + be used by the data mover + properties: + appArmorProfile: + description: |- + appArmorProfile is the AppArmor options to use by the containers in this pod. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile loaded on the node that should be used. + The profile must be preconfigured on the node to work. + Must match the loaded name of the profile. + Must be set if and only if type is "Localhost". + type: string + type: + description: |- + type indicates which kind of AppArmor profile will be applied. + Valid options are: + Localhost - a profile pre-loaded on the node. + RuntimeDefault - the container runtime's default profile. + Unconfined - no AppArmor enforcement. + type: string + required: + - type + type: object + fsGroup: + description: |- + A special supplemental group that applies to all containers in a pod. + Some volume types allow the Kubelet to change the ownership of that volume + to be owned by the pod: + + 1. The owning GID will be the FSGroup + 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) + 3. The permission bits are OR'd with rw-rw---- + + If unset, the Kubelet will not modify the ownership and permissions of any volume. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + fsGroupChangePolicy: + description: |- + fsGroupChangePolicy defines behavior of changing ownership and permission of the volume + before being exposed inside Pod. This field will only apply to + volume types which support fsGroup based ownership(and permissions). + It will have no effect on ephemeral volume types such as: secret, configmaps + and emptydir. + Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. + Note that this field cannot be set when spec.os.name is windows. + type: string + runAsGroup: + description: |- + The GID to run the entrypoint of the container process. + Uses runtime default if unset. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: |- + Indicates that the container must run as a non-root user. + If true, the Kubelet will validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start the container if it does. + If unset or false, no such validation will be performed. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: |- + The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: |- + The SELinux context to be applied to all containers. + If unspecified, the container runtime will allocate a random SELinux context for each + container. May also be set in SecurityContext. If set in + both SecurityContext and PodSecurityContext, the value specified in SecurityContext + takes precedence for that container. + Note that this field cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that applies to the container. + type: string + role: + description: Role is a SELinux role label that applies to the container. + type: string + type: + description: Type is a SELinux type label that applies to the container. + type: string + user: + description: User is a SELinux user label that applies to the container. + type: string + type: object + seccompProfile: + description: |- + The seccomp options to use by the containers in this pod. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + supplementalGroups: + description: |- + A list of groups applied to the first process run in each container, in + addition to the container's primary GID and fsGroup (if specified). If + the SupplementalGroupsPolicy feature is enabled, the + supplementalGroupsPolicy field determines whether these are in addition + to or instead of any group memberships defined in the container image. + If unspecified, no additional groups are added, though group memberships + defined in the container image may still be used, depending on the + supplementalGroupsPolicy field. + Note that this field cannot be set when spec.os.name is windows. + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + description: |- + Defines how supplemental groups of the first container processes are calculated. + Valid values are "Merge" and "Strict". If not specified, "Merge" is used. + (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled + and the container runtime must implement support for this feature. + Note that this field cannot be set when spec.os.name is windows. + type: string + sysctls: + description: |- + Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported + sysctls (by the container runtime) might fail to launch. + Note that this field cannot be set when spec.os.name is windows. + items: + description: Sysctl defines a kernel parameter to be set + properties: + name: + description: Name of a property to set + type: string + value: + description: Value of a property to set + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + description: |- + The Windows specific settings applied to all containers. + If unspecified, the options within a container's SecurityContext will be used. + If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: |- + GMSACredentialSpec is where the GMSA admission webhook + (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the + GMSA credential spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of the GMSA credential spec to use. + type: string + hostProcess: + description: |- + HostProcess determines if a container should be run as a 'Host Process' container. + All of a Pod's containers must have the same effective HostProcess value + (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). + In addition, if HostProcess is true then HostNetwork must also be set to true. + type: boolean + runAsUserName: + description: |- + The UserName in Windows to run the entrypoint of the container process. + Defaults to the user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: string + type: object + type: object + moverServiceAccount: + description: |- + MoverServiceAccount allows specifying the name of the service account + that will be used by the data mover. This should only be used by advanced + users who want to override the service account normally used by the mover. + The service account needs to exist in the same namespace as this CR. + type: string + rcloneConfig: + description: RcloneConfig is the rclone secret name + type: string + rcloneConfigSection: + description: RcloneConfigSection is the section in rclone_config file to use for the current job. + type: string + rcloneDestPath: + description: RcloneDestPath is the remote path to sync to. + type: string + storageClassName: + description: |- + storageClassName can be used to override the StorageClass of the PiT + image. + type: string + volumeSnapshotClassName: + description: |- + volumeSnapshotClassName can be used to specify the VSC to be used if + copyMethod is Snapshot. If not set, the default VSC is used. + type: string + type: object + restic: + description: restic defines the configuration when using Restic-based replication. + properties: + accessModes: + description: accessModes can be used to override the accessModes of the PiT image. + items: + type: string + minItems: 1 + type: array + cacheAccessModes: + description: CacheAccessModes can be used to set the accessModes of restic metadata cache volume + items: + type: string + type: array + cacheCapacity: + anyOf: + - type: integer + - type: string + description: cacheCapacity can be used to set the size of the restic metadata cache volume + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + cacheStorageClassName: + description: |- + cacheStorageClassName can be used to set the StorageClass of the restic + metadata cache volume + type: string + capacity: + anyOf: + - type: integer + - type: string + description: capacity can be used to override the capacity of the PiT image. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + copyMethod: + description: |- + copyMethod describes how a point-in-time (PiT) image of the source volume + should be created. + enum: + - Direct + - None + - Clone + - Snapshot + type: string + customCA: + description: customCA is a custom CA that will be used to verify the remote + properties: + configMapName: + description: |- + The name of a ConfigMap that contains the custom CA certificate + If ConfigMapName is used then SecretName should not be set + type: string + key: + description: The key within the Secret or ConfigMap containing the CA certificate + type: string + secretName: + description: |- + The name of a Secret that contains the custom CA certificate + If SecretName is used then ConfigMapName should not be set + type: string + type: object + moverAffinity: + description: MoverAffinity allows specifying the PodAffinity that will be used by the data mover + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + moverPodLabels: + additionalProperties: + type: string + description: |- + Labels that should be added to data mover pods + These will be in addition to any labels that VolSync may add + type: object + moverResources: + description: |- + Resources represents compute resources required by the data mover container. + Immutable. + More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ + This should only be used by advanced users as this can result in a mover + pod being unschedulable or crashing due to limited resources. + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + moverSecurityContext: + description: |- + MoverSecurityContext allows specifying the PodSecurityContext that will + be used by the data mover + properties: + appArmorProfile: + description: |- + appArmorProfile is the AppArmor options to use by the containers in this pod. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile loaded on the node that should be used. + The profile must be preconfigured on the node to work. + Must match the loaded name of the profile. + Must be set if and only if type is "Localhost". + type: string + type: + description: |- + type indicates which kind of AppArmor profile will be applied. + Valid options are: + Localhost - a profile pre-loaded on the node. + RuntimeDefault - the container runtime's default profile. + Unconfined - no AppArmor enforcement. + type: string + required: + - type + type: object + fsGroup: + description: |- + A special supplemental group that applies to all containers in a pod. + Some volume types allow the Kubelet to change the ownership of that volume + to be owned by the pod: + + 1. The owning GID will be the FSGroup + 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) + 3. The permission bits are OR'd with rw-rw---- + + If unset, the Kubelet will not modify the ownership and permissions of any volume. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + fsGroupChangePolicy: + description: |- + fsGroupChangePolicy defines behavior of changing ownership and permission of the volume + before being exposed inside Pod. This field will only apply to + volume types which support fsGroup based ownership(and permissions). + It will have no effect on ephemeral volume types such as: secret, configmaps + and emptydir. + Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. + Note that this field cannot be set when spec.os.name is windows. + type: string + runAsGroup: + description: |- + The GID to run the entrypoint of the container process. + Uses runtime default if unset. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: |- + Indicates that the container must run as a non-root user. + If true, the Kubelet will validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start the container if it does. + If unset or false, no such validation will be performed. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: |- + The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: |- + The SELinux context to be applied to all containers. + If unspecified, the container runtime will allocate a random SELinux context for each + container. May also be set in SecurityContext. If set in + both SecurityContext and PodSecurityContext, the value specified in SecurityContext + takes precedence for that container. + Note that this field cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that applies to the container. + type: string + role: + description: Role is a SELinux role label that applies to the container. + type: string + type: + description: Type is a SELinux type label that applies to the container. + type: string + user: + description: User is a SELinux user label that applies to the container. + type: string + type: object + seccompProfile: + description: |- + The seccomp options to use by the containers in this pod. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + supplementalGroups: + description: |- + A list of groups applied to the first process run in each container, in + addition to the container's primary GID and fsGroup (if specified). If + the SupplementalGroupsPolicy feature is enabled, the + supplementalGroupsPolicy field determines whether these are in addition + to or instead of any group memberships defined in the container image. + If unspecified, no additional groups are added, though group memberships + defined in the container image may still be used, depending on the + supplementalGroupsPolicy field. + Note that this field cannot be set when spec.os.name is windows. + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + description: |- + Defines how supplemental groups of the first container processes are calculated. + Valid values are "Merge" and "Strict". If not specified, "Merge" is used. + (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled + and the container runtime must implement support for this feature. + Note that this field cannot be set when spec.os.name is windows. + type: string + sysctls: + description: |- + Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported + sysctls (by the container runtime) might fail to launch. + Note that this field cannot be set when spec.os.name is windows. + items: + description: Sysctl defines a kernel parameter to be set + properties: + name: + description: Name of a property to set + type: string + value: + description: Value of a property to set + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + description: |- + The Windows specific settings applied to all containers. + If unspecified, the options within a container's SecurityContext will be used. + If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: |- + GMSACredentialSpec is where the GMSA admission webhook + (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the + GMSA credential spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of the GMSA credential spec to use. + type: string + hostProcess: + description: |- + HostProcess determines if a container should be run as a 'Host Process' container. + All of a Pod's containers must have the same effective HostProcess value + (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). + In addition, if HostProcess is true then HostNetwork must also be set to true. + type: boolean + runAsUserName: + description: |- + The UserName in Windows to run the entrypoint of the container process. + Defaults to the user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: string + type: object + type: object + moverServiceAccount: + description: |- + MoverServiceAccount allows specifying the name of the service account + that will be used by the data mover. This should only be used by advanced + users who want to override the service account normally used by the mover. + The service account needs to exist in the same namespace as this CR. + type: string + pruneIntervalDays: + description: PruneIntervalDays define how often to prune the repository + format: int32 + type: integer + repository: + description: Repository is the secret name containing repository info + type: string + retain: + description: ResticRetainPolicy define the retain policy + properties: + daily: + description: Daily defines the number of snapshots to be kept daily + format: int32 + type: integer + hourly: + description: Hourly defines the number of snapshots to be kept hourly + format: int32 + type: integer + last: + description: Last defines the number of snapshots to be kept + type: string + monthly: + description: Monthly defines the number of snapshots to be kept monthly + format: int32 + type: integer + weekly: + description: Weekly defines the number of snapshots to be kept weekly + format: int32 + type: integer + within: + description: Within defines the number of snapshots to be kept Within the given time period + type: string + yearly: + description: Yearly defines the number of snapshots to be kept yearly + format: int32 + type: integer + type: object + storageClassName: + description: |- + storageClassName can be used to override the StorageClass of the PiT + image. + type: string + unlock: + description: |- + unlock is a string value that schedules an unlock on the restic repository during + the next sync operation. + Once a sync completes then status.restic.lastUnlocked is set to the same string value. + To unlock a repository, set spec.restic.unlock to a known value and then wait for + lastUnlocked to be updated by the operator to the same value, + which means that the sync unlocked the repository by running a restic unlock command and + then ran a backup. + Unlock will not be run again unless spec.restic.unlock is set to a different value. + type: string + volumeSnapshotClassName: + description: |- + volumeSnapshotClassName can be used to specify the VSC to be used if + copyMethod is Snapshot. If not set, the default VSC is used. + type: string + type: object + rsync: + description: rsync defines the configuration when using Rsync-based replication. + properties: + accessModes: + description: accessModes can be used to override the accessModes of the PiT image. + items: + type: string + minItems: 1 + type: array + address: + description: address is the remote address to connect to for replication. + type: string + capacity: + anyOf: + - type: integer + - type: string + description: capacity can be used to override the capacity of the PiT image. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + copyMethod: + description: |- + copyMethod describes how a point-in-time (PiT) image of the source volume + should be created. + enum: + - Direct + - None + - Clone + - Snapshot + type: string + moverPodLabels: + additionalProperties: + type: string + description: |- + Labels that should be added to data mover pods + These will be in addition to any labels that VolSync may add + type: object + moverResources: + description: |- + Resources represents compute resources required by the data mover container. + Immutable. + More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ + This should only be used by advanced users as this can result in a mover + pod being unschedulable or crashing due to limited resources. + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + moverServiceAccount: + description: |- + MoverServiceAccount allows specifying the name of the service account + that will be used by the data mover. This should only be used by advanced + users who want to override the service account normally used by the mover. + The service account needs to exist in the same namespace as the ReplicationSource. + type: string + path: + description: path is the remote path to rsync to. Defaults to "/" + type: string + port: + description: port is the SSH port to connect to for replication. Defaults to 22. + format: int32 + maximum: 65535 + minimum: 0 + type: integer + serviceType: + description: |- + serviceType determines the Service type that will be created for incoming + SSH connections. + type: string + sshKeys: + description: |- + sshKeys is the name of a Secret that contains the SSH keys to be used for + authentication. If not provided, the keys will be generated. + type: string + sshUser: + description: sshUser is the username for outgoing SSH connections. Defaults to "root". + type: string + storageClassName: + description: |- + storageClassName can be used to override the StorageClass of the PiT + image. + type: string + volumeSnapshotClassName: + description: |- + volumeSnapshotClassName can be used to specify the VSC to be used if + copyMethod is Snapshot. If not set, the default VSC is used. + type: string + type: object + rsyncTLS: + description: rsyncTLS defines the configuration when using Rsync-based replication over TLS. + properties: + accessModes: + description: accessModes can be used to override the accessModes of the PiT image. + items: + type: string + minItems: 1 + type: array + address: + description: address is the remote address to connect to for replication. + type: string + capacity: + anyOf: + - type: integer + - type: string + description: capacity can be used to override the capacity of the PiT image. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + copyMethod: + description: |- + copyMethod describes how a point-in-time (PiT) image of the source volume + should be created. + enum: + - Direct + - None + - Clone + - Snapshot + type: string + keySecret: + description: |- + keySecret is the name of a Secret that contains the TLS pre-shared key to + be used for authentication. If not provided, the key will be generated. + type: string + moverAffinity: + description: MoverAffinity allows specifying the PodAffinity that will be used by the data mover + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + moverPodLabels: + additionalProperties: + type: string + description: |- + Labels that should be added to data mover pods + These will be in addition to any labels that VolSync may add + type: object + moverResources: + description: |- + Resources represents compute resources required by the data mover container. + Immutable. + More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ + This should only be used by advanced users as this can result in a mover + pod being unschedulable or crashing due to limited resources. + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + moverSecurityContext: + description: |- + MoverSecurityContext allows specifying the PodSecurityContext that will + be used by the data mover + properties: + appArmorProfile: + description: |- + appArmorProfile is the AppArmor options to use by the containers in this pod. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile loaded on the node that should be used. + The profile must be preconfigured on the node to work. + Must match the loaded name of the profile. + Must be set if and only if type is "Localhost". + type: string + type: + description: |- + type indicates which kind of AppArmor profile will be applied. + Valid options are: + Localhost - a profile pre-loaded on the node. + RuntimeDefault - the container runtime's default profile. + Unconfined - no AppArmor enforcement. + type: string + required: + - type + type: object + fsGroup: + description: |- + A special supplemental group that applies to all containers in a pod. + Some volume types allow the Kubelet to change the ownership of that volume + to be owned by the pod: + + 1. The owning GID will be the FSGroup + 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) + 3. The permission bits are OR'd with rw-rw---- + + If unset, the Kubelet will not modify the ownership and permissions of any volume. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + fsGroupChangePolicy: + description: |- + fsGroupChangePolicy defines behavior of changing ownership and permission of the volume + before being exposed inside Pod. This field will only apply to + volume types which support fsGroup based ownership(and permissions). + It will have no effect on ephemeral volume types such as: secret, configmaps + and emptydir. + Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. + Note that this field cannot be set when spec.os.name is windows. + type: string + runAsGroup: + description: |- + The GID to run the entrypoint of the container process. + Uses runtime default if unset. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: |- + Indicates that the container must run as a non-root user. + If true, the Kubelet will validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start the container if it does. + If unset or false, no such validation will be performed. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: |- + The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: |- + The SELinux context to be applied to all containers. + If unspecified, the container runtime will allocate a random SELinux context for each + container. May also be set in SecurityContext. If set in + both SecurityContext and PodSecurityContext, the value specified in SecurityContext + takes precedence for that container. + Note that this field cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that applies to the container. + type: string + role: + description: Role is a SELinux role label that applies to the container. + type: string + type: + description: Type is a SELinux type label that applies to the container. + type: string + user: + description: User is a SELinux user label that applies to the container. + type: string + type: object + seccompProfile: + description: |- + The seccomp options to use by the containers in this pod. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + supplementalGroups: + description: |- + A list of groups applied to the first process run in each container, in + addition to the container's primary GID and fsGroup (if specified). If + the SupplementalGroupsPolicy feature is enabled, the + supplementalGroupsPolicy field determines whether these are in addition + to or instead of any group memberships defined in the container image. + If unspecified, no additional groups are added, though group memberships + defined in the container image may still be used, depending on the + supplementalGroupsPolicy field. + Note that this field cannot be set when spec.os.name is windows. + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + description: |- + Defines how supplemental groups of the first container processes are calculated. + Valid values are "Merge" and "Strict". If not specified, "Merge" is used. + (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled + and the container runtime must implement support for this feature. + Note that this field cannot be set when spec.os.name is windows. + type: string + sysctls: + description: |- + Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported + sysctls (by the container runtime) might fail to launch. + Note that this field cannot be set when spec.os.name is windows. + items: + description: Sysctl defines a kernel parameter to be set + properties: + name: + description: Name of a property to set + type: string + value: + description: Value of a property to set + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + description: |- + The Windows specific settings applied to all containers. + If unspecified, the options within a container's SecurityContext will be used. + If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: |- + GMSACredentialSpec is where the GMSA admission webhook + (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the + GMSA credential spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of the GMSA credential spec to use. + type: string + hostProcess: + description: |- + HostProcess determines if a container should be run as a 'Host Process' container. + All of a Pod's containers must have the same effective HostProcess value + (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). + In addition, if HostProcess is true then HostNetwork must also be set to true. + type: boolean + runAsUserName: + description: |- + The UserName in Windows to run the entrypoint of the container process. + Defaults to the user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: string + type: object + type: object + moverServiceAccount: + description: |- + MoverServiceAccount allows specifying the name of the service account + that will be used by the data mover. This should only be used by advanced + users who want to override the service account normally used by the mover. + The service account needs to exist in the same namespace as this CR. + type: string + port: + description: port is the port to connect to for replication. Defaults to 8000. + format: int32 + maximum: 65535 + minimum: 0 + type: integer + storageClassName: + description: |- + storageClassName can be used to override the StorageClass of the PiT + image. + type: string + volumeSnapshotClassName: + description: |- + volumeSnapshotClassName can be used to specify the VSC to be used if + copyMethod is Snapshot. If not set, the default VSC is used. + type: string + type: object + sourcePVC: + description: sourcePVC is the name of the PersistentVolumeClaim (PVC) to replicate. + type: string + syncthing: + description: syncthing defines the configuration when using Syncthing-based replication. + properties: + configAccessModes: + description: Used to set the accessModes of Syncthing config volume. + items: + type: string + type: array + configCapacity: + anyOf: + - type: integer + - type: string + description: Used to set the size of the Syncthing config volume. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + configStorageClassName: + description: Used to set the StorageClass of the Syncthing config volume. + type: string + moverAffinity: + description: MoverAffinity allows specifying the PodAffinity that will be used by the data mover + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both matchLabelKeys and labelSelector. + Also, matchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + This is a beta field and requires enabling MatchLabelKeysInPodAffinity feature gate (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + moverPodLabels: + additionalProperties: + type: string + description: |- + Labels that should be added to data mover pods + These will be in addition to any labels that VolSync may add + type: object + moverResources: + description: |- + Resources represents compute resources required by the data mover container. + Immutable. + More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ + This should only be used by advanced users as this can result in a mover + pod being unschedulable or crashing due to limited resources. + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + moverSecurityContext: + description: |- + MoverSecurityContext allows specifying the PodSecurityContext that will + be used by the data mover + properties: + appArmorProfile: + description: |- + appArmorProfile is the AppArmor options to use by the containers in this pod. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile loaded on the node that should be used. + The profile must be preconfigured on the node to work. + Must match the loaded name of the profile. + Must be set if and only if type is "Localhost". + type: string + type: + description: |- + type indicates which kind of AppArmor profile will be applied. + Valid options are: + Localhost - a profile pre-loaded on the node. + RuntimeDefault - the container runtime's default profile. + Unconfined - no AppArmor enforcement. + type: string + required: + - type + type: object + fsGroup: + description: |- + A special supplemental group that applies to all containers in a pod. + Some volume types allow the Kubelet to change the ownership of that volume + to be owned by the pod: + + 1. The owning GID will be the FSGroup + 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) + 3. The permission bits are OR'd with rw-rw---- + + If unset, the Kubelet will not modify the ownership and permissions of any volume. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + fsGroupChangePolicy: + description: |- + fsGroupChangePolicy defines behavior of changing ownership and permission of the volume + before being exposed inside Pod. This field will only apply to + volume types which support fsGroup based ownership(and permissions). + It will have no effect on ephemeral volume types such as: secret, configmaps + and emptydir. + Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. + Note that this field cannot be set when spec.os.name is windows. + type: string + runAsGroup: + description: |- + The GID to run the entrypoint of the container process. + Uses runtime default if unset. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: |- + Indicates that the container must run as a non-root user. + If true, the Kubelet will validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start the container if it does. + If unset or false, no such validation will be performed. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: |- + The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: |- + The SELinux context to be applied to all containers. + If unspecified, the container runtime will allocate a random SELinux context for each + container. May also be set in SecurityContext. If set in + both SecurityContext and PodSecurityContext, the value specified in SecurityContext + takes precedence for that container. + Note that this field cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that applies to the container. + type: string + role: + description: Role is a SELinux role label that applies to the container. + type: string + type: + description: Type is a SELinux type label that applies to the container. + type: string + user: + description: User is a SELinux user label that applies to the container. + type: string + type: object + seccompProfile: + description: |- + The seccomp options to use by the containers in this pod. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + supplementalGroups: + description: |- + A list of groups applied to the first process run in each container, in + addition to the container's primary GID and fsGroup (if specified). If + the SupplementalGroupsPolicy feature is enabled, the + supplementalGroupsPolicy field determines whether these are in addition + to or instead of any group memberships defined in the container image. + If unspecified, no additional groups are added, though group memberships + defined in the container image may still be used, depending on the + supplementalGroupsPolicy field. + Note that this field cannot be set when spec.os.name is windows. + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + description: |- + Defines how supplemental groups of the first container processes are calculated. + Valid values are "Merge" and "Strict". If not specified, "Merge" is used. + (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled + and the container runtime must implement support for this feature. + Note that this field cannot be set when spec.os.name is windows. + type: string + sysctls: + description: |- + Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported + sysctls (by the container runtime) might fail to launch. + Note that this field cannot be set when spec.os.name is windows. + items: + description: Sysctl defines a kernel parameter to be set + properties: + name: + description: Name of a property to set + type: string + value: + description: Value of a property to set + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + description: |- + The Windows specific settings applied to all containers. + If unspecified, the options within a container's SecurityContext will be used. + If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: |- + GMSACredentialSpec is where the GMSA admission webhook + (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the + GMSA credential spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of the GMSA credential spec to use. + type: string + hostProcess: + description: |- + HostProcess determines if a container should be run as a 'Host Process' container. + All of a Pod's containers must have the same effective HostProcess value + (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). + In addition, if HostProcess is true then HostNetwork must also be set to true. + type: boolean + runAsUserName: + description: |- + The UserName in Windows to run the entrypoint of the container process. + Defaults to the user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: string + type: object + type: object + moverServiceAccount: + description: |- + MoverServiceAccount allows specifying the name of the service account + that will be used by the data mover. This should only be used by advanced + users who want to override the service account normally used by the mover. + The service account needs to exist in the same namespace as this CR. + type: string + peers: + description: List of Syncthing peers to be connected for syncing + items: + description: |- + SyncthingPeer Defines the necessary information needed by VolSync + to configure a given peer with the running Syncthing instance. + properties: + ID: + description: The peer's Syncthing ID. + type: string + address: + description: The peer's address that our Syncthing node will connect to. + type: string + introducer: + description: |- + A flag that determines whether this peer should + introduce us to other peers sharing this volume. + It is HIGHLY recommended that two Syncthing peers do NOT + set each other as introducers as you will have a difficult time + disconnecting the two. + type: boolean + required: + - ID + - address + - introducer + type: object + type: array + serviceType: + description: Type of service to be used when exposing the Syncthing peer + type: string + type: object + trigger: + description: |- + trigger determines when the latest state of the volume will be captured + (and potentially replicated to the destination). + properties: + manual: + description: |- + manual is a string value that schedules a manual trigger. + Once a sync completes then status.lastManualSync is set to the same string value. + A consumer of a manual trigger should set spec.trigger.manual to a known value + and then wait for lastManualSync to be updated by the operator to the same value, + which means that the manual trigger will then pause and wait for further + updates to the trigger. + type: string + schedule: + description: |- + schedule is a cronspec (https://en.wikipedia.org/wiki/Cron#Overview) that + can be used to schedule replication to occur at regular, time-based + intervals. + nolint:lll + pattern: ^(@(annually|yearly|monthly|weekly|daily|hourly))|((((\d+,)*\d+|(\d+(\/|-)\d+)|\*(\/\d+)?)\s?){5})$ + type: string + type: object + type: object + status: + description: |- + status is the observed state of the ReplicationSource as determined by + the controller. + properties: + conditions: + description: |- + conditions represent the latest available observations of the + source's state. + items: + description: Condition contains details for one aspect of the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + external: + additionalProperties: + type: string + description: |- + external contains provider-specific status information. For more details, + please see the documentation of the specific replication provider being + used. + type: object + lastManualSync: + description: lastManualSync is set to the last spec.trigger.manual when the manual sync is done. + type: string + lastSyncDuration: + description: |- + lastSyncDuration is the amount of time required to send the most recent + update. + type: string + lastSyncStartTime: + description: lastSyncStartTime is the time the most recent synchronization started. + format: date-time + type: string + lastSyncTime: + description: lastSyncTime is the time of the most recent successful synchronization. + format: date-time + type: string + latestMoverStatus: + description: Logs/Summary from latest mover job + properties: + logs: + type: string + result: + type: string + type: object + nextSyncTime: + description: |- + nextSyncTime is the time when the next volume synchronization is + scheduled to start (for schedule-based synchronization). + format: date-time + type: string + restic: + description: restic contains status information for Restic-based replication. + properties: + lastPruned: + description: lastPruned in the object holding the time of last pruned + format: date-time + type: string + lastUnlocked: + description: |- + lastUnlocked is set to the last spec.restic.unlock when a sync is done that unlocks the + restic repository. + type: string + type: object + rsync: + description: rsync contains status information for Rsync-based replication. + properties: + address: + description: |- + address is the address to connect to for incoming SSH replication + connections. + type: string + port: + description: |- + port is the SSH port to connect to for incoming SSH replication + connections. + format: int32 + type: integer + sshKeys: + description: |- + sshKeys is the name of a Secret that contains the SSH keys to be used for + authentication. If not provided in .spec.rsync.sshKeys, SSH keys will be + generated and the appropriate keys for the remote side will be placed + here. + type: string + type: object + rsyncTLS: + description: rsyncTLS contains status information for Rsync-based replication over TLS. + properties: + keySecret: + description: |- + keySecret is the name of a Secret that contains the TLS pre-shared key to + be used for authentication. If not provided in .spec.rsyncTLS.keySecret, + the key Secret will be generated and named here. + type: string + type: object + syncthing: + description: contains status information when Syncthing-based replication is used. + properties: + ID: + description: Device ID of the current syncthing device + type: string + address: + description: Service address where Syncthing is exposed to the rest of the world + type: string + peers: + description: List of the Syncthing nodes we are currently connected to. + items: + description: |- + SyncthingPeerStatus Is a struct that contains information pertaining to + the status of a given Syncthing peer. + properties: + ID: + description: ID Is the peer's Syncthing ID. + type: string + address: + description: The address of the Syncthing peer. + type: string + connected: + description: Flag indicating whether peer is currently connected. + type: boolean + introducedBy: + description: The ID of the Syncthing peer that this one was introduced by. + type: string + name: + description: A friendly name to associate the given device. + type: string + required: + - ID + - address + - connected + type: object + type: array + type: object + type: object + type: object + served: true + storage: true + subresources: + status: {} +{{- end }} diff --git a/helmcharts/stable-0.12/volsync/values.yaml b/helmcharts/stable-0.12/volsync/values.yaml new file mode 100644 index 0000000..e3a319a --- /dev/null +++ b/helmcharts/stable-0.12/volsync/values.yaml @@ -0,0 +1,89 @@ +# Default values for volsync. +replicaCount: 1 + +image: + repository: quay.io/backube/volsync + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: "" + # Directly specifies the SHA hash of the container image to deploy + image: "registry-proxy.engineering.redhat.com/rh-osbs/rhacm2-volsync-rhel8@sha256:a9b062f27b09ad8a42f7be2ee361baecc5856f66a83f7c4eb938a578b2713949" # v0.12.0-4 +rclone: + repository: quay.io/backube/volsync + # Overrides the image tag whose default is the chart appVersion. + tag: "" + image: "registry-proxy.engineering.redhat.com/rh-osbs/rhacm2-volsync-rhel8@sha256:a9b062f27b09ad8a42f7be2ee361baecc5856f66a83f7c4eb938a578b2713949" # v0.12.0-4 +restic: + repository: quay.io/backube/volsync + # Overrides the image tag whose default is the chart appVersion. + tag: "" + image: "registry-proxy.engineering.redhat.com/rh-osbs/rhacm2-volsync-rhel8@sha256:a9b062f27b09ad8a42f7be2ee361baecc5856f66a83f7c4eb938a578b2713949" # v0.12.0-4 +rsync: + repository: quay.io/backube/volsync + # Overrides the image tag whose default is the chart appVersion. + tag: "" + image: "registry-proxy.engineering.redhat.com/rh-osbs/rhacm2-volsync-rhel8@sha256:a9b062f27b09ad8a42f7be2ee361baecc5856f66a83f7c4eb938a578b2713949" # v0.12.0-4 +rsync-tls: + repository: quay.io/backube/volsync + # Overrides the image tag whose default is the chart appVersion. + tag: "" + image: "registry-proxy.engineering.redhat.com/rh-osbs/rhacm2-volsync-rhel8@sha256:a9b062f27b09ad8a42f7be2ee361baecc5856f66a83f7c4eb938a578b2713949" # v0.12.0-4 +syncthing: + repository: quay.io/backube/volsync + # Overrides the image tag whose default is the chart appVersion. + tag: "" + image: "registry-proxy.engineering.redhat.com/rh-osbs/rhacm2-volsync-rhel8@sha256:a9b062f27b09ad8a42f7be2ee361baecc5856f66a83f7c4eb938a578b2713949" # v0.12.0-4 +kube-rbac-proxy: + image: registry.redhat.io/openshift4/ose-kube-rbac-proxy:v4.15 + +manageCRDs: true + +metrics: + # Disable auth checks when scraping metrics (allow anyone to scrape) + disableAuth: false + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +service: + # Set the ip family policy to configure dual-stack see [Configure dual-stack](https://kubernetes.io/docs/concepts/services-networking/dual-stack/#services) + ipFamilyPolicy: "" + # Sets the families that should be supported and the order in which they should be applied to ClusterIP as well. Can be IPv4 and/or IPv6. + ipFamilies: [] + +podAnnotations: {} +podLabels: {} + +# Default security context values are in deployment-controller.yaml +podSecurityContext: {} + +securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + +resources: + limits: + cpu: 1000m + memory: 1Gi + requests: + cpu: 100m + memory: 64Mi + +nodeSelector: {} + +tolerations: [] + +affinity: {} diff --git a/main.go b/main.go index a6099ae..aaef036 100644 --- a/main.go +++ b/main.go @@ -17,6 +17,7 @@ import ( "github.com/openshift/library-go/pkg/controller/controllercmd" "github.com/stolostron/volsync-addon-controller/controllers" + "github.com/stolostron/volsync-addon-controller/controllers/helmutils" ) var versionFromGit = "0.0.0" @@ -32,6 +33,14 @@ func main() { command := newCommand() fmt.Printf("VolSyncAddonController version: %s\n", command.Version) + embeddedHelmChartsDir := os.Getenv("EMBEDDED_CHARTS_DIR") + // Load local embedded helm charts - will be read in as a charts object + err := helmutils.InitEmbeddedCharts(embeddedHelmChartsDir) + if err != nil { + fmt.Printf("error loading embedded chart: %s", err) + os.Exit(1) + } + if err := command.Execute(); err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) os.Exit(1) diff --git a/sonar-project.properties b/sonar-project.properties index 8bbf105..5277f65 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,7 +1,7 @@ sonar.projectKey=open-cluster-management_volsync-addon-controller sonar.projectName=volsync-addon-controller sonar.sources=. -sonar.exclusions=**/*_test.go,**/*_generated*.go,**/*_generated/**,**/vendor/** +sonar.exclusions=**/*_test.go,**/*_generated*.go,**/*_generated/**,**/vendor/**,**/helmcharts/** sonar.tests=. sonar.test.inclusions=**/*_test.go sonar.test.exclusions=**/*_generated*.go,**/*_generated/**,**/vendor/**