From 8736e01f5e6f869502e9bda43b6e9f59493248df Mon Sep 17 00:00:00 2001 From: Wesley Hayutin Date: Wed, 11 Feb 2026 13:20:20 -0700 Subject: [PATCH 1/2] DNM: add virt annotation remover webhook --- .../dataprotectionapplication_types.go | 24 +- api/v1alpha1/zz_generated.deepcopy.go | 25 + .../oadp-operator.clusterserviceversion.yaml | 16 + ...enshift.io_dataprotectionapplications.yaml | 12 + ...enshift.io_dataprotectionapplications.yaml | 5372 +++++++++-------- config/manager/manager.yaml | 2 + config/rbac/role.yaml | 12 + .../dataprotectionapplication_controller.go | 1 + .../kubevirt_annotations_remover.go | 509 ++ .../kubevirt_annotations_remover_test.go | 543 ++ internal/controller/readiness.go | 66 + 11 files changed, 4042 insertions(+), 2540 deletions(-) create mode 100644 internal/controller/kubevirt_annotations_remover.go create mode 100644 internal/controller/kubevirt_annotations_remover_test.go diff --git a/api/v1alpha1/dataprotectionapplication_types.go b/api/v1alpha1/dataprotectionapplication_types.go index 1bb4cfb14d..6c4d7b68b2 100644 --- a/api/v1alpha1/dataprotectionapplication_types.go +++ b/api/v1alpha1/dataprotectionapplication_types.go @@ -36,10 +36,11 @@ const ReconcileCompleteMessage = "Reconcile complete" // Readiness Conditions const ( - ConditionVeleroReady = "VeleroReady" - ConditionNodeAgentReady = "NodeAgentReady" - ConditionNonAdminReady = "NonAdminReady" - ConditionVMFileRestoreReady = "VMFileRestoreReady" + ConditionVeleroReady = "VeleroReady" + ConditionNodeAgentReady = "NodeAgentReady" + ConditionNonAdminReady = "NonAdminReady" + ConditionVMFileRestoreReady = "VMFileRestoreReady" + ConditionKubevirtAnnotationsRemoverReady = "KubevirtAnnotationsRemoverReady" ) // Readiness condition reasons @@ -97,6 +98,7 @@ const VMFileRestoreControllerImageKey UnsupportedImageKey = "vmFileRestoreContro const VMFileRestoreAccessImageKey UnsupportedImageKey = "vmFileRestoreAccessImageFqin" const VMFileRestoreSSHImageKey UnsupportedImageKey = "vmFileRestoreSSHImageFqin" const VMFileRestoreBrowserImageKey UnsupportedImageKey = "vmFileRestoreBrowserImageFqin" +const KubevirtAnnotationsRemoverImageKey UnsupportedImageKey = "kubevirtAnnotationsRemoverImageFqin" const OperatorTypeKey UnsupportedImageKey = "operator-type" const OperatorTypeMTC = "mtc" @@ -771,6 +773,15 @@ type VMFileRestore struct { Resources *corev1.ResourceRequirements `json:"resources,omitempty"` } +// KubevirtAnnotationsRemover defines configuration for the webhook that removes +// Velero backup hook annotations from KubeVirt virt-launcher pods +type KubevirtAnnotationsRemover struct { + // Enable flag to deploy kubevirt-velero-annotations-remover webhook. + // By default is disabled + // +optional + Enable *bool `json:"enable,omitempty"` +} + // DataMover defines the various config for DPA data mover type DataMover struct { // enable flag is used to specify whether you want to deploy the volume snapshot mover controller @@ -888,6 +899,7 @@ type DataProtectionApplicationSpec struct { // - vmFileRestoreAccessImageFqin // - vmFileRestoreSSHImageFqin // - vmFileRestoreBrowserImageFqin + // - kubevirtAnnotationsRemoverImageFqin // - operator-type // - tech-preview-ack // +optional @@ -933,6 +945,10 @@ type DataProtectionApplicationSpec struct { // vmFileRestore defines the configuration for the DPA to enable VM file restore feature // +optional VMFileRestore *VMFileRestore `json:"vmFileRestore,omitempty"` + // kubevirtAnnotationsRemover defines the configuration for the webhook that removes + // Velero backup hook annotations from KubeVirt virt-launcher pods + // +optional + KubevirtAnnotationsRemover *KubevirtAnnotationsRemover `json:"kubevirtAnnotationsRemover,omitempty"` // The format for log output. Valid values are text, json. (default text) // +kubebuilder:validation:Enum=text;json // +kubebuilder:default=text diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index ea56fc4066..1a92858d67 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -483,6 +483,11 @@ func (in *DataProtectionApplicationSpec) DeepCopyInto(out *DataProtectionApplica *out = new(VMFileRestore) (*in).DeepCopyInto(*out) } + if in.KubevirtAnnotationsRemover != nil { + in, out := &in.KubevirtAnnotationsRemover, &out.KubevirtAnnotationsRemover + *out = new(KubevirtAnnotationsRemover) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataProtectionApplicationSpec. @@ -732,6 +737,26 @@ func (in *KopiaRepoOptions) DeepCopy() *KopiaRepoOptions { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KubevirtAnnotationsRemover) DeepCopyInto(out *KubevirtAnnotationsRemover) { + *out = *in + if in.Enable != nil { + in, out := &in.Enable, &out.Enable + *out = new(bool) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubevirtAnnotationsRemover. +func (in *KubevirtAnnotationsRemover) DeepCopy() *KubevirtAnnotationsRemover { + if in == nil { + return nil + } + out := new(KubevirtAnnotationsRemover) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *LoadAffinity) DeepCopyInto(out *LoadAffinity) { *out = *in diff --git a/bundle/manifests/oadp-operator.clusterserviceversion.yaml b/bundle/manifests/oadp-operator.clusterserviceversion.yaml index b32d56e0eb..d46eac9612 100644 --- a/bundle/manifests/oadp-operator.clusterserviceversion.yaml +++ b/bundle/manifests/oadp-operator.clusterserviceversion.yaml @@ -1052,6 +1052,18 @@ spec: - patch - update - watch + - apiGroups: + - admissionregistration.k8s.io + resources: + - mutatingwebhookconfigurations + verbs: + - create + - delete + - get + - list + - patch + - update + - watch - apiGroups: - apps resources: @@ -1340,6 +1352,8 @@ spec: value: quay.io/konveyor/oadp-vmfr-access-sshd:latest - name: RELATED_IMAGE_VM_FILE_RESTORE_BROWSER value: quay.io/konveyor/oadp-vmfr-access-filebrowser:latest + - name: RELATED_IMAGE_KUBEVIRT_ANNOTATIONS_REMOVER + value: quay.io/migtools/kubevirt-velero-annotations-remover-go:latest - name: RELATED_IMAGE_CONSOLE_CLI_DOWNLOAD value: quay.io/konveyor/oadp-cli-binaries:latest image: quay.io/konveyor/oadp-operator:latest @@ -1545,6 +1559,8 @@ spec: name: vm-file-restore-ssh - image: quay.io/konveyor/oadp-vmfr-access-filebrowser:latest name: vm-file-restore-browser + - image: quay.io/migtools/kubevirt-velero-annotations-remover-go:latest + name: kubevirt-annotations-remover - image: quay.io/konveyor/oadp-cli-binaries:latest name: console-cli-download version: 99.0.0 diff --git a/bundle/manifests/oadp.openshift.io_dataprotectionapplications.yaml b/bundle/manifests/oadp.openshift.io_dataprotectionapplications.yaml index 71543936d2..6d1839c20f 100644 --- a/bundle/manifests/oadp.openshift.io_dataprotectionapplications.yaml +++ b/bundle/manifests/oadp.openshift.io_dataprotectionapplications.yaml @@ -1615,6 +1615,17 @@ spec: - IfNotPresent - Never type: string + kubevirtAnnotationsRemover: + description: |- + kubevirtAnnotationsRemover defines the configuration for the webhook that removes + Velero backup hook annotations from KubeVirt virt-launcher pods + properties: + enable: + description: |- + Enable flag to deploy kubevirt-velero-annotations-remover webhook. + By default is disabled + type: boolean + type: object logFormat: default: text description: The format for log output. Valid values are text, json. (default text) @@ -2698,6 +2709,7 @@ spec: - vmFileRestoreAccessImageFqin - vmFileRestoreSSHImageFqin - vmFileRestoreBrowserImageFqin + - kubevirtAnnotationsRemoverImageFqin - operator-type - tech-preview-ack type: object diff --git a/config/crd/bases/oadp.openshift.io_dataprotectionapplications.yaml b/config/crd/bases/oadp.openshift.io_dataprotectionapplications.yaml index c73015eac6..d0358cf5b5 100644 --- a/config/crd/bases/oadp.openshift.io_dataprotectionapplications.yaml +++ b/config/crd/bases/oadp.openshift.io_dataprotectionapplications.yaml @@ -12,653 +12,369 @@ spec: listKind: DataProtectionApplicationList plural: dataprotectionapplications shortNames: - - dpa + - dpa singular: dataprotectionapplication scope: Namespaced versions: - - additionalPrinterColumns: - - description: DataProtectionApplication Reconciled Status - jsonPath: .status.conditions[?(@.type=='Reconciled')].status - name: Reconciled - type: string - - description: DataProtectionApplication creation timestamp - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: |- - DataProtectionApplication represents configuration to install a data protection - application to safely backup and restore, perform disaster recovery and migrate - Kubernetes cluster resources and persistent volumes. - 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: DataProtectionApplicationSpec defines the desired state of Velero - properties: - backupImages: - description: backupImages is used to specify whether you want to deploy a registry for enabling backup and restore of images - type: boolean - backupLocations: - description: backupLocations defines the list of desired configuration to use for BackupStorageLocations - items: - description: BackupLocation defines the configuration for the DPA backup storage - properties: - bucket: - description: CloudStorageLocation defines BackupStorageLocation using bucket referenced by CloudStorage CR. - properties: - backupSyncPeriod: - description: backupSyncPeriod defines how frequently to sync backup API objects from object storage. A value of 0 disables sync. - nullable: true - type: string - caCert: - description: CACert defines a CA bundle to use when verifying TLS connections to the provider. - format: byte - type: string - cloudStorageRef: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - config: - additionalProperties: - type: string - description: config is for provider-specific configuration fields. - type: object - credential: - description: credential contains the credential information intended to be used with this location - properties: - key: - description: The key of the secret to select from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - default: - description: default indicates this location is the default backup storage location. - type: boolean - prefix: - description: Prefix is the path inside a bucket to use for Velero storage. Optional. - type: string - required: - - cloudStorageRef - type: object - name: - type: string - velero: - description: BackupStorageLocationSpec defines the desired state of a Velero BackupStorageLocation - properties: - accessMode: - description: AccessMode defines the permissions for the backup storage location. - enum: - - ReadOnly - - ReadWrite - type: string - backupSyncPeriod: - description: BackupSyncPeriod defines how frequently to sync backup API objects from object storage. A value of 0 disables sync. - nullable: true - type: string - config: - additionalProperties: - type: string - description: Config is for provider-specific configuration fields. - type: object - credential: - description: Credential contains the credential information intended to be used with this location - properties: - key: - description: The key of the secret to select from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - default: - description: Default indicates this location is the default backup storage location. - type: boolean - objectStorage: - description: ObjectStorageLocation specifies the settings necessary to connect to a provider's object storage. - properties: - bucket: - description: Bucket is the bucket to use for object storage. - type: string - caCert: - description: CACert defines a CA bundle to use when verifying TLS connections to the provider. - format: byte - type: string - prefix: - description: Prefix is the path inside a bucket to use for Velero storage. Optional. - type: string - required: - - bucket - type: object - provider: - description: Provider is the provider of the backup storage. - type: string - validationFrequency: - description: ValidationFrequency defines how frequently to validate the corresponding object storage. A value of 0 disables validation. - nullable: true - type: string - required: - - objectStorage - - provider - type: object - type: object - type: array - configuration: - description: configuration is used to configure the data protection application's server config + - additionalPrinterColumns: + - description: DataProtectionApplication Reconciled Status + jsonPath: .status.conditions[?(@.type=='Reconciled')].status + name: Reconciled + type: string + - description: DataProtectionApplication creation timestamp + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + DataProtectionApplication represents configuration to install a data protection + application to safely backup and restore, perform disaster recovery and migrate + Kubernetes cluster resources and persistent volumes. + 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: DataProtectionApplicationSpec defines the desired state of + Velero + properties: + backupImages: + description: backupImages is used to specify whether you want to deploy + a registry for enabling backup and restore of images + type: boolean + backupLocations: + description: backupLocations defines the list of desired configuration + to use for BackupStorageLocations + items: + description: BackupLocation defines the configuration for the DPA + backup storage properties: - nodeAgent: - description: NodeAgent is needed to allow selection between kopia or restic + bucket: + description: CloudStorageLocation defines BackupStorageLocation + using bucket referenced by CloudStorage CR. properties: - backupPVC: - additionalProperties: - properties: - annotations: - additionalProperties: - type: string - description: Annotations permits setting annotations for the backupPVC - type: object - readOnly: - description: ReadOnly sets the backupPVC's access mode as read only - type: boolean - spcNoRelabeling: - description: |- - SPCNoRelabeling sets Spec.SecurityContext.SELinux.Type to "spc_t" for the pod mounting the backupPVC - ignored if ReadOnly is false - type: boolean - storageClass: - description: StorageClass is the name of storage class to be used by the backupPVC - type: string - type: object - description: BackupPVCConfig is the config for backupPVC (intermediate PVC) of snapshot data movement - type: object - cacheLimitMB: - description: CacheLimitMB specifies the size limit(in MB) for the local data cache - format: int64 - minimum: 0 - type: integer - dataMoverPrepareTimeout: - description: How long to wait for preparing a DataUpload/DataDownload. Default is 30 minutes. + backupSyncPeriod: + description: backupSyncPeriod defines how frequently to + sync backup API objects from object storage. A value of + 0 disables sync. + nullable: true type: string - enable: + caCert: + description: CACert defines a CA bundle to use when verifying + TLS connections to the provider. + format: byte + type: string + cloudStorageRef: description: |- - enable defines a boolean pointer whether we want the daemonset to - exist or not + LocalObjectReference contains enough information to let you locate the + referenced object inside the same namespace. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + config: + additionalProperties: + type: string + description: config is for provider-specific configuration + fields. + type: object + credential: + description: credential contains the credential information + intended to be used with this location + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + default: + description: default indicates this location is the default + backup storage location. type: boolean - fullMaintenanceInterval: - description: |- - fullMaintenanceInterval determines the time between kopia full maintenance operations. - normalGC: 24 hours - fastGC: 12 hours - eagerGC: 6 hours + prefix: + description: Prefix is the path inside a bucket to use for + Velero storage. Optional. + type: string + required: + - cloudStorageRef + type: object + name: + type: string + velero: + description: BackupStorageLocationSpec defines the desired state + of a Velero BackupStorageLocation + properties: + accessMode: + description: AccessMode defines the permissions for the + backup storage location. enum: - - normalGC - - fastGC - - eagerGC + - ReadOnly + - ReadWrite type: string - loadAffinity: - description: LoadAffinity is the config for data path load affinity. - items: - description: |- - LoadAffinity is the config for data path load affinity. - Used by the Node-Agent, that needs to match the DataMover and the RepositoryMaintenance pods. - properties: - nodeSelector: - description: NodeSelector specifies the label selector to match nodes - 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 - type: object - type: array - loadConcurrency: - description: LoadConcurrency is the config for data path load concurrency per node. + backupSyncPeriod: + description: BackupSyncPeriod defines how frequently to + sync backup API objects from object storage. A value of + 0 disables sync. + nullable: true + type: string + config: + additionalProperties: + type: string + description: Config is for provider-specific configuration + fields. + type: object + credential: + description: Credential contains the credential information + intended to be used with this location properties: - globalConfig: - description: GlobalConfig specifies the concurrency number to all nodes for which per-node config is not specified - type: integer - perNodeConfig: - description: PerNodeConfig specifies the concurrency number to nodes matched by rules - items: - description: RuledConfigs is the config for data path load concurrency per node. - properties: - nodeSelector: - description: NodeSelector specifies the label selector to match nodes - 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 - number: - description: Number specifies the number value associated to the matched nodes - type: integer - required: - - nodeSelector - - number - type: object - type: array - prepareQueueLength: - description: PrepareQueueLength specifies the max number of loads that are under expose - type: integer + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + default: + description: Default indicates this location is the default + backup storage location. + type: boolean + objectStorage: + description: ObjectStorageLocation specifies the settings + necessary to connect to a provider's object storage. + properties: + bucket: + description: Bucket is the bucket to use for object + storage. + type: string + caCert: + description: CACert defines a CA bundle to use when + verifying TLS connections to the provider. + format: byte + type: string + prefix: + description: Prefix is the path inside a bucket to use + for Velero storage. Optional. + type: string + required: + - bucket type: object - podConfig: - description: Pod specific configuration + provider: + description: Provider is the provider of the backup storage. + type: string + validationFrequency: + description: ValidationFrequency defines how frequently + to validate the corresponding object storage. A value + of 0 disables validation. + nullable: true + type: string + required: + - objectStorage + - provider + type: object + type: object + type: array + configuration: + description: configuration is used to configure the data protection + application's server config + properties: + nodeAgent: + description: NodeAgent is needed to allow selection between kopia + or restic + properties: + backupPVC: + additionalProperties: properties: annotations: additionalProperties: type: string - description: annotations to add to pods + description: Annotations permits setting annotations + for the backupPVC type: object - env: - description: env defines the list of environment variables to be supplied to podSpec - items: - description: EnvVar represents an environment variable present in a Container. - properties: - name: - description: Name of the environment variable. Must be a C_IDENTIFIER. - type: string - value: + readOnly: + description: ReadOnly sets the backupPVC's access mode + as read only + type: boolean + spcNoRelabeling: + description: |- + SPCNoRelabeling sets Spec.SecurityContext.SELinux.Type to "spc_t" for the pod mounting the backupPVC + ignored if ReadOnly is false + type: boolean + storageClass: + description: StorageClass is the name of storage class + to be used by the backupPVC + type: string + type: object + description: BackupPVCConfig is the config for backupPVC (intermediate + PVC) of snapshot data movement + type: object + cacheLimitMB: + description: CacheLimitMB specifies the size limit(in MB) + for the local data cache + format: int64 + minimum: 0 + type: integer + dataMoverPrepareTimeout: + description: How long to wait for preparing a DataUpload/DataDownload. + Default is 30 minutes. + type: string + enable: + description: |- + enable defines a boolean pointer whether we want the daemonset to + exist or not + type: boolean + fullMaintenanceInterval: + description: |- + fullMaintenanceInterval determines the time between kopia full maintenance operations. + normalGC: 24 hours + fastGC: 12 hours + eagerGC: 6 hours + enum: + - normalGC + - fastGC + - eagerGC + type: string + loadAffinity: + description: LoadAffinity is the config for data path load + affinity. + items: + description: |- + LoadAffinity is the config for data path load affinity. + Used by the Node-Agent, that needs to match the DataMover and the RepositoryMaintenance pods. + properties: + nodeSelector: + description: NodeSelector specifies the label selector + to match nodes + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are ANDed. + items: description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". - type: string - valueFrom: - description: Source for the environment variable's value. Cannot be used if value is not empty. + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: - configMapKeyRef: - description: Selects a key of a ConfigMap. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - fieldRef: + key: + description: key is the label key that the + selector applies to. + type: string + operator: description: |- - Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, - spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. - properties: - apiVersion: - description: Version of the schema the FieldPath is written in terms of, defaults to "v1". - type: string - fieldPath: - description: Path of the field to select in the specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. - properties: - containerName: - description: 'Container name: required for volumes, optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format of the exposed resources, defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret in the pod's namespace - properties: - key: - description: The key of the secret to select from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - required: - - name - type: object - type: array - labels: - additionalProperties: - type: string - description: labels to add to pods - type: object - nodeSelector: - additionalProperties: - type: string - description: nodeSelector defines the nodeSelector to be supplied to podSpec - type: object - resourceAllocations: - description: resourceAllocations defines the CPU, Memory and ephemeral-storage resource allocations for the Pod - nullable: true - 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. + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string - request: + values: 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 + 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: - - name + - key + - operator type: object type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: + x-kubernetes-list-type: atomic + matchLabels: 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 + type: string 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/ + 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 - tolerations: - description: tolerations defines the list of tolerations to be applied to daemonset - items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - format: int64 - type: integer - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - type: object - type: array - type: object - podResources: - description: PodResources is the resource config for various types of pods launched by node-agent, i.e., data mover pods. - properties: - cpuLimit: - type: string - cpuRequest: - type: string - memoryLimit: - type: string - memoryRequest: - type: string - type: object - resourceTimeout: - description: How long to wait for resource processes which are not covered by other specific timeout parameters. Default is 10 minutes. - type: string - restorePVC: - description: RestoreVCConfig is the config for restorePVC (intermediate PVC) of generic restore - properties: - ignoreDelayBinding: - description: IgnoreDelayBinding indicates to ignore delay binding the restorePVC when it is in WaitForFirstConsumer mode - type: boolean + x-kubernetes-map-type: atomic type: object - supplementalGroups: - description: supplementalGroups defines the linux groups to be applied to the NodeAgent Pod - items: - format: int64 - type: integer - type: array - timeout: - description: timeout defines the NodeAgent timeout, default value is 1h - type: string - uploaderType: - description: The type of uploader to transfer the data of pod volumes, the supported values are 'restic' or 'kopia' - enum: - - restic - - kopia - type: string - required: - - uploaderType - type: object - repositoryMaintenance: - additionalProperties: + type: array + loadConcurrency: + description: LoadConcurrency is the config for data path load + concurrency per node. properties: - loadAffinity: - description: LoadAffinity is the config for data path load affinity. + globalConfig: + description: GlobalConfig specifies the concurrency number + to all nodes for which per-node config is not specified + type: integer + perNodeConfig: + description: PerNodeConfig specifies the concurrency number + to nodes matched by rules items: - description: |- - LoadAffinity is the config for data path load affinity. - Used by the Node-Agent, that needs to match the DataMover and the RepositoryMaintenance pods. + description: RuledConfigs is the config for data path + load concurrency per node. properties: nodeSelector: - description: NodeSelector specifies the label selector to match nodes + description: NodeSelector specifies the label selector + to match nodes properties: matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + 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. + description: key is the label key that + the selector applies to. type: string operator: description: |- @@ -676,8 +392,8 @@ spec: type: array x-kubernetes-list-type: atomic required: - - key - - operator + - key + - operator type: object type: array x-kubernetes-list-type: atomic @@ -691,514 +407,340 @@ spec: type: object type: object x-kubernetes-map-type: atomic + number: + description: Number specifies the number value associated + to the matched nodes + type: integer + required: + - nodeSelector + - number type: object type: array - podResources: - description: PodResources is the config for the CPU and memory resources setting. - properties: - cpuLimit: - type: string - cpuRequest: - type: string - memoryLimit: - type: string - memoryRequest: - type: string - type: object + prepareQueueLength: + description: PrepareQueueLength specifies the max number + of loads that are under expose + type: integer type: object - description: |- - RepositoryMaintenance maps a BackupRepository identifier to its configuration. - Keys can be: - - "global" : Applies to all repositories without specific config. - - "" : The namespace of the BackupRepository. - - "" : The specific BackupRepository name referencing the BSL. - - "" : Either "kopia" or "restic". - type: object - restic: - description: |- - (do not use warning) restic field is for backwards compatibility and - will be removed in the future. Use nodeAgent field instead - properties: - enable: - description: |- - enable defines a boolean pointer whether we want the daemonset to - exist or not - type: boolean - podConfig: - description: Pod specific configuration - properties: - annotations: - additionalProperties: - type: string - description: annotations to add to pods + podConfig: + description: Pod specific configuration + properties: + annotations: + additionalProperties: + type: string + description: annotations to add to pods + type: object + env: + description: env defines the list of environment variables + to be supplied to podSpec + items: + description: EnvVar represents an environment variable + present in a Container. + properties: + name: + description: Name of the environment variable. Must + be a C_IDENTIFIER. + type: string + value: + description: |- + Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in the container and + any service environment variables. If a variable cannot be resolved, + the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless of whether the variable + exists or not. + Defaults to "". + type: string + valueFrom: + description: Source for the environment variable's + value. Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: |- + Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select + in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + properties: + containerName: + description: 'Container name: required for + volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format + of the exposed resources, defaults to + "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the + pod's namespace + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name type: object - env: - description: env defines the list of environment variables to be supplied to podSpec - items: - description: EnvVar represents an environment variable present in a Container. - properties: - name: - description: Name of the environment variable. Must be a C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". - type: string - valueFrom: - description: Source for the environment variable's value. Cannot be used if value is not empty. - properties: - configMapKeyRef: - description: Selects a key of a ConfigMap. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - fieldRef: - description: |- - Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, - spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. - properties: - apiVersion: - description: Version of the schema the FieldPath is written in terms of, defaults to "v1". - type: string - fieldPath: - description: Path of the field to select in the specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. - properties: - containerName: - description: 'Container name: required for volumes, optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format of the exposed resources, defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret in the pod's namespace - properties: - key: - description: The key of the secret to select from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - required: + type: array + labels: + additionalProperties: + type: string + description: labels to add to pods + type: object + nodeSelector: + additionalProperties: + type: string + description: nodeSelector defines the nodeSelector to + be supplied to podSpec + type: object + resourceAllocations: + description: resourceAllocations defines the CPU, Memory + and ephemeral-storage resource allocations for the Pod + nullable: true + 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 - type: array - labels: - additionalProperties: - type: string - description: labels to add to pods - type: object - nodeSelector: - additionalProperties: - type: string - description: nodeSelector defines the nodeSelector to be supplied to podSpec - type: object - resourceAllocations: - description: resourceAllocations defines the CPU, Memory and ephemeral-storage resource allocations for the Pod - nullable: true + 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 + tolerations: + description: tolerations defines the list of tolerations + to be applied to daemonset + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . properties: - claims: + effect: 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 - nullable: true + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - nullable: true - 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 - nullable: true + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: 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 - nullable: true + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string type: object - tolerations: - description: tolerations defines the list of tolerations to be applied to daemonset - items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - format: int64 - type: integer - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - type: object - type: array - type: object - supplementalGroups: - description: supplementalGroups defines the linux groups to be applied to the NodeAgent Pod - items: - format: int64 - type: integer - type: array - timeout: - description: timeout defines the NodeAgent timeout, default value is 1h - type: string - type: object - velero: - properties: - args: - description: Velero args are settings to customize velero server arguments. Overrides values in other fields. - properties: - add_dir_header: - description: If true, adds the file directory to the header of the log messages - type: boolean - alsologtostderr: - description: log to standard error as well as files (no effect when -logtostderr=true) - type: boolean - backup-sync-period: - description: How often (in nanoseconds) to ensure all Velero backups in object storage exist as Backup API objects in the cluster. This is the default sync period if none is explicitly specified for a backup storage location. - format: int64 - type: integer - client-burst: - description: Maximum number of requests by the server to the Kubernetes API in a short period of time. - type: integer - client-page-size: - description: Page size of requests by the server to the Kubernetes API when listing objects during a backup. Set to 0 to disable paging. - type: integer - client-qps: - description: |- - Maximum number of requests per second by the server to the Kubernetes API once the burst limit has been reached. - this will be validated as a valid float32 - type: string - colorized: - description: Show colored output in TTY - type: boolean - default-backup-ttl: - description: How long (in nanoseconds) to wait by default before backups can be garbage collected. (default is 720 hours) - format: int64 - type: integer - default-item-operation-timeout: - description: How long (in nanoseconds) to wait on asynchronous BackupItemActions and RestoreItemActions to complete before timing out. (default is 1 hour) - format: int64 - type: integer - default-repo-maintain-frequency: - description: How often (in nanoseconds) 'maintain' is run for backup repositories by default. - format: int64 - type: integer - default-volumes-to-fs-backup: - description: Backup all volumes with pod volume file system backup by default. - type: boolean - disabled-controllers: - description: List of controllers to disable on startup. Valid values are backup,backup-operations,backup-deletion,backup-finalizer,backup-sync,download-request,gc,backup-repo,restore,restore-operations,schedule,server-status-request - enum: - - backup - - backup-operations - - backup-deletion - - backup-finalizer - - backup-sync - - download-request - - gc - - backup-repo - - restore - - restore-operations - - schedule - - server-status-request - items: - type: string - type: array - fs-backup-timeout: - description: How long (in nanoseconds) pod volume file system backups/restores should be allowed to run before timing out. (default is 4 hours) - format: int64 - type: integer - garbage-collection-frequency: - description: How often (in nanoseconds) garbage collection checks for expired backups. (default is 1 hour) - format: int64 - type: integer - item-operation-sync-frequency: - description: How often (in nanoseconds) to check status on backup/restore operations after backup/restore processing. - format: int64 - type: integer - log-format: - description: The format for log output. Valid values are text, json. (default text) - enum: - - text - - json - type: string - log_backtrace_at: - description: when logging hits line file:N, emit a stack trace - type: string - log_dir: - description: If non-empty, write log files in this directory (no effect when -logtostderr=true) - type: string - log_file: - description: If non-empty, use this log file (no effect when -logtostderr=true) - type: string - log_file_max_size: - description: Defines the maximum size a log file can grow to (no effect when -logtostderr=true). Unit is megabytes. If the value is 0, the maximum file size is unlimited. (default 1800) - format: int64 - minimum: 0 - type: integer - logtostderr: - description: |- - Boolean flags. Not handled atomically because the flag.Value interface - does not let us avoid the =true, and that shorthand is necessary for - compatibility. TODO: does this matter enough to fix? Seems unlikely. - type: boolean - max-concurrent-k8s-connections: - description: Max concurrent connections number that Velero can create with kube-apiserver. Default is 30. (default 30) - type: integer - metrics-address: - description: The address to expose prometheus metrics - type: string - one_output: - description: If true, only write logs to their native severity level (vs also writing to each lower severity level; no effect when -logtostderr=true) - type: boolean - profiler-address: - description: The address to expose the pprof profiler. - type: string - resource-timeout: - description: How long (in nanoseconds) to wait for resource processes which are not covered by other specific timeout parameters. (default is 10 minutes) - format: int64 - type: integer - restore-resource-priorities: - description: Desired order of resource restores, the priority list contains two parts which are split by "-" element. The resources before "-" element are restored first as high priorities, the resources after "-" element are restored last as low priorities, and any resource not in the list will be restored alphabetically between the high and low priorities. (default securitycontextconstraints,customresourcedefinitions,klusterletconfigs.config.open-cluster-management.io,managedcluster.cluster.open-cluster-management.io,namespaces,roles,rolebindings,clusterrolebindings,klusterletaddonconfig.agent.open-cluster-management.io,managedclusteraddon.addon.open-cluster-management.io,storageclasses,volumesnapshotclass.snapshot.storage.k8s.io,volumesnapshotcontents.snapshot.storage.k8s.io,volumesnapshots.snapshot.storage.k8s.io,datauploads.velero.io,persistentvolumes,persistentvolumeclaims,serviceaccounts,secrets,configmaps,limitranges,pods,replicasets.apps,clusterclasses.cluster.x-k8s.io,endpoints,services,-,clusterbootstraps.run.tanzu.vmware.com,clusters.cluster.x-k8s.io,clusterresourcesets.addons.cluster.x-k8s.io) - type: string - skip_headers: - description: If true, avoid header prefixes in the log messages - type: boolean - skip_log_headers: - description: If true, avoid headers when opening log files (no effect when -logtostderr=true) - type: boolean - stderrthreshold: - description: logs at or above this threshold go to stderr when writing to files and stderr (no effect when -logtostderr=true or -alsologtostderr=false) (default 2) - type: integer - store-validation-frequency: - description: How often (in nanoseconds) to verify if the storage is valid. Optional. Set this to `0` to disable sync. (default is 1 minute) - format: int64 - type: integer - terminating-resource-timeout: - description: How long (in nanoseconds) to wait on persistent volumes and namespaces to terminate during a restore before timing out. - format: int64 - type: integer - v: - description: number for the log level verbosity - type: integer - vmodule: - description: comma-separated list of pattern=N settings for file-filtered logging - type: string - type: object - client-burst: - description: maximum number of requests by the server to the Kubernetes API in a short period of time. (default 100) - type: integer - client-qps: - description: maximum number of requests per second by the server to the Kubernetes API once the burst limit has been reached. (default 100) - type: integer - concurrentBackups: - description: |- - Number of backups to process at the same time. Only backups which do not have any namespaces - in common will run at the same time. Default is 1. - type: integer - customPlugins: - description: customPlugins defines the custom plugin to be installed with Velero - items: - properties: - image: - type: string - name: - type: string - required: - - image - - name - type: object - type: array - defaultItemOperationTimeout: - description: How long to wait on asynchronous BackupItemActions and RestoreItemActions to complete before timing out. Default value is 1h. - type: string - defaultPlugins: - items: - enum: - - aws - - legacy-aws - - gcp - - azure - - csi - - vsm - - openshift - - kubevirt - - kubevirt-datamover - - hypershift + type: array + type: object + podResources: + description: PodResources is the resource config for various + types of pods launched by node-agent, i.e., data mover pods. + properties: + cpuLimit: type: string - type: array - defaultSnapshotMoveData: - description: Specify whether CSI snapshot data should be moved to backup storage by default - type: boolean - defaultVolumesToFSBackup: - description: Use pod volume file system backup by default for volumes - type: boolean - disableFsBackup: - default: false - description: |- - DisableFsBackup determines whether the NodeAgent should disable file system backup. - When set to true, the NodeAgent runs in non-privileged mode. - Defaults to false. - type: boolean - disableInformerCache: - description: Disable informer cache for Get calls on restore. With this enabled, it will speed up restore in cases where there are backup resources which already exist in the cluster, but for very large clusters this will increase velero memory usage. Default is false. - type: boolean - featureFlags: - description: featureFlags defines the list of features to enable for Velero instance - items: + cpuRequest: type: string - type: array - itemBlockWorkerCount: - description: |- - Number of workers in worker pool for processing item backup. This will allow multiple items within - a Velero backup to be backed up at the same time which may improve performance for backups with - a large number of items. Workers are per backup if concurrent backups are enabled. Default is 1. + memoryLimit: + type: string + memoryRequest: + type: string + type: object + resourceTimeout: + description: How long to wait for resource processes which + are not covered by other specific timeout parameters. Default + is 10 minutes. + type: string + restorePVC: + description: RestoreVCConfig is the config for restorePVC + (intermediate PVC) of generic restore + properties: + ignoreDelayBinding: + description: IgnoreDelayBinding indicates to ignore delay + binding the restorePVC when it is in WaitForFirstConsumer + mode + type: boolean + type: object + supplementalGroups: + description: supplementalGroups defines the linux groups to + be applied to the NodeAgent Pod + items: + format: int64 type: integer - itemOperationSyncFrequency: - description: How often to check status on async backup/restore operations after backup processing. Default value is 2m. - type: string + type: array + timeout: + description: timeout defines the NodeAgent timeout, default + value is 1h + type: string + uploaderType: + description: The type of uploader to transfer the data of + pod volumes, the supported values are 'restic' or 'kopia' + enum: + - restic + - kopia + type: string + required: + - uploaderType + type: object + repositoryMaintenance: + additionalProperties: + properties: loadAffinity: - description: LoadAffinityConfig is the config for data path load affinity. + description: LoadAffinity is the config for data path load + affinity. items: description: |- LoadAffinity is the config for data path load affinity. Used by the Node-Agent, that needs to match the DataMover and the RepositoryMaintenance pods. properties: nodeSelector: - description: NodeSelector specifies the label selector to match nodes + description: NodeSelector specifies the label selector + to match nodes properties: matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + 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. + description: key is the label key that the + selector applies to. type: string operator: description: |- @@ -1216,8 +758,8 @@ spec: type: array x-kubernetes-list-type: atomic required: - - key - - operator + - key + - operator type: object type: array x-kubernetes-list-type: atomic @@ -1233,767 +775,1534 @@ spec: x-kubernetes-map-type: atomic type: object type: array - logLevel: - description: Velero server's log level (use debug for the most logging, leave unset for velero default) - enum: - - trace - - debug - - info - - warning - - error - - fatal - - panic - type: string - noDefaultBackupLocation: - description: If you need to install Velero without a default backup storage location noDefaultBackupLocation flag is required for confirmation - type: boolean - podConfig: - description: Pod specific configuration + podResources: + description: PodResources is the config for the CPU and + memory resources setting. properties: - annotations: - additionalProperties: - type: string - description: annotations to add to pods + cpuLimit: + type: string + cpuRequest: + type: string + memoryLimit: + type: string + memoryRequest: + type: string + type: object + type: object + description: |- + RepositoryMaintenance maps a BackupRepository identifier to its configuration. + Keys can be: + - "global" : Applies to all repositories without specific config. + - "" : The namespace of the BackupRepository. + - "" : The specific BackupRepository name referencing the BSL. + - "" : Either "kopia" or "restic". + type: object + restic: + description: |- + (do not use warning) restic field is for backwards compatibility and + will be removed in the future. Use nodeAgent field instead + properties: + enable: + description: |- + enable defines a boolean pointer whether we want the daemonset to + exist or not + type: boolean + podConfig: + description: Pod specific configuration + properties: + annotations: + additionalProperties: + type: string + description: annotations to add to pods + type: object + env: + description: env defines the list of environment variables + to be supplied to podSpec + items: + description: EnvVar represents an environment variable + present in a Container. + properties: + name: + description: Name of the environment variable. Must + be a C_IDENTIFIER. + type: string + value: + description: |- + Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in the container and + any service environment variables. If a variable cannot be resolved, + the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless of whether the variable + exists or not. + Defaults to "". + type: string + valueFrom: + description: Source for the environment variable's + value. Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: |- + Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select + in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + properties: + containerName: + description: 'Container name: required for + volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format + of the exposed resources, defaults to + "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the + pod's namespace + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name type: object - env: - description: env defines the list of environment variables to be supplied to podSpec - items: - description: EnvVar represents an environment variable present in a Container. - properties: - name: - description: Name of the environment variable. Must be a C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". - type: string - valueFrom: - description: Source for the environment variable's value. Cannot be used if value is not empty. - properties: - configMapKeyRef: - description: Selects a key of a ConfigMap. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - fieldRef: - description: |- - Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, - spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. - properties: - apiVersion: - description: Version of the schema the FieldPath is written in terms of, defaults to "v1". - type: string - fieldPath: - description: Path of the field to select in the specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. - properties: - containerName: - description: 'Container name: required for volumes, optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format of the exposed resources, defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret in the pod's namespace - properties: - key: - description: The key of the secret to select from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - required: + type: array + labels: + additionalProperties: + type: string + description: labels to add to pods + type: object + nodeSelector: + additionalProperties: + type: string + description: nodeSelector defines the nodeSelector to + be supplied to podSpec + type: object + resourceAllocations: + description: resourceAllocations defines the CPU, Memory + and ephemeral-storage resource allocations for the Pod + nullable: true + 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 - type: array - labels: - additionalProperties: - type: string - description: labels to add to pods - type: object - nodeSelector: - additionalProperties: - type: string - description: nodeSelector defines the nodeSelector to be supplied to podSpec - type: object - resourceAllocations: - description: resourceAllocations defines the CPU, Memory and ephemeral-storage resource allocations for the Pod - nullable: true + 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 + tolerations: + description: tolerations defines the list of tolerations + to be applied to daemonset + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . properties: - claims: + effect: 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 - nullable: true + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - nullable: true - 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 - nullable: true + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: 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 - nullable: true + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string type: object - tolerations: - description: tolerations defines the list of tolerations to be applied to daemonset - items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - format: int64 - type: integer - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - type: object - type: array - type: object - resourceTimeout: - description: |- - resourceTimeout defines how long to wait for several Velero resources before timeout occurs, - such as Velero CRD availability, volumeSnapshot deletion, and repo availability. - Default is 10m - type: string - restoreResourcesVersionPriority: - description: |- - restoreResourceVersionPriority represents a configmap that will be created if defined for use in conjunction with EnableAPIGroupVersions feature flag - Defining this field automatically add EnableAPIGroupVersions to the velero server feature flag - type: string - type: object - type: object - features: - description: features defines the configuration for the DPA to enable the OADP tech preview features - properties: - dataMover: - description: |- - (do not use warning) dataMover is for backwards compatibility and - will be removed in the future. Use Velero Built-in Data Mover instead - properties: - credentialName: - description: User supplied Restic Secret name - type: string - enable: - description: enable flag is used to specify whether you want to deploy the volume snapshot mover controller - type: boolean - maxConcurrentBackupVolumes: - description: the number of batched volumeSnapshotBackups that can be inProgress at once, default value is 10 - type: string - maxConcurrentRestoreVolumes: - description: the number of batched volumeSnapshotRestores that can be inProgress at once, default value is 10 - type: string - pruneInterval: - description: defines how often (in days) to prune the datamover snapshots from the repository - type: string - schedule: - description: |- - schedule is a cronspec (https://en.wikipedia.org/wiki/Cron#Overview) that - can be used to schedule datamover(volsync) synchronization to occur at regular, time-based - intervals. For example, in order to enforce datamover SnapshotRetainPolicy at a regular interval you need to - specify this Schedule trigger as a cron expression, by default the trigger is a manual trigger. For more details - on Volsync triggers, refer: https://volsync.readthedocs.io/en/stable/usage/triggers.html - pattern: ^(\d+|\*)(/\d+)?(\s+(\d+|\*)(/\d+)?){4}$ - type: string - snapshotRetainPolicy: - description: defines the parameters that can be specified for retention of datamover snapshots - properties: - daily: - description: Daily defines the number of snapshots to be kept daily - type: string - hourly: - description: Hourly defines the number of snapshots to be kept hourly - type: string - monthly: - description: Monthly defines the number of snapshots to be kept monthly - type: string - weekly: - description: Weekly defines the number of snapshots to be kept weekly - type: string - 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 + type: array + type: object + supplementalGroups: + description: supplementalGroups defines the linux groups to + be applied to the NodeAgent Pod + items: + format: int64 + type: integer + type: array + timeout: + description: timeout defines the NodeAgent timeout, default + value is 1h + type: string + type: object + velero: + properties: + args: + description: Velero args are settings to customize velero + server arguments. Overrides values in other fields. + properties: + add_dir_header: + description: If true, adds the file directory to the header + of the log messages + type: boolean + alsologtostderr: + description: log to standard error as well as files (no + effect when -logtostderr=true) + type: boolean + backup-sync-period: + description: How often (in nanoseconds) to ensure all + Velero backups in object storage exist as Backup API + objects in the cluster. This is the default sync period + if none is explicitly specified for a backup storage + location. + format: int64 + type: integer + client-burst: + description: Maximum number of requests by the server + to the Kubernetes API in a short period of time. + type: integer + client-page-size: + description: Page size of requests by the server to the + Kubernetes API when listing objects during a backup. + Set to 0 to disable paging. + type: integer + client-qps: + description: |- + Maximum number of requests per second by the server to the Kubernetes API once the burst limit has been reached. + this will be validated as a valid float32 + type: string + colorized: + description: Show colored output in TTY + type: boolean + default-backup-ttl: + description: How long (in nanoseconds) to wait by default + before backups can be garbage collected. (default is + 720 hours) + format: int64 + type: integer + default-item-operation-timeout: + description: How long (in nanoseconds) to wait on asynchronous + BackupItemActions and RestoreItemActions to complete + before timing out. (default is 1 hour) + format: int64 + type: integer + default-repo-maintain-frequency: + description: How often (in nanoseconds) 'maintain' is + run for backup repositories by default. + format: int64 + type: integer + default-volumes-to-fs-backup: + description: Backup all volumes with pod volume file system + backup by default. + type: boolean + disabled-controllers: + description: List of controllers to disable on startup. + Valid values are backup,backup-operations,backup-deletion,backup-finalizer,backup-sync,download-request,gc,backup-repo,restore,restore-operations,schedule,server-status-request + enum: + - backup + - backup-operations + - backup-deletion + - backup-finalizer + - backup-sync + - download-request + - gc + - backup-repo + - restore + - restore-operations + - schedule + - server-status-request + items: type: string - type: object - timeout: - description: User supplied timeout to be used for VolumeSnapshotBackup and VolumeSnapshotRestore to complete, default value is 10m - type: string - volumeOptionsForStorageClasses: - additionalProperties: - properties: - destinationVolumeOptions: - description: VolumeOptions defines configurations for VolSync options - properties: - accessMode: - description: |- - accessMode can be used to override the accessMode of the source or - destination PVC - type: string - cacheAccessMode: - description: cacheAccessMode is the access mode to be used to provision the cache volume - type: string - cacheCapacity: - description: cacheCapacity determines the size of the restic metadata cache volume - type: string - cacheStorageClassName: - description: |- - cacheStorageClassName is the storageClass that should be used when provisioning - the data mover cache volume - type: string - storageClassName: - description: |- - storageClassName can be used to override the StorageClass of the source - or destination PVC - type: string - type: object - sourceVolumeOptions: - description: VolumeOptions defines configurations for VolSync options - properties: - accessMode: - description: |- - accessMode can be used to override the accessMode of the source or - destination PVC - type: string - cacheAccessMode: - description: cacheAccessMode is the access mode to be used to provision the cache volume - type: string - cacheCapacity: - description: cacheCapacity determines the size of the restic metadata cache volume - type: string - cacheStorageClassName: - description: |- - cacheStorageClassName is the storageClass that should be used when provisioning - the data mover cache volume - type: string - storageClassName: - description: |- - storageClassName can be used to override the StorageClass of the source - or destination PVC - type: string - type: object - type: object - description: defines configurations for data mover volume options for a storageClass - type: object - type: object - type: object - imagePullPolicy: - description: |- - which imagePullPolicy to use in all container images used by OADP. - By default, for images with sha256 or sha512 digest, OADP uses IfNotPresent and uses Always for all other images. - enum: - - Always - - IfNotPresent - - Never - type: string - logFormat: - default: text - description: The format for log output. Valid values are text, json. (default text) - enum: - - text - - json - type: string - nonAdmin: - description: nonAdmin defines the configuration for the DPA to enable backup and restore operations for non-admin users - properties: - backupSyncPeriod: - description: |- - BackupSyncPeriod specifies the interval at which backups from the OADP namespace are synchronized with non-admin namespaces. - A value of 0 disables sync. - By default 2m - type: string - enable: - description: Enables non admin feature, by default is disabled - type: boolean - enforceBSLSpec: - description: which backupstoragelocation spec field values to enforce - properties: - accessMode: - description: AccessMode defines the permissions for the backup storage location. - enum: - - ReadOnly - - ReadWrite - type: string - backupSyncPeriod: - description: BackupSyncPeriod defines how frequently to sync backup API objects from object storage. A value of 0 disables sync. - nullable: true - type: string - config: - additionalProperties: + type: array + fs-backup-timeout: + description: How long (in nanoseconds) pod volume file + system backups/restores should be allowed to run before + timing out. (default is 4 hours) + format: int64 + type: integer + garbage-collection-frequency: + description: How often (in nanoseconds) garbage collection + checks for expired backups. (default is 1 hour) + format: int64 + type: integer + item-operation-sync-frequency: + description: How often (in nanoseconds) to check status + on backup/restore operations after backup/restore processing. + format: int64 + type: integer + log-format: + description: The format for log output. Valid values are + text, json. (default text) + enum: + - text + - json type: string - description: Config is for provider-specific configuration fields. - type: object - credential: - description: Credential contains the credential information intended to be used with this location + log_backtrace_at: + description: when logging hits line file:N, emit a stack + trace + type: string + log_dir: + description: If non-empty, write log files in this directory + (no effect when -logtostderr=true) + type: string + log_file: + description: If non-empty, use this log file (no effect + when -logtostderr=true) + type: string + log_file_max_size: + description: Defines the maximum size a log file can grow + to (no effect when -logtostderr=true). Unit is megabytes. + If the value is 0, the maximum file size is unlimited. + (default 1800) + format: int64 + minimum: 0 + type: integer + logtostderr: + description: |- + Boolean flags. Not handled atomically because the flag.Value interface + does not let us avoid the =true, and that shorthand is necessary for + compatibility. TODO: does this matter enough to fix? Seems unlikely. + type: boolean + max-concurrent-k8s-connections: + description: Max concurrent connections number that Velero + can create with kube-apiserver. Default is 30. (default + 30) + type: integer + metrics-address: + description: The address to expose prometheus metrics + type: string + one_output: + description: If true, only write logs to their native + severity level (vs also writing to each lower severity + level; no effect when -logtostderr=true) + type: boolean + profiler-address: + description: The address to expose the pprof profiler. + type: string + resource-timeout: + description: How long (in nanoseconds) to wait for resource + processes which are not covered by other specific timeout + parameters. (default is 10 minutes) + format: int64 + type: integer + restore-resource-priorities: + description: Desired order of resource restores, the priority + list contains two parts which are split by "-" element. + The resources before "-" element are restored first + as high priorities, the resources after "-" element + are restored last as low priorities, and any resource + not in the list will be restored alphabetically between + the high and low priorities. (default securitycontextconstraints,customresourcedefinitions,klusterletconfigs.config.open-cluster-management.io,managedcluster.cluster.open-cluster-management.io,namespaces,roles,rolebindings,clusterrolebindings,klusterletaddonconfig.agent.open-cluster-management.io,managedclusteraddon.addon.open-cluster-management.io,storageclasses,volumesnapshotclass.snapshot.storage.k8s.io,volumesnapshotcontents.snapshot.storage.k8s.io,volumesnapshots.snapshot.storage.k8s.io,datauploads.velero.io,persistentvolumes,persistentvolumeclaims,serviceaccounts,secrets,configmaps,limitranges,pods,replicasets.apps,clusterclasses.cluster.x-k8s.io,endpoints,services,-,clusterbootstraps.run.tanzu.vmware.com,clusters.cluster.x-k8s.io,clusterresourcesets.addons.cluster.x-k8s.io) + type: string + skip_headers: + description: If true, avoid header prefixes in the log + messages + type: boolean + skip_log_headers: + description: If true, avoid headers when opening log files + (no effect when -logtostderr=true) + type: boolean + stderrthreshold: + description: logs at or above this threshold go to stderr + when writing to files and stderr (no effect when -logtostderr=true + or -alsologtostderr=false) (default 2) + type: integer + store-validation-frequency: + description: How often (in nanoseconds) to verify if the + storage is valid. Optional. Set this to `0` to disable + sync. (default is 1 minute) + format: int64 + type: integer + terminating-resource-timeout: + description: How long (in nanoseconds) to wait on persistent + volumes and namespaces to terminate during a restore + before timing out. + format: int64 + type: integer + v: + description: number for the log level verbosity + type: integer + vmodule: + description: comma-separated list of pattern=N settings + for file-filtered logging + type: string + type: object + client-burst: + description: maximum number of requests by the server to the + Kubernetes API in a short period of time. (default 100) + type: integer + client-qps: + description: maximum number of requests per second by the + server to the Kubernetes API once the burst limit has been + reached. (default 100) + type: integer + concurrentBackups: + description: |- + Number of backups to process at the same time. Only backups which do not have any namespaces + in common will run at the same time. Default is 1. + type: integer + customPlugins: + description: customPlugins defines the custom plugin to be + installed with Velero + items: properties: - key: - description: The key of the secret to select from. Must be a valid secret key. + image: type: string name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string - optional: - description: Specify whether the Secret or its key must be defined - type: boolean required: - - key - type: object - x-kubernetes-map-type: atomic - objectStorage: - description: ObjectStorageLocation defines the enforced values for the Velero ObjectStorageLocation - nullable: true - properties: - bucket: - description: Bucket is the bucket to use for object storage. - type: string - caCert: - description: CACert defines a CA bundle to use when verifying TLS connections to the provider. - format: byte - type: string - prefix: - description: Prefix is the path inside a bucket to use for Velero storage. Optional. - type: string + - image + - name type: object - provider: - description: Provider is the provider of the backup storage. - type: string - validationFrequency: - description: ValidationFrequency defines how frequently to validate the corresponding object storage. A value of 0 disables validation. - nullable: true - type: string - type: object - enforceBackupSpec: - description: which bakup spec field values to enforce - properties: - csiSnapshotTimeout: - description: |- - CSISnapshotTimeout specifies the time used to wait for CSI VolumeSnapshot status turns to - ReadyToUse during creation, before returning error as timeout. - The default value is 10 minute. + type: array + defaultItemOperationTimeout: + description: How long to wait on asynchronous BackupItemActions + and RestoreItemActions to complete before timing out. Default + value is 1h. + type: string + defaultPlugins: + items: + enum: + - aws + - legacy-aws + - gcp + - azure + - csi + - vsm + - openshift + - kubevirt + - kubevirt-datamover + - hypershift type: string - datamover: - description: |- - DataMover specifies the data mover to be used by the backup. - If DataMover is "" or "velero", the built-in data mover will be used. + type: array + defaultSnapshotMoveData: + description: Specify whether CSI snapshot data should be moved + to backup storage by default + type: boolean + defaultVolumesToFSBackup: + description: Use pod volume file system backup by default + for volumes + type: boolean + disableFsBackup: + default: false + description: |- + DisableFsBackup determines whether the NodeAgent should disable file system backup. + When set to true, the NodeAgent runs in non-privileged mode. + Defaults to false. + type: boolean + disableInformerCache: + description: Disable informer cache for Get calls on restore. + With this enabled, it will speed up restore in cases where + there are backup resources which already exist in the cluster, + but for very large clusters this will increase velero memory + usage. Default is false. + type: boolean + featureFlags: + description: featureFlags defines the list of features to + enable for Velero instance + items: type: string - defaultVolumesToFsBackup: - description: |- - DefaultVolumesToFsBackup specifies whether pod volume file system backup should be used - for all volumes by default. - nullable: true - type: boolean - defaultVolumesToRestic: - description: |- - DefaultVolumesToRestic specifies whether restic should be used to take a - backup of all pod volumes by default. - - Deprecated: this field is no longer used and will be removed entirely in future. Use DefaultVolumesToFsBackup instead. - nullable: true - type: boolean - excludedClusterScopedResources: - description: |- - ExcludedClusterScopedResources is a slice of cluster-scoped - resource type names to exclude from the backup. - If set to "*", all cluster-scoped resource types are excluded. - The default value is empty. - items: - type: string - nullable: true - type: array - excludedNamespaceScopedResources: - description: |- - ExcludedNamespaceScopedResources is a slice of namespace-scoped - resource type names to exclude from the backup. - If set to "*", all namespace-scoped resource types are excluded. - The default value is empty. - items: - type: string - nullable: true - type: array - excludedNamespaces: - description: |- - ExcludedNamespaces contains a list of namespaces that are not - included in the backup. - items: - type: string - nullable: true - type: array - excludedResources: + type: array + itemBlockWorkerCount: + description: |- + Number of workers in worker pool for processing item backup. This will allow multiple items within + a Velero backup to be backed up at the same time which may improve performance for backups with + a large number of items. Workers are per backup if concurrent backups are enabled. Default is 1. + type: integer + itemOperationSyncFrequency: + description: How often to check status on async backup/restore + operations after backup processing. Default value is 2m. + type: string + loadAffinity: + description: LoadAffinityConfig is the config for data path + load affinity. + items: description: |- - ExcludedResources is a slice of resource names that are not - included in the backup. - items: - type: string - nullable: true - type: array - hooks: - description: Hooks represent custom behaviors that should be executed at different phases of the backup. + LoadAffinity is the config for data path load affinity. + Used by the Node-Agent, that needs to match the DataMover and the RepositoryMaintenance pods. properties: - resources: - description: Resources are hooks that should be executed when backing up individual instances of a resource. - items: - description: |- - BackupResourceHookSpec defines one or more BackupResourceHooks that should be executed based on - the rules defined for namespaces, resources, and label selector. - properties: - excludedNamespaces: - description: ExcludedNamespaces specifies the namespaces to which this hook spec does not apply. - items: - type: string - nullable: true - type: array - excludedResources: - description: ExcludedResources specifies the resources to which this hook spec does not apply. - items: - type: string - nullable: true - type: array - includedNamespaces: - description: |- - IncludedNamespaces specifies the namespaces to which this hook spec applies. If empty, it applies - to all namespaces. - items: - type: string - nullable: true - type: array - includedResources: + nodeSelector: + description: NodeSelector specifies the label selector + to match nodes + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are ANDed. + items: description: |- - IncludedResources specifies the resources to which this hook spec applies. If empty, it applies - to all resources. - items: - type: string - nullable: true - type: array - labelSelector: - description: LabelSelector, if specified, filters the resources to which this hook spec applies. - nullable: true + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + 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: - 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: string 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 + required: + - key + - operator type: object - x-kubernetes-map-type: atomic - name: - description: Name is the name of this hook. + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: type: string - post: - description: |- - PostHooks is a list of BackupResourceHooks to execute after storing the item in the backup. - These are executed after all "additional items" from item actions are processed. - items: - description: BackupResourceHook defines a hook for a resource. + 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 + type: object + type: array + logLevel: + description: Velero server's log level (use debug for the + most logging, leave unset for velero default) + enum: + - trace + - debug + - info + - warning + - error + - fatal + - panic + type: string + noDefaultBackupLocation: + description: If you need to install Velero without a default + backup storage location noDefaultBackupLocation flag is + required for confirmation + type: boolean + podConfig: + description: Pod specific configuration + properties: + annotations: + additionalProperties: + type: string + description: annotations to add to pods + type: object + env: + description: env defines the list of environment variables + to be supplied to podSpec + items: + description: EnvVar represents an environment variable + present in a Container. + properties: + name: + description: Name of the environment variable. Must + be a C_IDENTIFIER. + type: string + value: + description: |- + Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in the container and + any service environment variables. If a variable cannot be resolved, + the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless of whether the variable + exists or not. + Defaults to "". + type: string + valueFrom: + description: Source for the environment variable's + value. Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. properties: - exec: - description: Exec defines an exec hook. - properties: - command: - description: Command is the command and arguments to execute. - items: - type: string - minItems: 1 - type: array - container: - description: |- - Container is the container in the pod where the command should be executed. If not specified, - the pod's first container is used. - type: string - onError: - description: OnError specifies how Velero should behave if it encounters an error executing this hook. - enum: - - Continue - - Fail - type: string - timeout: - description: |- - Timeout defines the maximum amount of time Velero should wait for the hook to complete before - considering the execution a failure. - type: string - required: - - command - type: object + key: + description: The key to select. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean required: - - exec + - key type: object - type: array - pre: - description: |- - PreHooks is a list of BackupResourceHooks to execute prior to storing the item in the backup. - These are executed before any "additional items" from item actions are processed. - items: - description: BackupResourceHook defines a hook for a resource. + x-kubernetes-map-type: atomic + fieldRef: + description: |- + Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. properties: - exec: - description: Exec defines an exec hook. - properties: - command: - description: Command is the command and arguments to execute. - items: - type: string - minItems: 1 - type: array - container: - description: |- - Container is the container in the pod where the command should be executed. If not specified, - the pod's first container is used. - type: string - onError: - description: OnError specifies how Velero should behave if it encounters an error executing this hook. - enum: - - Continue - - Fail - type: string - timeout: - description: |- - Timeout defines the maximum amount of time Velero should wait for the hook to complete before - considering the execution a failure. - type: string - required: - - command - type: object + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select + in the specified API version. + type: string required: - - exec + - fieldPath type: object - type: array - required: + x-kubernetes-map-type: atomic + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + properties: + containerName: + description: 'Container name: required for + volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format + of the exposed resources, defaults to + "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the + pod's namespace + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + labels: + additionalProperties: + type: string + description: labels to add to pods + type: object + nodeSelector: + additionalProperties: + type: string + description: nodeSelector defines the nodeSelector to + be supplied to podSpec + type: object + resourceAllocations: + description: resourceAllocations defines the CPU, Memory + and ephemeral-storage resource allocations for the Pod + nullable: true + 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 - nullable: true - type: array + 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 + tolerations: + description: tolerations defines the list of tolerations + to be applied to daemonset + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + type: object + resourceTimeout: + description: |- + resourceTimeout defines how long to wait for several Velero resources before timeout occurs, + such as Velero CRD availability, volumeSnapshot deletion, and repo availability. + Default is 10m + type: string + restoreResourcesVersionPriority: + description: |- + restoreResourceVersionPriority represents a configmap that will be created if defined for use in conjunction with EnableAPIGroupVersions feature flag + Defining this field automatically add EnableAPIGroupVersions to the velero server feature flag + type: string + type: object + type: object + features: + description: features defines the configuration for the DPA to enable + the OADP tech preview features + properties: + dataMover: + description: |- + (do not use warning) dataMover is for backwards compatibility and + will be removed in the future. Use Velero Built-in Data Mover instead + properties: + credentialName: + description: User supplied Restic Secret name + type: string + enable: + description: enable flag is used to specify whether you want + to deploy the volume snapshot mover controller + type: boolean + maxConcurrentBackupVolumes: + description: the number of batched volumeSnapshotBackups that + can be inProgress at once, default value is 10 + type: string + maxConcurrentRestoreVolumes: + description: the number of batched volumeSnapshotRestores + that can be inProgress at once, default value is 10 + type: string + pruneInterval: + description: defines how often (in days) to prune the datamover + snapshots from the repository + type: string + schedule: + description: |- + schedule is a cronspec (https://en.wikipedia.org/wiki/Cron#Overview) that + can be used to schedule datamover(volsync) synchronization to occur at regular, time-based + intervals. For example, in order to enforce datamover SnapshotRetainPolicy at a regular interval you need to + specify this Schedule trigger as a cron expression, by default the trigger is a manual trigger. For more details + on Volsync triggers, refer: https://volsync.readthedocs.io/en/stable/usage/triggers.html + pattern: ^(\d+|\*)(/\d+)?(\s+(\d+|\*)(/\d+)?){4}$ + type: string + snapshotRetainPolicy: + description: defines the parameters that can be specified + for retention of datamover snapshots + properties: + daily: + description: Daily defines the number of snapshots to + be kept daily + type: string + hourly: + description: Hourly defines the number of snapshots to + be kept hourly + type: string + monthly: + description: Monthly defines the number of snapshots to + be kept monthly + type: string + weekly: + description: Weekly defines the number of snapshots to + be kept weekly + type: string + 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 + type: string + type: object + timeout: + description: User supplied timeout to be used for VolumeSnapshotBackup + and VolumeSnapshotRestore to complete, default value is + 10m + type: string + volumeOptionsForStorageClasses: + additionalProperties: + properties: + destinationVolumeOptions: + description: VolumeOptions defines configurations for + VolSync options + properties: + accessMode: + description: |- + accessMode can be used to override the accessMode of the source or + destination PVC + type: string + cacheAccessMode: + description: cacheAccessMode is the access mode + to be used to provision the cache volume + type: string + cacheCapacity: + description: cacheCapacity determines the size of + the restic metadata cache volume + type: string + cacheStorageClassName: + description: |- + cacheStorageClassName is the storageClass that should be used when provisioning + the data mover cache volume + type: string + storageClassName: + description: |- + storageClassName can be used to override the StorageClass of the source + or destination PVC + type: string + type: object + sourceVolumeOptions: + description: VolumeOptions defines configurations for + VolSync options + properties: + accessMode: + description: |- + accessMode can be used to override the accessMode of the source or + destination PVC + type: string + cacheAccessMode: + description: cacheAccessMode is the access mode + to be used to provision the cache volume + type: string + cacheCapacity: + description: cacheCapacity determines the size of + the restic metadata cache volume + type: string + cacheStorageClassName: + description: |- + cacheStorageClassName is the storageClass that should be used when provisioning + the data mover cache volume + type: string + storageClassName: + description: |- + storageClassName can be used to override the StorageClass of the source + or destination PVC + type: string + type: object type: object - includeClusterResources: - description: |- - IncludeClusterResources specifies whether cluster-scoped resources - should be included for consideration in the backup. - nullable: true - type: boolean - includedClusterScopedResources: - description: |- - IncludedClusterScopedResources is a slice of cluster-scoped - resource type names to include in the backup. - If set to "*", all cluster-scoped resource types are included. - The default value is empty, which means only related - cluster-scoped resources are included. - items: + description: defines configurations for data mover volume + options for a storageClass + type: object + type: object + type: object + imagePullPolicy: + description: |- + which imagePullPolicy to use in all container images used by OADP. + By default, for images with sha256 or sha512 digest, OADP uses IfNotPresent and uses Always for all other images. + enum: + - Always + - IfNotPresent + - Never + type: string + kubevirtAnnotationsRemover: + description: |- + kubevirtAnnotationsRemover defines the configuration for the webhook that removes + Velero backup hook annotations from KubeVirt virt-launcher pods + properties: + enable: + description: |- + Enable flag to deploy kubevirt-velero-annotations-remover webhook. + By default is disabled + type: boolean + type: object + logFormat: + default: text + description: The format for log output. Valid values are text, json. + (default text) + enum: + - text + - json + type: string + nonAdmin: + description: nonAdmin defines the configuration for the DPA to enable + backup and restore operations for non-admin users + properties: + backupSyncPeriod: + description: |- + BackupSyncPeriod specifies the interval at which backups from the OADP namespace are synchronized with non-admin namespaces. + A value of 0 disables sync. + By default 2m + type: string + enable: + description: Enables non admin feature, by default is disabled + type: boolean + enforceBSLSpec: + description: which backupstoragelocation spec field values to + enforce + properties: + accessMode: + description: AccessMode defines the permissions for the backup + storage location. + enum: + - ReadOnly + - ReadWrite + type: string + backupSyncPeriod: + description: BackupSyncPeriod defines how frequently to sync + backup API objects from object storage. A value of 0 disables + sync. + nullable: true + type: string + config: + additionalProperties: + type: string + description: Config is for provider-specific configuration + fields. + type: object + credential: + description: Credential contains the credential information + intended to be used with this location + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. type: string - nullable: true - type: array - includedNamespaceScopedResources: - description: |- - IncludedNamespaceScopedResources is a slice of namespace-scoped - resource type names to include in the backup. - The default value is "*". - items: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string - nullable: true - type: array - includedNamespaces: - description: |- - IncludedNamespaces is a slice of namespace names to include objects - from. If empty, all namespaces are included. - items: + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + objectStorage: + description: ObjectStorageLocation defines the enforced values + for the Velero ObjectStorageLocation + nullable: true + properties: + bucket: + description: Bucket is the bucket to use for object storage. type: string - nullable: true - type: array - includedResources: - description: |- - IncludedResources is a slice of resource names to include - in the backup. If empty, all resources are included. - items: + caCert: + description: CACert defines a CA bundle to use when verifying + TLS connections to the provider. + format: byte type: string - nullable: true - type: array - itemOperationTimeout: - description: |- - ItemOperationTimeout specifies the time used to wait for asynchronous BackupItemAction operations - The default value is 4 hour. + prefix: + description: Prefix is the path inside a bucket to use + for Velero storage. Optional. + type: string + type: object + provider: + description: Provider is the provider of the backup storage. + type: string + validationFrequency: + description: ValidationFrequency defines how frequently to + validate the corresponding object storage. A value of 0 + disables validation. + nullable: true + type: string + type: object + enforceBackupSpec: + description: which bakup spec field values to enforce + properties: + csiSnapshotTimeout: + description: |- + CSISnapshotTimeout specifies the time used to wait for CSI VolumeSnapshot status turns to + ReadyToUse during creation, before returning error as timeout. + The default value is 10 minute. + type: string + datamover: + description: |- + DataMover specifies the data mover to be used by the backup. + If DataMover is "" or "velero", the built-in data mover will be used. + type: string + defaultVolumesToFsBackup: + description: |- + DefaultVolumesToFsBackup specifies whether pod volume file system backup should be used + for all volumes by default. + nullable: true + type: boolean + defaultVolumesToRestic: + description: |- + DefaultVolumesToRestic specifies whether restic should be used to take a + backup of all pod volumes by default. + + Deprecated: this field is no longer used and will be removed entirely in future. Use DefaultVolumesToFsBackup instead. + nullable: true + type: boolean + excludedClusterScopedResources: + description: |- + ExcludedClusterScopedResources is a slice of cluster-scoped + resource type names to exclude from the backup. + If set to "*", all cluster-scoped resource types are excluded. + The default value is empty. + items: + type: string + nullable: true + type: array + excludedNamespaceScopedResources: + description: |- + ExcludedNamespaceScopedResources is a slice of namespace-scoped + resource type names to exclude from the backup. + If set to "*", all namespace-scoped resource types are excluded. + The default value is empty. + items: + type: string + nullable: true + type: array + excludedNamespaces: + description: |- + ExcludedNamespaces contains a list of namespaces that are not + included in the backup. + items: + type: string + nullable: true + type: array + excludedResources: + description: |- + ExcludedResources is a slice of resource names that are not + included in the backup. + items: + type: string + nullable: true + type: array + hooks: + description: Hooks represent custom behaviors that should + be executed at different phases of the backup. + properties: + resources: + description: Resources are hooks that should be executed + when backing up individual instances of a resource. + items: + description: |- + BackupResourceHookSpec defines one or more BackupResourceHooks that should be executed based on + the rules defined for namespaces, resources, and label selector. + properties: + excludedNamespaces: + description: ExcludedNamespaces specifies the namespaces + to which this hook spec does not apply. + items: + type: string + nullable: true + type: array + excludedResources: + description: ExcludedResources specifies the resources + to which this hook spec does not apply. + items: + type: string + nullable: true + type: array + includedNamespaces: + description: |- + IncludedNamespaces specifies the namespaces to which this hook spec applies. If empty, it applies + to all namespaces. + items: + type: string + nullable: true + type: array + includedResources: + description: |- + IncludedResources specifies the resources to which this hook spec applies. If empty, it applies + to all resources. + items: + type: string + nullable: true + type: array + labelSelector: + description: LabelSelector, if specified, filters + the resources to which this hook spec applies. + nullable: true + 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 + name: + description: Name is the name of this hook. + type: string + post: + description: |- + PostHooks is a list of BackupResourceHooks to execute after storing the item in the backup. + These are executed after all "additional items" from item actions are processed. + items: + description: BackupResourceHook defines a hook + for a resource. + properties: + exec: + description: Exec defines an exec hook. + properties: + command: + description: Command is the command and + arguments to execute. + items: + type: string + minItems: 1 + type: array + container: + description: |- + Container is the container in the pod where the command should be executed. If not specified, + the pod's first container is used. + type: string + onError: + description: OnError specifies how Velero + should behave if it encounters an error + executing this hook. + enum: + - Continue + - Fail + type: string + timeout: + description: |- + Timeout defines the maximum amount of time Velero should wait for the hook to complete before + considering the execution a failure. + type: string + required: + - command + type: object + required: + - exec + type: object + type: array + pre: + description: |- + PreHooks is a list of BackupResourceHooks to execute prior to storing the item in the backup. + These are executed before any "additional items" from item actions are processed. + items: + description: BackupResourceHook defines a hook + for a resource. + properties: + exec: + description: Exec defines an exec hook. + properties: + command: + description: Command is the command and + arguments to execute. + items: + type: string + minItems: 1 + type: array + container: + description: |- + Container is the container in the pod where the command should be executed. If not specified, + the pod's first container is used. + type: string + onError: + description: OnError specifies how Velero + should behave if it encounters an error + executing this hook. + enum: + - Continue + - Fail + type: string + timeout: + description: |- + Timeout defines the maximum amount of time Velero should wait for the hook to complete before + considering the execution a failure. + type: string + required: + - command + type: object + required: + - exec + type: object + type: array + required: + - name + type: object + nullable: true + type: array + type: object + includeClusterResources: + description: |- + IncludeClusterResources specifies whether cluster-scoped resources + should be included for consideration in the backup. + nullable: true + type: boolean + includedClusterScopedResources: + description: |- + IncludedClusterScopedResources is a slice of cluster-scoped + resource type names to include in the backup. + If set to "*", all cluster-scoped resource types are included. + The default value is empty, which means only related + cluster-scoped resources are included. + items: + type: string + nullable: true + type: array + includedNamespaceScopedResources: + description: |- + IncludedNamespaceScopedResources is a slice of namespace-scoped + resource type names to include in the backup. + The default value is "*". + items: + type: string + nullable: true + type: array + includedNamespaces: + description: |- + IncludedNamespaces is a slice of namespace names to include objects + from. If empty, all namespaces are included. + items: + type: string + nullable: true + type: array + includedResources: + description: |- + IncludedResources is a slice of resource names to include + in the backup. If empty, all resources are included. + items: type: string - labelSelector: + nullable: true + type: array + itemOperationTimeout: + description: |- + ItemOperationTimeout specifies the time used to wait for asynchronous BackupItemAction operations + The default value is 4 hour. + type: string + labelSelector: + description: |- + LabelSelector is a metav1.LabelSelector to filter with + when adding individual objects to the backup. If empty + or nil, all objects are included. Optional. + nullable: true + 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 + metadata: + properties: + labels: + additionalProperties: + type: string + type: object + type: object + orLabelSelectors: + description: |- + OrLabelSelectors is list of metav1.LabelSelector to filter with + when adding individual objects to the backup. If multiple provided + they will be joined by the OR operator. LabelSelector as well as + OrLabelSelectors cannot co-exist in backup request, only one of them + can be used. + items: description: |- - LabelSelector is a metav1.LabelSelector to filter with - when adding individual objects to the backup. If empty - or nil, all objects are included. Optional. - nullable: true + A label selector is a label query over a set of resources. The result of matchLabels and + matchExpressions are ANDed. An empty label selector matches all objects. A null + label selector matches no objects. properties: matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + 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. + description: key is the label key that the selector + applies to. type: string operator: description: |- @@ -2011,8 +2320,8 @@ spec: type: array x-kubernetes-list-type: atomic required: - - key - - operator + - key + - operator type: object type: array x-kubernetes-list-type: atomic @@ -2026,354 +2335,389 @@ spec: type: object type: object x-kubernetes-map-type: atomic - metadata: - properties: - labels: - additionalProperties: - type: string - type: object - type: object - orLabelSelectors: - description: |- - OrLabelSelectors is list of metav1.LabelSelector to filter with - when adding individual objects to the backup. If multiple provided - they will be joined by the OR operator. LabelSelector as well as - OrLabelSelectors cannot co-exist in backup request, only one of them - can be used. - items: + nullable: true + type: array + orderedResources: + additionalProperties: + type: string + description: |- + OrderedResources specifies the backup order of resources of specific Kind. + The map key is the resource name and value is a list of object names separated by commas. + Each resource name has format "namespace/objectname". For cluster resources, simply use "objectname". + nullable: true + type: object + resourcePolicy: + description: ResourcePolicy specifies the referenced resource + policies that backup should follow + properties: + apiGroup: description: |- - A label selector is a label query over a set of resources. The result of matchLabels and - matchExpressions are ANDed. An empty label selector matches all objects. A null - label selector matches no objects. - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - items: + 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 + snapshotMoveData: + description: SnapshotMoveData specifies whether snapshot data + should be moved + nullable: true + type: boolean + snapshotVolumes: + description: |- + SnapshotVolumes specifies whether to take snapshots + of any PV's referenced in the set of objects included + in the Backup. + nullable: true + type: boolean + storageLocation: + description: StorageLocation is a string containing the name + of a BackupStorageLocation where the backup should be stored. + type: string + ttl: + description: |- + TTL is a time.Duration-parseable string describing how long + the Backup should be retained for. + type: string + uploaderConfig: + description: UploaderConfig specifies the configuration for + the uploader. + nullable: true + properties: + parallelFilesUpload: + description: ParallelFilesUpload is the number of files + parallel uploads to perform when using the uploader. + type: integer + type: object + volumeGroupSnapshotLabelKey: + description: VolumeGroupSnapshotLabelKey specifies the label + key to group PVCs under a VGS. + type: string + volumeSnapshotLocations: + description: VolumeSnapshotLocations is a list containing + names of VolumeSnapshotLocations associated with this backup. + items: + type: string + type: array + type: object + enforceRestoreSpec: + description: which restore spec field values to enforce + properties: + backupName: + description: |- + BackupName is the unique name of the Velero backup to restore + from. + type: string + excludedNamespaces: + description: |- + ExcludedNamespaces contains a list of namespaces that are not + included in the restore. + items: + type: string + nullable: true + type: array + excludedResources: + description: |- + ExcludedResources is a slice of resource names that are not + included in the restore. + items: + type: string + nullable: true + type: array + existingResourcePolicy: + description: ExistingResourcePolicy specifies the restore + behavior for the Kubernetes resource to be restored + nullable: true + type: string + hooks: + description: Hooks represent custom behaviors that should + be executed during or post restore. + properties: + resources: + items: + description: |- + RestoreResourceHookSpec defines one or more RestoreResrouceHooks that should be executed based on + the rules defined for namespaces, resources, and label selector. + properties: + excludedNamespaces: + description: ExcludedNamespaces specifies the namespaces + to which this hook spec does not apply. + items: + type: string + nullable: true + type: array + excludedResources: + description: ExcludedResources specifies the resources + to which this hook spec does not apply. + items: + type: string + nullable: true + type: array + includedNamespaces: + description: |- + IncludedNamespaces specifies the namespaces to which this hook spec applies. If empty, it applies + to all namespaces. + items: + type: string + nullable: true + type: array + includedResources: description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. + IncludedResources specifies the resources to which this hook spec applies. If empty, it applies + to all resources. + items: + type: string + nullable: true + type: array + labelSelector: + description: LabelSelector, if specified, filters + the resources to which this hook spec applies. + nullable: true 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. + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. items: - type: string + 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 - required: - - key - - operator + 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 - type: array - x-kubernetes-list-type: atomic - matchLabels: - additionalProperties: + x-kubernetes-map-type: atomic + name: + description: Name is the name of this hook. 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 - nullable: true - type: array - orderedResources: - additionalProperties: - type: string - description: |- - OrderedResources specifies the backup order of resources of specific Kind. - The map key is the resource name and value is a list of object names separated by commas. - Each resource name has format "namespace/objectname". For cluster resources, simply use "objectname". - nullable: true - type: object - resourcePolicy: - description: ResourcePolicy specifies the referenced resource policies that backup should follow - 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 - snapshotMoveData: - description: SnapshotMoveData specifies whether snapshot data should be moved - nullable: true - type: boolean - snapshotVolumes: - description: |- - SnapshotVolumes specifies whether to take snapshots - of any PV's referenced in the set of objects included - in the Backup. - nullable: true - type: boolean - storageLocation: - description: StorageLocation is a string containing the name of a BackupStorageLocation where the backup should be stored. - type: string - ttl: - description: |- - TTL is a time.Duration-parseable string describing how long - the Backup should be retained for. - type: string - uploaderConfig: - description: UploaderConfig specifies the configuration for the uploader. - nullable: true - properties: - parallelFilesUpload: - description: ParallelFilesUpload is the number of files parallel uploads to perform when using the uploader. - type: integer - type: object - volumeGroupSnapshotLabelKey: - description: VolumeGroupSnapshotLabelKey specifies the label key to group PVCs under a VGS. - type: string - volumeSnapshotLocations: - description: VolumeSnapshotLocations is a list containing names of VolumeSnapshotLocations associated with this backup. - items: - type: string - type: array - type: object - enforceRestoreSpec: - description: which restore spec field values to enforce - properties: - backupName: - description: |- - BackupName is the unique name of the Velero backup to restore - from. - type: string - excludedNamespaces: - description: |- - ExcludedNamespaces contains a list of namespaces that are not - included in the restore. - items: - type: string - nullable: true - type: array - excludedResources: - description: |- - ExcludedResources is a slice of resource names that are not - included in the restore. - items: - type: string - nullable: true - type: array - existingResourcePolicy: - description: ExistingResourcePolicy specifies the restore behavior for the Kubernetes resource to be restored - nullable: true - type: string - hooks: - description: Hooks represent custom behaviors that should be executed during or post restore. - properties: - resources: - items: - description: |- - RestoreResourceHookSpec defines one or more RestoreResrouceHooks that should be executed based on - the rules defined for namespaces, resources, and label selector. - properties: - excludedNamespaces: - description: ExcludedNamespaces specifies the namespaces to which this hook spec does not apply. - items: - type: string - nullable: true - type: array - excludedResources: - description: ExcludedResources specifies the resources to which this hook spec does not apply. - items: - type: string - nullable: true - type: array - includedNamespaces: - description: |- - IncludedNamespaces specifies the namespaces to which this hook spec applies. If empty, it applies - to all namespaces. - items: - type: string - nullable: true - type: array - includedResources: - description: |- - IncludedResources specifies the resources to which this hook spec applies. If empty, it applies - to all resources. - items: - type: string - nullable: true - type: array - labelSelector: - description: LabelSelector, if specified, filters the resources to which this hook spec applies. - nullable: true + postHooks: + description: PostHooks is a list of RestoreResourceHooks + to execute during and after restoring a resource. + items: + description: RestoreResourceHook defines a restore + hook for a resource. 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. + exec: + description: Exec defines an exec restore + hook. + properties: + command: + description: Command is the command and + arguments to execute from within a container + after a pod has been restored. + items: 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. + minItems: 1 + type: array + container: + description: |- + Container is the container in the pod where the command should be executed. If not specified, + the pod's first container is used. + type: string + execTimeout: + description: |- + ExecTimeout defines the maximum amount of time Velero should wait for the hook to complete before + considering the execution a failure. + type: string + onError: + description: OnError specifies how Velero + should behave if it encounters an error + executing this hook. + enum: + - Continue + - Fail + type: string + waitForReady: + description: WaitForReady ensures command + will be launched when container is Ready + instead of Running. + nullable: true + type: boolean + waitTimeout: + description: |- + WaitTimeout defines the maximum amount of time Velero should wait for the container to be Ready + before attempting to run the command. + type: string + required: + - command + type: object + init: + description: Init defines an init restore + hook. + properties: + initContainers: + description: InitContainers is list of + init containers to be added to a pod + during its restore. + items: + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + x-kubernetes-preserve-unknown-fields: true + timeout: + description: Timeout defines the maximum + amount of time Velero should wait for + the initContainers to complete. + type: string type: object type: object - x-kubernetes-map-type: atomic - name: - description: Name is the name of this hook. + type: array + required: + - name + type: object + type: array + type: object + includeClusterResources: + description: |- + IncludeClusterResources specifies whether cluster-scoped resources + should be included for consideration in the restore. If null, defaults + to true. + nullable: true + type: boolean + includedNamespaces: + description: |- + IncludedNamespaces is a slice of namespace names to include objects + from. If empty, all namespaces are included. + items: + type: string + nullable: true + type: array + includedResources: + description: |- + IncludedResources is a slice of resource names to include + in the restore. If empty, all resources in the backup are included. + items: + type: string + nullable: true + type: array + itemOperationTimeout: + description: |- + ItemOperationTimeout specifies the time used to wait for RestoreItemAction operations + The default value is 4 hour. + type: string + labelSelector: + description: |- + LabelSelector is a metav1.LabelSelector to filter with + when restoring individual objects from the backup. If empty + or nil, all objects are included. Optional. + nullable: true + 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 - postHooks: - description: PostHooks is a list of RestoreResourceHooks to execute during and after restoring a resource. - items: - description: RestoreResourceHook defines a restore hook for a resource. - properties: - exec: - description: Exec defines an exec restore hook. - properties: - command: - description: Command is the command and arguments to execute from within a container after a pod has been restored. - items: - type: string - minItems: 1 - type: array - container: - description: |- - Container is the container in the pod where the command should be executed. If not specified, - the pod's first container is used. - type: string - execTimeout: - description: |- - ExecTimeout defines the maximum amount of time Velero should wait for the hook to complete before - considering the execution a failure. - type: string - onError: - description: OnError specifies how Velero should behave if it encounters an error executing this hook. - enum: - - Continue - - Fail - type: string - waitForReady: - description: WaitForReady ensures command will be launched when container is Ready instead of Running. - nullable: true - type: boolean - waitTimeout: - description: |- - WaitTimeout defines the maximum amount of time Velero should wait for the container to be Ready - before attempting to run the command. - type: string - required: - - command - type: object - init: - description: Init defines an init restore hook. - properties: - initContainers: - description: InitContainers is list of init containers to be added to a pod during its restore. - items: - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - x-kubernetes-preserve-unknown-fields: true - timeout: - description: Timeout defines the maximum amount of time Velero should wait for the initContainers to complete. - type: string - type: object - type: object - type: array - required: - - name - type: object - type: array - type: object - includeClusterResources: - description: |- - IncludeClusterResources specifies whether cluster-scoped resources - should be included for consideration in the restore. If null, defaults - to true. - nullable: true - type: boolean - includedNamespaces: - description: |- - IncludedNamespaces is a slice of namespace names to include objects - from. If empty, all namespaces are included. - items: - type: string - nullable: true - type: array - includedResources: - description: |- - IncludedResources is a slice of resource names to include - in the restore. If empty, all resources in the backup are included. - items: - type: string - nullable: true - type: array - itemOperationTimeout: - description: |- - ItemOperationTimeout specifies the time used to wait for RestoreItemAction operations - The default value is 4 hour. + 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 + namespaceMapping: + additionalProperties: type: string - labelSelector: + description: |- + NamespaceMapping is a map of source namespace names + to target namespace names to restore into. Any source + namespaces not included in the map will be restored into + namespaces of the same name. + type: object + orLabelSelectors: + description: |- + OrLabelSelectors is list of metav1.LabelSelector to filter with + when restoring individual objects from the backup. If multiple provided + they will be joined by the OR operator. LabelSelector as well as + OrLabelSelectors cannot co-exist in restore request, only one of them + can be used + items: description: |- - LabelSelector is a metav1.LabelSelector to filter with - when restoring individual objects from the backup. If empty - or nil, all objects are included. Optional. - nullable: true + A label selector is a label query over a set of resources. The result of matchLabels and + matchExpressions are ANDed. An empty label selector matches all objects. A null + label selector matches no objects. properties: matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + 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. + description: key is the label key that the selector + applies to. type: string operator: description: |- @@ -2391,8 +2735,8 @@ spec: type: array x-kubernetes-list-type: atomic required: - - key - - operator + - key + - operator type: object type: array x-kubernetes-list-type: atomic @@ -2406,434 +2750,390 @@ spec: type: object type: object x-kubernetes-map-type: atomic - namespaceMapping: - additionalProperties: - type: string - description: |- - NamespaceMapping is a map of source namespace names - to target namespace names to restore into. Any source - namespaces not included in the map will be restored into - namespaces of the same name. - type: object - orLabelSelectors: - description: |- - OrLabelSelectors is list of metav1.LabelSelector to filter with - when restoring individual objects from the backup. If multiple provided - they will be joined by the OR operator. LabelSelector as well as - OrLabelSelectors cannot co-exist in restore request, only one of them - can be used - items: - description: |- - A label selector is a label query over a set of resources. The result of matchLabels and - matchExpressions are ANDed. An empty label selector matches all objects. A null - label selector matches no objects. - 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 - nullable: true - type: array - preserveNodePorts: - description: PreserveNodePorts specifies whether to restore old nodePorts from backup. - nullable: true - type: boolean - resourceModifier: - description: ResourceModifier specifies the reference to JSON resource patches that should be applied to resources before restoration. - nullable: true - 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 - restorePVs: - description: |- - RestorePVs specifies whether to restore all included - PVs from snapshot - nullable: true - type: boolean - restoreStatus: - description: |- - RestoreStatus specifies which resources we should restore the status - field. If nil, no objects are included. Optional. - nullable: true - properties: - excludedResources: - description: ExcludedResources specifies the resources to which will not restore the status. - items: - type: string - nullable: true - type: array - includedResources: - description: |- - IncludedResources specifies the resources to which will restore the status. - If empty, it applies to all resources. - items: - type: string - nullable: true - type: array - type: object - scheduleName: - description: |- - ScheduleName is the unique name of the Velero schedule to restore - from. If specified, and BackupName is empty, Velero will restore - from the most recent successful backup created from this schedule. - type: string - uploaderConfig: - description: UploaderConfig specifies the configuration for the restore. - nullable: true - properties: - parallelFilesDownload: - description: ParallelFilesDownload is the concurrency number setting for restore. - type: integer - writeSparseFiles: - description: WriteSparseFiles is a flag to indicate whether write files sparsely or not. - nullable: true - type: boolean - type: object - type: object - garbageCollectionPeriod: - description: |- - GarbageCollectionPeriod defines how frequently to look for possible leftover non admin related objects in OADP namespace. - A value of 0 disables garbage collection. - By default 24h - type: string - requireApprovalForBSL: - description: |- - RequireApprovalForBSL specifies whether cluster administrator approval is required - for creating Velero BackupStorageLocation (BSL) resources. - - If set to false, all NonAdminBackupStorageLocationApproval CRDs will be automatically approved, - including those that were previously pending or rejected. - - If set to true, any existing BackupStorageLocation CRDs that lack the necessary approvals may be deleted, - leaving the associated NonAdminBackup objects non-restorable until approval is granted. - Defaults to false - type: boolean - type: object - podAnnotations: - additionalProperties: - type: string - description: |- - add annotations to pods deployed by operator - Deprecated: Use PodConfig instead - type: object - podDnsConfig: - description: |- - podDnsConfig defines the DNS parameters of a pod in addition to - those generated from DNSPolicy. - https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-dns-config - properties: - nameservers: - description: |- - A list of DNS name server IP addresses. - This will be appended to the base nameservers generated from DNSPolicy. - Duplicated nameservers will be removed. - items: - type: string - type: array - x-kubernetes-list-type: atomic - options: - description: |- - A list of DNS resolver options. - This will be merged with the base options generated from DNSPolicy. - Duplicated entries will be removed. Resolution options given in Options - will override those that appear in the base DNSPolicy. - items: - description: PodDNSConfigOption defines DNS resolver options of a pod. + nullable: true + type: array + preserveNodePorts: + description: PreserveNodePorts specifies whether to restore + old nodePorts from backup. + nullable: true + type: boolean + resourceModifier: + description: ResourceModifier specifies the reference to JSON + resource patches that should be applied to resources before + restoration. + nullable: true properties: - name: + apiGroup: description: |- - Name is this DNS resolver option's name. - Required. + 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 - value: - description: Value is this DNS resolver option's value. + name: + description: Name is the name of resource being referenced type: string + required: + - kind + - name type: object - type: array - x-kubernetes-list-type: atomic - searches: - description: |- - A list of DNS search domains for host-name lookup. - This will be appended to the base search paths generated from DNSPolicy. - Duplicated search paths will be removed. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - podDnsPolicy: - description: |- - podDnsPolicy defines how a pod's DNS will be configured. - https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-s-dns-policy - type: string - resourceAnnotations: - additionalProperties: - type: string - description: |- - resourceAnnotations defines annotations that will be applied to all resources managed by the DPA. - Useful for GitOps tools like ArgoCD (e.g., argocd.argoproj.io/ignore-resource-updates: 'true'). - type: object - resourceLabels: - additionalProperties: - type: string - description: |- - resourceLabels defines labels that will be applied to all resources managed by the DPA. - These labels are merged with OADP-required labels. User-provided labels cannot override - core operator labels (app.kubernetes.io/*, openshift.io/oadp). - type: object - snapshotLocations: - description: snapshotLocations defines the list of desired configuration to use for VolumeSnapshotLocations - items: - description: SnapshotLocation defines the configuration for the DPA snapshot store - properties: - name: - type: string - velero: - description: VolumeSnapshotLocationSpec defines the specification for a Velero VolumeSnapshotLocation. + x-kubernetes-map-type: atomic + restorePVs: + description: |- + RestorePVs specifies whether to restore all included + PVs from snapshot + nullable: true + type: boolean + restoreStatus: + description: |- + RestoreStatus specifies which resources we should restore the status + field. If nil, no objects are included. Optional. + nullable: true properties: - config: - additionalProperties: + excludedResources: + description: ExcludedResources specifies the resources + to which will not restore the status. + items: type: string - description: Config is for provider-specific configuration fields. - type: object - credential: - description: Credential contains the credential information intended to be used with this location - properties: - key: - description: The key of the secret to select from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - provider: - description: Provider is the provider of the volume storage. - type: string - required: - - provider + nullable: true + type: array + includedResources: + description: |- + IncludedResources specifies the resources to which will restore the status. + If empty, it applies to all resources. + items: + type: string + nullable: true + type: array + type: object + scheduleName: + description: |- + ScheduleName is the unique name of the Velero schedule to restore + from. If specified, and BackupName is empty, Velero will restore + from the most recent successful backup created from this schedule. + type: string + uploaderConfig: + description: UploaderConfig specifies the configuration for + the restore. + nullable: true + properties: + parallelFilesDownload: + description: ParallelFilesDownload is the concurrency + number setting for restore. + type: integer + writeSparseFiles: + description: WriteSparseFiles is a flag to indicate whether + write files sparsely or not. + nullable: true + type: boolean type: object - required: - - velero type: object - type: array - unsupportedOverrides: - additionalProperties: + garbageCollectionPeriod: + description: |- + GarbageCollectionPeriod defines how frequently to look for possible leftover non admin related objects in OADP namespace. + A value of 0 disables garbage collection. + By default 24h type: string - description: |- - unsupportedOverrides can be used to override images used in deployments. - Available keys are: - - veleroImageFqin - - awsPluginImageFqin - - legacyAWSPluginImageFqin - - openshiftPluginImageFqin - - azurePluginImageFqin - - gcpPluginImageFqin - - kubevirtPluginImageFqin - - kubevirtDatamoverPluginImageFqin - - hypershiftPluginImageFqin - - nonAdminControllerImageFqin - - vmFileRestoreControllerImageFqin - - vmFileRestoreAccessImageFqin - - vmFileRestoreSSHImageFqin - - vmFileRestoreBrowserImageFqin - - operator-type - - tech-preview-ack - type: object - vmFileRestore: - description: vmFileRestore defines the configuration for the DPA to enable VM file restore feature - properties: - enable: - description: |- - Enable flag to deploy VM file restore controller - By default is disabled - type: boolean - resources: - description: Resource requirements for the VM file restore controller + requireApprovalForBSL: + description: |- + RequireApprovalForBSL specifies whether cluster administrator approval is required + for creating Velero BackupStorageLocation (BSL) resources. + - If set to false, all NonAdminBackupStorageLocationApproval CRDs will be automatically approved, + including those that were previously pending or rejected. + - If set to true, any existing BackupStorageLocation CRDs that lack the necessary approvals may be deleted, + leaving the associated NonAdminBackup objects non-restorable until approval is granted. + Defaults to false + type: boolean + type: object + podAnnotations: + additionalProperties: + type: string + description: |- + add annotations to pods deployed by operator + Deprecated: Use PodConfig instead + type: object + podDnsConfig: + description: |- + podDnsConfig defines the DNS parameters of a pod in addition to + those generated from DNSPolicy. + https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-dns-config + properties: + nameservers: + description: |- + A list of DNS name server IP addresses. + This will be appended to the base nameservers generated from DNSPolicy. + Duplicated nameservers will be removed. + items: + type: string + type: array + x-kubernetes-list-type: atomic + options: + description: |- + A list of DNS resolver options. + This will be merged with the base options generated from DNSPolicy. + Duplicated entries will be removed. Resolution options given in Options + will override those that appear in the base DNSPolicy. + items: + description: PodDNSConfigOption defines DNS resolver options + of a pod. properties: - claims: + name: 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: + Name is this DNS resolver option's name. + Required. + type: string + value: + description: Value is this DNS resolver option's value. + type: string + type: object + type: array + x-kubernetes-list-type: atomic + searches: + description: |- + A list of DNS search domains for host-name lookup. + This will be appended to the base search paths generated from DNSPolicy. + Duplicated search paths will be removed. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + podDnsPolicy: + description: |- + podDnsPolicy defines how a pod's DNS will be configured. + https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-s-dns-policy + type: string + resourceAnnotations: + additionalProperties: + type: string + description: |- + resourceAnnotations defines annotations that will be applied to all resources managed by the DPA. + Useful for GitOps tools like ArgoCD (e.g., argocd.argoproj.io/ignore-resource-updates: 'true'). + type: object + resourceLabels: + additionalProperties: + type: string + description: |- + resourceLabels defines labels that will be applied to all resources managed by the DPA. + These labels are merged with OADP-required labels. User-provided labels cannot override + core operator labels (app.kubernetes.io/*, openshift.io/oadp). + type: object + snapshotLocations: + description: snapshotLocations defines the list of desired configuration + to use for VolumeSnapshotLocations + items: + description: SnapshotLocation defines the configuration for the + DPA snapshot store + properties: + name: + type: string + velero: + description: VolumeSnapshotLocationSpec defines the specification + for a Velero VolumeSnapshotLocation. + properties: + config: 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: string + description: Config is for provider-specific configuration + fields. 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/ + credential: + description: Credential contains the credential information + intended to be used with this location + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key type: object + x-kubernetes-map-type: atomic + provider: + description: Provider is the provider of the volume storage. + type: string + required: + - provider type: object + required: + - velero type: object - required: - - configuration - type: object - status: - description: DataProtectionApplicationStatus defines the observed state of DataProtectionApplication - properties: - conditions: - description: Conditions defines the observed state of DataProtectionApplication - items: - description: Condition contains details for one aspect of the current state of this API Resource. + type: array + unsupportedOverrides: + additionalProperties: + type: string + description: |- + unsupportedOverrides can be used to override images used in deployments. + Available keys are: + - veleroImageFqin + - awsPluginImageFqin + - legacyAWSPluginImageFqin + - openshiftPluginImageFqin + - azurePluginImageFqin + - gcpPluginImageFqin + - kubevirtPluginImageFqin + - kubevirtDatamoverPluginImageFqin + - hypershiftPluginImageFqin + - nonAdminControllerImageFqin + - vmFileRestoreControllerImageFqin + - vmFileRestoreAccessImageFqin + - vmFileRestoreSSHImageFqin + - vmFileRestoreBrowserImageFqin + - kubevirtAnnotationsRemoverImageFqin + - operator-type + - tech-preview-ack + type: object + vmFileRestore: + description: vmFileRestore defines the configuration for the DPA to + enable VM file restore feature + properties: + enable: + description: |- + Enable flag to deploy VM file restore controller + By default is disabled + type: boolean + resources: + description: Resource requirements for the VM file restore controller 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: + claims: description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: + 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: |- - 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: + 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: |- - 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 + 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 - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} + type: object + required: + - configuration + type: object + status: + description: DataProtectionApplicationStatus defines the observed state + of DataProtectionApplication + properties: + conditions: + description: Conditions defines the observed state of DataProtectionApplication + 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 + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml index 1b5b0efea5..f50360f9a3 100644 --- a/config/manager/manager.yaml +++ b/config/manager/manager.yaml @@ -96,6 +96,8 @@ spec: value: quay.io/konveyor/oadp-vmfr-access-sshd:latest - name: RELATED_IMAGE_VM_FILE_RESTORE_BROWSER value: quay.io/konveyor/oadp-vmfr-access-filebrowser:latest + - name: RELATED_IMAGE_KUBEVIRT_ANNOTATIONS_REMOVER + value: quay.io/migtools/kubevirt-velero-annotations-remover-go:latest - name: RELATED_IMAGE_CONSOLE_CLI_DOWNLOAD value: quay.io/konveyor/oadp-cli-binaries:latest args: diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index be00e6d710..42628544df 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -35,6 +35,18 @@ rules: - patch - update - watch +- apiGroups: + - admissionregistration.k8s.io + resources: + - mutatingwebhookconfigurations + verbs: + - create + - delete + - get + - list + - patch + - update + - watch - apiGroups: - apps resources: diff --git a/internal/controller/dataprotectionapplication_controller.go b/internal/controller/dataprotectionapplication_controller.go index c49c7e97eb..2f930d6fb6 100644 --- a/internal/controller/dataprotectionapplication_controller.go +++ b/internal/controller/dataprotectionapplication_controller.go @@ -115,6 +115,7 @@ func (r *DataProtectionApplicationReconciler) Reconcile(ctx context.Context, req r.ReconcileVeleroMetricsSVC, r.ReconcileNonAdminController, r.ReconcileVMFileRestoreController, + r.ReconcileKubevirtAnnotationsRemover, ) if err != nil { diff --git a/internal/controller/kubevirt_annotations_remover.go b/internal/controller/kubevirt_annotations_remover.go new file mode 100644 index 0000000000..c44f0aed47 --- /dev/null +++ b/internal/controller/kubevirt_annotations_remover.go @@ -0,0 +1,509 @@ +package controller + +import ( + "fmt" + "os" + + "github.com/go-logr/logr" + admissionregistrationv1 "k8s.io/api/admissionregistration/v1" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + k8serror "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + oadpv1alpha1 "github.com/openshift/oadp-operator/api/v1alpha1" + "github.com/openshift/oadp-operator/pkg/common" +) + +const ( + kubevirtAnnotationsRemoverName = "kubevirt-velero-annotations-remover" + kubevirtAnnotationsRemoverTLSSecret = "kubevirt-annotations-remover-tls" + kubevirtAnnotationsRemoverWebhookPort = int32(8443) +) + +var ( + kubevirtAnnotationsRemoverAppLabel = map[string]string{ + "app": kubevirtAnnotationsRemoverName, + } + kubevirtAnnotationsRemoverDeploymentLabels = map[string]string{ + "app": kubevirtAnnotationsRemoverName, + "app.kubernetes.io/component": "webhook", + "app.kubernetes.io/created-by": common.OADPOperator, + "app.kubernetes.io/instance": kubevirtAnnotationsRemoverName, + "app.kubernetes.io/managed-by": common.OADPOperator, + "app.kubernetes.io/name": kubevirtAnnotationsRemoverName, + "app.kubernetes.io/part-of": common.OADPOperator, + } +) + +//+kubebuilder:rbac:groups=admissionregistration.k8s.io,resources=mutatingwebhookconfigurations,verbs=get;list;watch;create;update;patch;delete + +// ReconcileKubevirtAnnotationsRemover manages the kubevirt-velero-annotations-remover +// webhook deployment, service, and MutatingWebhookConfiguration. +func (r *DataProtectionApplicationReconciler) ReconcileKubevirtAnnotationsRemover(log logr.Logger) (bool, error) { + if !r.checkKubevirtAnnotationsRemoverEnabled() { + return r.cleanupKubevirtAnnotationsRemover(log) + } + + // Reconcile Service first (triggers TLS secret creation via OpenShift Service CA) + if err := r.reconcileKubevirtAnnotationsRemoverService(log); err != nil { + return false, err + } + + // Reconcile Deployment + if err := r.reconcileKubevirtAnnotationsRemoverDeployment(log); err != nil { + return false, err + } + + // Reconcile MutatingWebhookConfiguration (cluster-scoped) + if err := r.reconcileKubevirtAnnotationsRemoverWebhook(log); err != nil { + return false, err + } + + return true, nil +} + +// cleanupKubevirtAnnotationsRemover removes all resources when the feature is disabled. +func (r *DataProtectionApplicationReconciler) cleanupKubevirtAnnotationsRemover(log logr.Logger) (bool, error) { + // Delete MutatingWebhookConfiguration (cluster-scoped, must be deleted by name) + webhookConfig := &admissionregistrationv1.MutatingWebhookConfiguration{} + if err := r.Get( + r.Context, + types.NamespacedName{Name: kubevirtAnnotationsRemoverName}, + webhookConfig, + ); err != nil { + if !k8serror.IsNotFound(err) { + return false, err + } + } else { + if err := r.Delete(r.Context, webhookConfig); err != nil && !k8serror.IsNotFound(err) { + r.EventRecorder.Event( + webhookConfig, + corev1.EventTypeWarning, + "KubevirtAnnotationsRemoverWebhookDeleteFailed", + fmt.Sprintf("Could not delete MutatingWebhookConfiguration %s: %s", kubevirtAnnotationsRemoverName, err), + ) + return false, err + } + r.EventRecorder.Event( + webhookConfig, + corev1.EventTypeNormal, + "KubevirtAnnotationsRemoverWebhookDeleteSucceed", + fmt.Sprintf("MutatingWebhookConfiguration %s deleted", kubevirtAnnotationsRemoverName), + ) + } + + // Delete Deployment (namespace-scoped) + deployment := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: kubevirtAnnotationsRemoverName, + Namespace: r.NamespacedName.Namespace, + }, + } + if err := r.Get( + r.Context, + types.NamespacedName{ + Name: deployment.Name, + Namespace: deployment.Namespace, + }, + deployment, + ); err != nil { + if !k8serror.IsNotFound(err) { + return false, err + } + } else { + if err := r.Delete( + r.Context, + deployment, + &client.DeleteOptions{PropagationPolicy: ptr.To(metav1.DeletePropagationForeground)}, + ); err != nil && !k8serror.IsNotFound(err) { + r.EventRecorder.Event( + deployment, + corev1.EventTypeWarning, + "KubevirtAnnotationsRemoverDeploymentDeleteFailed", + fmt.Sprintf("Could not delete deployment %s/%s: %s", deployment.Namespace, deployment.Name, err), + ) + return false, err + } + r.EventRecorder.Event( + deployment, + corev1.EventTypeNormal, + "KubevirtAnnotationsRemoverDeploymentDeleteSucceed", + fmt.Sprintf("Deployment %s/%s deleted", deployment.Namespace, deployment.Name), + ) + } + + // Delete Service (namespace-scoped) + svc := &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: kubevirtAnnotationsRemoverName, + Namespace: r.NamespacedName.Namespace, + }, + } + if err := r.Get( + r.Context, + types.NamespacedName{ + Name: svc.Name, + Namespace: svc.Namespace, + }, + svc, + ); err != nil { + if !k8serror.IsNotFound(err) { + return false, err + } + } else { + if err := r.Delete(r.Context, svc); err != nil && !k8serror.IsNotFound(err) { + r.EventRecorder.Event( + svc, + corev1.EventTypeWarning, + "KubevirtAnnotationsRemoverServiceDeleteFailed", + fmt.Sprintf("Could not delete service %s/%s: %s", svc.Namespace, svc.Name, err), + ) + return false, err + } + r.EventRecorder.Event( + svc, + corev1.EventTypeNormal, + "KubevirtAnnotationsRemoverServiceDeleteSucceed", + fmt.Sprintf("Service %s/%s deleted", svc.Namespace, svc.Name), + ) + } + + return true, nil +} + +// reconcileKubevirtAnnotationsRemoverService creates or updates the Service +// with OpenShift Service CA annotation for TLS certificate generation. +func (r *DataProtectionApplicationReconciler) reconcileKubevirtAnnotationsRemoverService(log logr.Logger) error { + svc := &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: kubevirtAnnotationsRemoverName, + Namespace: r.NamespacedName.Namespace, + }, + } + + op, err := controllerutil.CreateOrPatch(r.Context, r.Client, svc, func() error { + // Set annotations for OpenShift Service CA TLS certificate generation + if svc.Annotations == nil { + svc.Annotations = make(map[string]string) + } + svc.Annotations["service.beta.openshift.io/serving-cert-secret-name"] = kubevirtAnnotationsRemoverTLSSecret + + // Set labels + if svc.Labels == nil { + svc.Labels = make(map[string]string) + } + for k, v := range kubevirtAnnotationsRemoverAppLabel { + svc.Labels[k] = v + } + + // Set spec + svc.Spec.Selector = kubevirtAnnotationsRemoverAppLabel + svc.Spec.Type = corev1.ServiceTypeClusterIP + svc.Spec.Ports = []corev1.ServicePort{ + { + Protocol: corev1.ProtocolTCP, + Port: 443, + TargetPort: intstr.FromInt32(kubevirtAnnotationsRemoverWebhookPort), + }, + } + + // Apply user-provided resource labels and annotations + svc.Labels = applyResourceLabels(r.dpa, svc.Labels) + svc.Annotations = applyResourceAnnotations(r.dpa, svc.Annotations) + + return controllerutil.SetControllerReference(r.dpa, svc, r.Scheme) + }) + if err != nil { + return err + } + + if op != controllerutil.OperationResultNone { + r.EventRecorder.Event( + svc, + corev1.EventTypeNormal, + "KubevirtAnnotationsRemoverServiceReconciled", + fmt.Sprintf("Service %s/%s %s", svc.Namespace, svc.Name, op), + ) + } + + return nil +} + +// reconcileKubevirtAnnotationsRemoverDeployment creates or updates the webhook Deployment. +func (r *DataProtectionApplicationReconciler) reconcileKubevirtAnnotationsRemoverDeployment(log logr.Logger) error { + deployment := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: kubevirtAnnotationsRemoverName, + Namespace: r.NamespacedName.Namespace, + }, + } + + op, err := controllerutil.CreateOrUpdate(r.Context, r.Client, deployment, func() error { + if err := r.buildKubevirtAnnotationsRemoverDeployment(deployment); err != nil { + return err + } + return controllerutil.SetControllerReference(r.dpa, deployment, r.Scheme) + }) + if err != nil { + return err + } + + if op != controllerutil.OperationResultNone { + r.EventRecorder.Event( + deployment, + corev1.EventTypeNormal, + "KubevirtAnnotationsRemoverDeploymentReconciled", + fmt.Sprintf("Deployment %s/%s %s", deployment.Namespace, deployment.Name, op), + ) + } + + return nil +} + +// buildKubevirtAnnotationsRemoverDeployment populates the Deployment spec. +func (r *DataProtectionApplicationReconciler) buildKubevirtAnnotationsRemoverDeployment(deploymentObject *appsv1.Deployment) error { + image := r.getKubevirtAnnotationsRemoverImage() + imagePullPolicy, err := common.GetImagePullPolicy(r.dpa.Spec.ImagePullPolicy, image) + if err != nil { + r.Log.Error(err, "imagePullPolicy regex failed") + } + + // Set labels + deploymentObjectLabels := deploymentObject.GetLabels() + if deploymentObjectLabels == nil { + deploymentObject.SetLabels(make(map[string]string)) + deploymentObjectLabels = deploymentObject.GetLabels() + } + for k, v := range kubevirtAnnotationsRemoverDeploymentLabels { + deploymentObjectLabels[k] = v + } + deploymentObject.SetLabels(deploymentObjectLabels) + + // Set spec + deploymentObject.Spec.Replicas = ptr.To(int32(1)) + deploymentObject.Spec.Selector = &metav1.LabelSelector{ + MatchLabels: kubevirtAnnotationsRemoverAppLabel, + } + + // Template labels + templateLabels := deploymentObject.Spec.Template.GetLabels() + if templateLabels == nil { + templateLabels = make(map[string]string) + } + for k, v := range kubevirtAnnotationsRemoverAppLabel { + templateLabels[k] = v + } + deploymentObject.Spec.Template.SetLabels(templateLabels) + + // Pod security context + if deploymentObject.Spec.Template.Spec.SecurityContext == nil { + deploymentObject.Spec.Template.Spec.SecurityContext = &corev1.PodSecurityContext{ + RunAsNonRoot: ptr.To(true), + RunAsUser: ptr.To(int64(1001)), + FSGroup: ptr.To(int64(1001)), + SeccompProfile: &corev1.SeccompProfile{ + Type: corev1.SeccompProfileTypeRuntimeDefault, + }, + } + } + + // Container spec + containerSpec := corev1.Container{ + Name: "webhook", + Image: image, + ImagePullPolicy: imagePullPolicy, + Ports: []corev1.ContainerPort{ + { + Name: "https", + ContainerPort: kubevirtAnnotationsRemoverWebhookPort, + Protocol: corev1.ProtocolTCP, + }, + }, + VolumeMounts: []corev1.VolumeMount{ + { + Name: "tls", + MountPath: "/tls", + ReadOnly: true, + }, + }, + SecurityContext: &corev1.SecurityContext{ + RunAsNonRoot: ptr.To(true), + AllowPrivilegeEscalation: ptr.To(false), + Capabilities: &corev1.Capabilities{ + Drop: []corev1.Capability{"ALL"}, + }, + }, + TerminationMessagePolicy: corev1.TerminationMessageFallbackToLogsOnError, + } + + webhookContainerFound := false + if len(deploymentObject.Spec.Template.Spec.Containers) == 0 { + deploymentObject.Spec.Template.Spec.Containers = []corev1.Container{containerSpec} + webhookContainerFound = true + } else { + for index, container := range deploymentObject.Spec.Template.Spec.Containers { + if container.Name == "webhook" { + c := &deploymentObject.Spec.Template.Spec.Containers[index] + c.Image = image + c.ImagePullPolicy = imagePullPolicy + c.Ports = containerSpec.Ports + c.VolumeMounts = containerSpec.VolumeMounts + c.SecurityContext = containerSpec.SecurityContext + c.TerminationMessagePolicy = containerSpec.TerminationMessagePolicy + webhookContainerFound = true + break + } + } + } + if !webhookContainerFound { + return fmt.Errorf("could not find webhook container in kubevirt-velero-annotations-remover Deployment") + } + + // Volumes + deploymentObject.Spec.Template.Spec.Volumes = []corev1.Volume{ + { + Name: "tls", + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: kubevirtAnnotationsRemoverTLSSecret, + }, + }, + }, + } + + deploymentObject.Spec.Template.Spec.RestartPolicy = corev1.RestartPolicyAlways + deploymentObject.Spec.Template.Spec.ServiceAccountName = common.Velero + + // Apply user-provided resource labels (protected labels are filtered) + deploymentObject.Labels = applyResourceLabels(r.dpa, deploymentObject.Labels) + deploymentObject.Spec.Template.Labels = applyResourceLabels(r.dpa, deploymentObject.Spec.Template.Labels) + + // Re-assert selector labels to ensure template labels match selector + if deploymentObject.Spec.Selector != nil && deploymentObject.Spec.Selector.MatchLabels != nil { + if deploymentObject.Spec.Template.Labels == nil { + deploymentObject.Spec.Template.Labels = make(map[string]string) + } + for k, v := range deploymentObject.Spec.Selector.MatchLabels { + deploymentObject.Spec.Template.Labels[k] = v + } + } + + // Apply user-provided resource annotations + deploymentObject.Annotations = applyResourceAnnotations(r.dpa, deploymentObject.Annotations) + deploymentObject.Spec.Template.Annotations = applyResourceAnnotations(r.dpa, deploymentObject.Spec.Template.Annotations) + + return nil +} + +// reconcileKubevirtAnnotationsRemoverWebhook creates or updates the MutatingWebhookConfiguration. +// This is a cluster-scoped resource, so it cannot have an owner reference to the namespace-scoped DPA. +// Instead, it is managed by label-based tracking with a fixed name. +func (r *DataProtectionApplicationReconciler) reconcileKubevirtAnnotationsRemoverWebhook(log logr.Logger) error { + webhookConfig := &admissionregistrationv1.MutatingWebhookConfiguration{ + ObjectMeta: metav1.ObjectMeta{ + Name: kubevirtAnnotationsRemoverName, + }, + } + + failurePolicy := admissionregistrationv1.Ignore + sideEffects := admissionregistrationv1.SideEffectClassNone + webhookPath := "/mutate" + + op, err := controllerutil.CreateOrUpdate(r.Context, r.Client, webhookConfig, func() error { + // Set labels for tracking (cannot use owner reference for cluster-scoped resources) + if webhookConfig.Labels == nil { + webhookConfig.Labels = make(map[string]string) + } + webhookConfig.Labels[oadpv1alpha1.OadpOperatorLabel] = "True" + webhookConfig.Labels["app.kubernetes.io/managed-by"] = common.OADPOperator + webhookConfig.Labels["app.kubernetes.io/instance"] = kubevirtAnnotationsRemoverName + + // Set annotation for OpenShift Service CA bundle injection + if webhookConfig.Annotations == nil { + webhookConfig.Annotations = make(map[string]string) + } + webhookConfig.Annotations["service.beta.openshift.io/inject-cabundle"] = "true" + + webhookConfig.Webhooks = []admissionregistrationv1.MutatingWebhook{ + { + Name: fmt.Sprintf("%s.%s.svc", kubevirtAnnotationsRemoverName, r.NamespacedName.Namespace), + AdmissionReviewVersions: []string{"v1"}, + FailurePolicy: &failurePolicy, + SideEffects: &sideEffects, + ClientConfig: admissionregistrationv1.WebhookClientConfig{ + Service: &admissionregistrationv1.ServiceReference{ + Name: kubevirtAnnotationsRemoverName, + Namespace: r.NamespacedName.Namespace, + Path: &webhookPath, + Port: ptr.To(int32(443)), + }, + }, + Rules: []admissionregistrationv1.RuleWithOperations{ + { + Operations: []admissionregistrationv1.OperationType{ + admissionregistrationv1.Create, + admissionregistrationv1.Update, + }, + Rule: admissionregistrationv1.Rule{ + APIGroups: []string{""}, + APIVersions: []string{"v1"}, + Resources: []string{"pods"}, + }, + }, + }, + ObjectSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "kubevirt.io": "virt-launcher", + }, + }, + }, + } + + return nil + }) + if err != nil { + return err + } + + if op != controllerutil.OperationResultNone { + r.EventRecorder.Event( + webhookConfig, + corev1.EventTypeNormal, + "KubevirtAnnotationsRemoverWebhookReconciled", + fmt.Sprintf("MutatingWebhookConfiguration %s %s", kubevirtAnnotationsRemoverName, op), + ) + } + + return nil +} + +// checkKubevirtAnnotationsRemoverEnabled returns true if the feature is enabled in the DPA spec. +func (r *DataProtectionApplicationReconciler) checkKubevirtAnnotationsRemoverEnabled() bool { + if r.dpa.Spec.KubevirtAnnotationsRemover != nil && r.dpa.Spec.KubevirtAnnotationsRemover.Enable != nil { + return *r.dpa.Spec.KubevirtAnnotationsRemover.Enable + } + return false +} + +// getKubevirtAnnotationsRemoverImage returns the image to use for the webhook, +// following the standard UnsupportedOverrides -> RELATED_IMAGE -> default pattern. +func (r *DataProtectionApplicationReconciler) getKubevirtAnnotationsRemoverImage() string { + dpa := r.dpa + unsupportedOverride := dpa.Spec.UnsupportedOverrides[oadpv1alpha1.KubevirtAnnotationsRemoverImageKey] + if unsupportedOverride != "" { + return unsupportedOverride + } + + environmentVariable := os.Getenv("RELATED_IMAGE_KUBEVIRT_ANNOTATIONS_REMOVER") + if environmentVariable != "" { + return environmentVariable + } + + return "quay.io/migtools/kubevirt-velero-annotations-remover-go:latest" +} diff --git a/internal/controller/kubevirt_annotations_remover_test.go b/internal/controller/kubevirt_annotations_remover_test.go new file mode 100644 index 0000000000..131b6a3d54 --- /dev/null +++ b/internal/controller/kubevirt_annotations_remover_test.go @@ -0,0 +1,543 @@ +package controller + +import ( + "context" + "os" + "testing" + + "github.com/go-logr/logr" + "github.com/onsi/ginkgo/v2" + "github.com/onsi/gomega" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/tools/record" + "k8s.io/utils/ptr" + + oadpv1alpha1 "github.com/openshift/oadp-operator/api/v1alpha1" +) + +const ( + defaultKubevirtAnnotationsRemoverImage = "quay.io/migtools/kubevirt-velero-annotations-remover-go:latest" +) + +type ReconcileKubevirtAnnotationsRemoverScenario struct { + namespace string + dpa string + errMessage string + eventWords []string + enabled bool + deployment *appsv1.Deployment +} + +func createTestKubevirtAnnotationsRemoverDeployment(namespace string) *appsv1.Deployment { + return &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: kubevirtAnnotationsRemoverName, + Namespace: namespace, + Labels: map[string]string{ + "test": "test", + "app": "wrong", + }, + }, + Spec: appsv1.DeploymentSpec{ + Replicas: ptr.To(int32(2)), + Selector: &metav1.LabelSelector{ + MatchLabels: kubevirtAnnotationsRemoverAppLabel, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: kubevirtAnnotationsRemoverAppLabel, + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "webhook", + Image: "wrong", + }, + }, + ServiceAccountName: "wrong-one", + }, + }, + }, + } +} + +func runReconcileKubevirtAnnotationsRemoverTest( + scenario ReconcileKubevirtAnnotationsRemoverScenario, + updateTestScenario func(scenario ReconcileKubevirtAnnotationsRemoverScenario), + ctx context.Context, + imageEnvValue string, +) { + updateTestScenario(scenario) + + namespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: scenario.namespace, + }, + } + gomega.Expect(k8sClient.Create(ctx, namespace)).To(gomega.Succeed()) + + dpa := &oadpv1alpha1.DataProtectionApplication{ + ObjectMeta: metav1.ObjectMeta{ + Name: scenario.dpa, + Namespace: scenario.namespace, + }, + Spec: oadpv1alpha1.DataProtectionApplicationSpec{ + Configuration: &oadpv1alpha1.ApplicationConfig{ + Velero: &oadpv1alpha1.VeleroConfig{}, + }, + KubevirtAnnotationsRemover: &oadpv1alpha1.KubevirtAnnotationsRemover{ + Enable: ptr.To(scenario.enabled), + }, + }, + } + gomega.Expect(k8sClient.Create(ctx, dpa)).To(gomega.Succeed()) + + if scenario.deployment != nil { + gomega.Expect(k8sClient.Create(ctx, scenario.deployment)).To(gomega.Succeed()) + } + + os.Setenv("RELATED_IMAGE_KUBEVIRT_ANNOTATIONS_REMOVER", imageEnvValue) + + event := record.NewFakeRecorder(10) + r := &DataProtectionApplicationReconciler{ + Client: k8sClient, + Scheme: testEnv.Scheme, + Context: ctx, + NamespacedName: types.NamespacedName{ + Name: scenario.dpa, + Namespace: scenario.namespace, + }, + EventRecorder: event, + dpa: dpa, + } + result, err := r.ReconcileKubevirtAnnotationsRemover(logr.Discard()) + + if len(scenario.errMessage) == 0 { + gomega.Expect(result).To(gomega.BeTrue()) + gomega.Expect(err).To(gomega.Not(gomega.HaveOccurred())) + } else { + gomega.Expect(result).To(gomega.BeFalse()) + gomega.Expect(err).To(gomega.HaveOccurred()) + gomega.Expect(err.Error()).To(gomega.ContainSubstring(scenario.errMessage)) + } + + if scenario.eventWords != nil { + gomega.Expect(len(event.Events)).To(gomega.BeNumerically(">=", 1)) + message := <-event.Events + for _, word := range scenario.eventWords { + gomega.Expect(message).To(gomega.ContainSubstring(word)) + } + } +} + +var _ = ginkgo.Describe("Test ReconcileKubevirtAnnotationsRemover function", func() { + var ( + ctx = context.Background() + currentTestScenario ReconcileKubevirtAnnotationsRemoverScenario + updateTestScenario = func(scenario ReconcileKubevirtAnnotationsRemoverScenario) { + currentTestScenario = scenario + } + ) + + ginkgo.AfterEach(func() { + os.Unsetenv("RELATED_IMAGE_KUBEVIRT_ANNOTATIONS_REMOVER") + + deployment := &appsv1.Deployment{} + if k8sClient.Get( + ctx, + types.NamespacedName{ + Name: kubevirtAnnotationsRemoverName, + Namespace: currentTestScenario.namespace, + }, + deployment, + ) == nil { + gomega.Expect(k8sClient.Delete(ctx, deployment)).To(gomega.Succeed()) + } + + svc := &corev1.Service{} + if k8sClient.Get( + ctx, + types.NamespacedName{ + Name: kubevirtAnnotationsRemoverName, + Namespace: currentTestScenario.namespace, + }, + svc, + ) == nil { + gomega.Expect(k8sClient.Delete(ctx, svc)).To(gomega.Succeed()) + } + + dpa := &oadpv1alpha1.DataProtectionApplication{ + ObjectMeta: metav1.ObjectMeta{ + Name: currentTestScenario.dpa, + Namespace: currentTestScenario.namespace, + }, + } + gomega.Expect(k8sClient.Delete(ctx, dpa)).To(gomega.Succeed()) + + namespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: currentTestScenario.namespace, + }, + } + gomega.Expect(k8sClient.Delete(ctx, namespace)).To(gomega.Succeed()) + }) + + ginkgo.DescribeTable("Reconcile is true", + func(scenario ReconcileKubevirtAnnotationsRemoverScenario) { + runReconcileKubevirtAnnotationsRemoverTest( + scenario, + updateTestScenario, + ctx, + defaultKubevirtAnnotationsRemoverImage, + ) + }, + ginkgo.Entry("Should create kubevirt annotations remover resources", ReconcileKubevirtAnnotationsRemoverScenario{ + namespace: "kar-test-1", + dpa: "kar-test-1-dpa", + eventWords: []string{"Normal", "KubevirtAnnotationsRemoverServiceReconciled", "created"}, + enabled: true, + }), + ginkgo.Entry("Should update kubevirt annotations remover deployment", ReconcileKubevirtAnnotationsRemoverScenario{ + namespace: "kar-test-2", + dpa: "kar-test-2-dpa", + eventWords: []string{"Normal", "KubevirtAnnotationsRemoverServiceReconciled"}, + enabled: true, + deployment: createTestKubevirtAnnotationsRemoverDeployment("kar-test-2"), + }), + ginkgo.Entry("Should do nothing when disabled and no resources exist", ReconcileKubevirtAnnotationsRemoverScenario{ + namespace: "kar-test-3", + dpa: "kar-test-3-dpa", + enabled: false, + }), + ginkgo.Entry("Should delete resources when disabled", ReconcileKubevirtAnnotationsRemoverScenario{ + namespace: "kar-test-4", + dpa: "kar-test-4-dpa", + eventWords: []string{"Normal", "KubevirtAnnotationsRemoverDeploymentDeleteSucceed"}, + enabled: false, + deployment: createTestKubevirtAnnotationsRemoverDeployment("kar-test-4"), + }), + ) + + ginkgo.DescribeTable("Reconcile is false", + func(scenario ReconcileKubevirtAnnotationsRemoverScenario) { + runReconcileKubevirtAnnotationsRemoverTest( + scenario, + updateTestScenario, + ctx, + defaultKubevirtAnnotationsRemoverImage, + ) + }, + ginkgo.Entry("Should error because webhook container was not found in Deployment", ReconcileKubevirtAnnotationsRemoverScenario{ + namespace: "kar-test-error-1", + dpa: "kar-test-error-1-dpa", + errMessage: "could not find webhook container in kubevirt-velero-annotations-remover Deployment", + enabled: true, + deployment: &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: kubevirtAnnotationsRemoverName, + Namespace: "kar-test-error-1", + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: kubevirtAnnotationsRemoverAppLabel, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: kubevirtAnnotationsRemoverAppLabel, + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{{ + Name: "wrong-name", + Image: defaultKubevirtAnnotationsRemoverImage, + }}, + }, + }, + }, + }, + }), + ) +}) + +func TestCheckKubevirtAnnotationsRemoverEnabled(t *testing.T) { + tests := []struct { + name string + config *oadpv1alpha1.KubevirtAnnotationsRemover + expectedResult bool + }{ + { + name: "Should return false when KubevirtAnnotationsRemover is nil", + config: nil, + expectedResult: false, + }, + { + name: "Should return false when Enable is nil", + config: &oadpv1alpha1.KubevirtAnnotationsRemover{ + Enable: nil, + }, + expectedResult: false, + }, + { + name: "Should return false when Enable is false", + config: &oadpv1alpha1.KubevirtAnnotationsRemover{ + Enable: ptr.To(false), + }, + expectedResult: false, + }, + { + name: "Should return true when Enable is true", + config: &oadpv1alpha1.KubevirtAnnotationsRemover{ + Enable: ptr.To(true), + }, + expectedResult: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + dpa := &oadpv1alpha1.DataProtectionApplication{ + Spec: oadpv1alpha1.DataProtectionApplicationSpec{ + KubevirtAnnotationsRemover: tt.config, + }, + } + + r := &DataProtectionApplicationReconciler{dpa: dpa} + result := r.checkKubevirtAnnotationsRemoverEnabled() + + if result != tt.expectedResult { + t.Errorf("expected %v, got %v", tt.expectedResult, result) + } + }) + } +} + +func TestGetKubevirtAnnotationsRemoverImage(t *testing.T) { + tests := []struct { + name string + envValue string + overrideValue string + expectedResult string + }{ + { + name: "Should return override value when set", + envValue: "env-image:v1", + overrideValue: "override-image:v1", + expectedResult: "override-image:v1", + }, + { + name: "Should return env value when override not set", + envValue: "env-image:v1", + overrideValue: "", + expectedResult: "env-image:v1", + }, + { + name: "Should return default when neither set", + envValue: "", + overrideValue: "", + expectedResult: defaultKubevirtAnnotationsRemoverImage, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.envValue != "" { + os.Setenv("RELATED_IMAGE_KUBEVIRT_ANNOTATIONS_REMOVER", tt.envValue) + defer os.Unsetenv("RELATED_IMAGE_KUBEVIRT_ANNOTATIONS_REMOVER") + } else { + os.Unsetenv("RELATED_IMAGE_KUBEVIRT_ANNOTATIONS_REMOVER") + } + + dpa := &oadpv1alpha1.DataProtectionApplication{ + Spec: oadpv1alpha1.DataProtectionApplicationSpec{}, + } + + if tt.overrideValue != "" { + dpa.Spec.UnsupportedOverrides = map[oadpv1alpha1.UnsupportedImageKey]string{ + oadpv1alpha1.KubevirtAnnotationsRemoverImageKey: tt.overrideValue, + } + } + + r := &DataProtectionApplicationReconciler{dpa: dpa} + result := r.getKubevirtAnnotationsRemoverImage() + + if result != tt.expectedResult { + t.Errorf("expected %s, got %s", tt.expectedResult, result) + } + }) + } +} + +func TestBuildKubevirtAnnotationsRemoverDeployment(t *testing.T) { + tests := []struct { + name string + dpa *oadpv1alpha1.DataProtectionApplication + expectedImage string + expectedReplicas int32 + expectedSAName string + expectError bool + errorContains string + }{ + { + name: "Should build deployment with default image", + dpa: &oadpv1alpha1.DataProtectionApplication{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-dpa", + Namespace: "test-namespace", + ResourceVersion: "12345", + }, + Spec: oadpv1alpha1.DataProtectionApplicationSpec{ + KubevirtAnnotationsRemover: &oadpv1alpha1.KubevirtAnnotationsRemover{ + Enable: ptr.To(true), + }, + Configuration: &oadpv1alpha1.ApplicationConfig{ + Velero: &oadpv1alpha1.VeleroConfig{}, + }, + }, + }, + expectedImage: defaultKubevirtAnnotationsRemoverImage, + expectedReplicas: 1, + expectedSAName: "velero", + expectError: false, + }, + { + name: "Should use override image from unsupportedOverrides", + dpa: &oadpv1alpha1.DataProtectionApplication{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-dpa", + Namespace: "test-namespace", + ResourceVersion: "12345", + }, + Spec: oadpv1alpha1.DataProtectionApplicationSpec{ + KubevirtAnnotationsRemover: &oadpv1alpha1.KubevirtAnnotationsRemover{ + Enable: ptr.To(true), + }, + UnsupportedOverrides: map[oadpv1alpha1.UnsupportedImageKey]string{ + oadpv1alpha1.KubevirtAnnotationsRemoverImageKey: "custom-registry.io/kar:v1.0", + }, + Configuration: &oadpv1alpha1.ApplicationConfig{ + Velero: &oadpv1alpha1.VeleroConfig{}, + }, + }, + }, + expectedImage: "custom-registry.io/kar:v1.0", + expectedReplicas: 1, + expectedSAName: "velero", + expectError: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + os.Unsetenv("RELATED_IMAGE_KUBEVIRT_ANNOTATIONS_REMOVER") + + r := &DataProtectionApplicationReconciler{ + dpa: tt.dpa, + } + + deployment := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: kubevirtAnnotationsRemoverName, + Namespace: tt.dpa.Namespace, + }, + } + + err := r.buildKubevirtAnnotationsRemoverDeployment(deployment) + + if tt.expectError { + if err == nil { + t.Errorf("expected error but got none") + } else if tt.errorContains != "" && !containsStr(err.Error(), tt.errorContains) { + t.Errorf("expected error to contain '%s', got: %v", tt.errorContains, err) + } + return + } + + if err != nil { + t.Errorf("unexpected error: %v", err) + return + } + + // Verify deployment spec + if *deployment.Spec.Replicas != tt.expectedReplicas { + t.Errorf("replicas: expected %d, got %d", tt.expectedReplicas, *deployment.Spec.Replicas) + } + + if deployment.Spec.Template.Spec.ServiceAccountName != tt.expectedSAName { + t.Errorf("serviceAccountName: expected %s, got %s", tt.expectedSAName, deployment.Spec.Template.Spec.ServiceAccountName) + } + + // Verify container exists and has correct image + if len(deployment.Spec.Template.Spec.Containers) == 0 { + t.Fatalf("no containers found in deployment") + } + + container := deployment.Spec.Template.Spec.Containers[0] + if container.Name != "webhook" { + t.Errorf("container name: expected 'webhook', got %s", container.Name) + } + + if container.Image != tt.expectedImage { + t.Errorf("container image: expected %s, got %s", tt.expectedImage, container.Image) + } + + // Verify TLS volume mount + foundTLSMount := false + for _, vm := range container.VolumeMounts { + if vm.Name == "tls" && vm.MountPath == "/tls" && vm.ReadOnly { + foundTLSMount = true + break + } + } + if !foundTLSMount { + t.Error("expected TLS volume mount at /tls") + } + + // Verify TLS volume + foundTLSVolume := false + for _, v := range deployment.Spec.Template.Spec.Volumes { + if v.Name == "tls" && v.Secret != nil && v.Secret.SecretName == kubevirtAnnotationsRemoverTLSSecret { + foundTLSVolume = true + break + } + } + if !foundTLSVolume { + t.Error("expected TLS volume with secret") + } + + // Verify security context + if deployment.Spec.Template.Spec.SecurityContext.RunAsNonRoot == nil || !*deployment.Spec.Template.Spec.SecurityContext.RunAsNonRoot { + t.Error("expected runAsNonRoot to be true") + } + + if container.SecurityContext.AllowPrivilegeEscalation == nil || *container.SecurityContext.AllowPrivilegeEscalation { + t.Error("expected allowPrivilegeEscalation to be false") + } + + // Verify labels + labels := deployment.GetLabels() + if labels["app"] != kubevirtAnnotationsRemoverName { + t.Errorf("app label: expected '%s', got %s", kubevirtAnnotationsRemoverName, labels["app"]) + } + + // Verify port + if len(container.Ports) == 0 || container.Ports[0].ContainerPort != kubevirtAnnotationsRemoverWebhookPort { + t.Errorf("expected container port %d", kubevirtAnnotationsRemoverWebhookPort) + } + }) + } +} + +func containsStr(s, substr string) bool { + return len(s) >= len(substr) && (s == substr || len(s) > 0 && containsSubstring(s, substr)) +} + +func containsSubstring(s, substr string) bool { + for i := 0; i <= len(s)-len(substr); i++ { + if s[i:i+len(substr)] == substr { + return true + } + } + return false +} diff --git a/internal/controller/readiness.go b/internal/controller/readiness.go index e8494f2278..ca38f2ccc2 100644 --- a/internal/controller/readiness.go +++ b/internal/controller/readiness.go @@ -62,6 +62,13 @@ func (r *DataProtectionApplicationReconciler) updateReadinessConditions() (bool, } allReady = allReady && vmfrReady + // Check KubevirtAnnotationsRemover (optional - only if enabled) + karReady, err := r.updateKubevirtAnnotationsRemoverReadinessCondition() + if err != nil { + return false, err + } + allReady = allReady && karReady + return allReady, nil } @@ -284,3 +291,62 @@ func (r *DataProtectionApplicationReconciler) updateVMFileRestoreReadinessCondit return isReady, nil } + +// updateKubevirtAnnotationsRemoverReadinessCondition checks the kubevirt-velero-annotations-remover +// deployment readiness and updates the condition. +func (r *DataProtectionApplicationReconciler) updateKubevirtAnnotationsRemoverReadinessCondition() (bool, error) { + // If not enabled, mark as disabled + if !r.checkKubevirtAnnotationsRemoverEnabled() { + apimeta.SetStatusCondition(&r.dpa.Status.Conditions, metav1.Condition{ + Type: oadpv1alpha1.ConditionKubevirtAnnotationsRemoverReady, + Status: metav1.ConditionTrue, + Reason: oadpv1alpha1.ReasonComponentDisabled, + Message: "KubeVirt annotations remover webhook is disabled", + }) + return true, nil + } + + deployment := &appsv1.Deployment{} + err := r.Get(r.Context, types.NamespacedName{ + Name: kubevirtAnnotationsRemoverName, + Namespace: r.dpa.Namespace, + }, deployment) + + if err != nil { + if k8serror.IsNotFound(err) { + apimeta.SetStatusCondition(&r.dpa.Status.Conditions, metav1.Condition{ + Type: oadpv1alpha1.ConditionKubevirtAnnotationsRemoverReady, + Status: metav1.ConditionFalse, + Reason: oadpv1alpha1.ReasonComponentNotFound, + Message: "KubeVirt annotations remover deployment not found", + }) + return false, nil + } + return false, err + } + + replicas := int32(1) + if deployment.Spec.Replicas != nil { + replicas = *deployment.Spec.Replicas + } + isReady := deployment.Status.ReadyReplicas >= 1 && + deployment.Status.ReadyReplicas == replicas + + if isReady { + apimeta.SetStatusCondition(&r.dpa.Status.Conditions, metav1.Condition{ + Type: oadpv1alpha1.ConditionKubevirtAnnotationsRemoverReady, + Status: metav1.ConditionTrue, + Reason: oadpv1alpha1.ReasonDeploymentReady, + Message: fmt.Sprintf("KubeVirt annotations remover ready: %d/%d replicas", deployment.Status.ReadyReplicas, replicas), + }) + } else { + apimeta.SetStatusCondition(&r.dpa.Status.Conditions, metav1.Condition{ + Type: oadpv1alpha1.ConditionKubevirtAnnotationsRemoverReady, + Status: metav1.ConditionFalse, + Reason: oadpv1alpha1.ReasonDeploymentNotReady, + Message: fmt.Sprintf("KubeVirt annotations remover not ready: %d/%d replicas ready", deployment.Status.ReadyReplicas, replicas), + }) + } + + return isReady, nil +} From 85f8a90c62e69496bfd394c6becd3dd845f7f1ba Mon Sep 17 00:00:00 2001 From: Wesley Hayutin Date: Thu, 12 Feb 2026 19:32:18 -0700 Subject: [PATCH 2/2] fix unit/lint tests --- .../controller/kubevirt_annotations_remover.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/internal/controller/kubevirt_annotations_remover.go b/internal/controller/kubevirt_annotations_remover.go index c44f0aed47..64c577af96 100644 --- a/internal/controller/kubevirt_annotations_remover.go +++ b/internal/controller/kubevirt_annotations_remover.go @@ -47,21 +47,21 @@ var ( // webhook deployment, service, and MutatingWebhookConfiguration. func (r *DataProtectionApplicationReconciler) ReconcileKubevirtAnnotationsRemover(log logr.Logger) (bool, error) { if !r.checkKubevirtAnnotationsRemoverEnabled() { - return r.cleanupKubevirtAnnotationsRemover(log) + return r.cleanupKubevirtAnnotationsRemover() } // Reconcile Service first (triggers TLS secret creation via OpenShift Service CA) - if err := r.reconcileKubevirtAnnotationsRemoverService(log); err != nil { + if err := r.reconcileKubevirtAnnotationsRemoverService(); err != nil { return false, err } // Reconcile Deployment - if err := r.reconcileKubevirtAnnotationsRemoverDeployment(log); err != nil { + if err := r.reconcileKubevirtAnnotationsRemoverDeployment(); err != nil { return false, err } // Reconcile MutatingWebhookConfiguration (cluster-scoped) - if err := r.reconcileKubevirtAnnotationsRemoverWebhook(log); err != nil { + if err := r.reconcileKubevirtAnnotationsRemoverWebhook(); err != nil { return false, err } @@ -69,7 +69,7 @@ func (r *DataProtectionApplicationReconciler) ReconcileKubevirtAnnotationsRemove } // cleanupKubevirtAnnotationsRemover removes all resources when the feature is disabled. -func (r *DataProtectionApplicationReconciler) cleanupKubevirtAnnotationsRemover(log logr.Logger) (bool, error) { +func (r *DataProtectionApplicationReconciler) cleanupKubevirtAnnotationsRemover() (bool, error) { // Delete MutatingWebhookConfiguration (cluster-scoped, must be deleted by name) webhookConfig := &admissionregistrationv1.MutatingWebhookConfiguration{} if err := r.Get( @@ -179,7 +179,7 @@ func (r *DataProtectionApplicationReconciler) cleanupKubevirtAnnotationsRemover( // reconcileKubevirtAnnotationsRemoverService creates or updates the Service // with OpenShift Service CA annotation for TLS certificate generation. -func (r *DataProtectionApplicationReconciler) reconcileKubevirtAnnotationsRemoverService(log logr.Logger) error { +func (r *DataProtectionApplicationReconciler) reconcileKubevirtAnnotationsRemoverService() error { svc := &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ Name: kubevirtAnnotationsRemoverName, @@ -236,7 +236,7 @@ func (r *DataProtectionApplicationReconciler) reconcileKubevirtAnnotationsRemove } // reconcileKubevirtAnnotationsRemoverDeployment creates or updates the webhook Deployment. -func (r *DataProtectionApplicationReconciler) reconcileKubevirtAnnotationsRemoverDeployment(log logr.Logger) error { +func (r *DataProtectionApplicationReconciler) reconcileKubevirtAnnotationsRemoverDeployment() error { deployment := &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Name: kubevirtAnnotationsRemoverName, @@ -404,7 +404,7 @@ func (r *DataProtectionApplicationReconciler) buildKubevirtAnnotationsRemoverDep // reconcileKubevirtAnnotationsRemoverWebhook creates or updates the MutatingWebhookConfiguration. // This is a cluster-scoped resource, so it cannot have an owner reference to the namespace-scoped DPA. // Instead, it is managed by label-based tracking with a fixed name. -func (r *DataProtectionApplicationReconciler) reconcileKubevirtAnnotationsRemoverWebhook(log logr.Logger) error { +func (r *DataProtectionApplicationReconciler) reconcileKubevirtAnnotationsRemoverWebhook() error { webhookConfig := &admissionregistrationv1.MutatingWebhookConfiguration{ ObjectMeta: metav1.ObjectMeta{ Name: kubevirtAnnotationsRemoverName,