From 91d6cf66562912b6b86a153a2a839b4d36dbad7b Mon Sep 17 00:00:00 2001 From: zerospiel Date: Mon, 2 Dec 2024 17:36:06 +0100 Subject: [PATCH] Introduce Backup API * draft --- api/v1alpha1/management_types.go | 131 +++++++ api/v1alpha1/zz_generated.deepcopy.go | 111 ++++++ .../crds/hmc.mirantis.com_managements.yaml | 362 ++++++++++++++++++ 3 files changed, 604 insertions(+) diff --git a/api/v1alpha1/management_types.go b/api/v1alpha1/management_types.go index c34611bbd..2270e4c9a 100644 --- a/api/v1alpha1/management_types.go +++ b/api/v1alpha1/management_types.go @@ -15,6 +15,9 @@ package v1alpha1 import ( + "time" + + corev1 "k8s.io/api/core/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/yaml" @@ -35,6 +38,7 @@ const ( type ManagementSpec struct { // +kubebuilder:validation:MinLength=1 // +kubebuilder:validation:MaxLength=253 + // Release references the Release object. Release string `json:"release"` // Core holds the core Management components that are mandatory. @@ -43,6 +47,8 @@ type ManagementSpec struct { // Providers is the list of supported CAPI providers. Providers []Provider `json:"providers,omitempty"` + + Backup Backup `json:"backup,omitempty"` } // Core represents a structure describing core Management components. @@ -53,6 +59,131 @@ type Core struct { CAPI Component `json:"capi,omitempty"` } +// Backup enables a feature to backup HMC objects into a cloud. +type Backup struct { + // NOTE: TODO: to avoid any dependencies it is just a ref for now + // actually it must be the velero.ScheduleSpec to avoid creating an actual + // objects and hence introducing other non-HMC-managed backups. + // + // Custom Schedule (and Backup) options to fetch parameters from. + // The HMC-required options might override or precede the options from the field. + CustomBackup *corev1.ObjectReference/* velero.ScheduleSpec */ `json:"customBackup,omitempty"` + + // +kubebuilder:default="0 */6 * * *" + + // Schedule is a Cron expression defining when to run the Backup. + // A shortcut instead of filling customBackup field up. + // Default value is to backup every 6 hours. + // If both this field and the customBackup are given, the schedule + // from the latter will be utilized. + Schedule string `json:"schedule"` + + InstallationParameters *VeleroInstallationParameters `json:"installationParameters,omitempty"` // TODO: remove optional, for now just to pass the tests + + // 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. + // A shortcut instead of filling customBackup field up. + // If both this field and the customBackup are given, the orLabelsSelectors + // from the latter will be utilized. + // The HMC default values will be prefixed by default to any value provided. + OrLabelsSelectors []string `json:"orLabelsSelectors,omitempty"` + + // +kubebuilder:default=false + + // Flag to indicate whether the backup feature is enabled. + // To make any post-install actions, disable the feature at first, + // install Velero, perform actions and only then enable the feature back. + Enabled bool `json:"enabled"` +} + +// VeleroInstallationParameters declares a full list of options to configure Velero installation. +// Changing options will lead to perform installation once again with the updated values. +type VeleroInstallationParameters struct { + // Provider name for backup and volume storage. + Provider string `json:"provider"` + // Name of the object storage bucket where backups should be stored. + Bucket string `json:"bucket"` + // Plugin container images to install into the Velero Deployment. + Plugins []string `json:"plugins"` + // Image to use for the Velero and node agent pods. + Image string `json:"image,omitempty"` + // Prefix under which all Velero data should be stored within the bucket + Prefix string `json:"prefix,omitempty"` + + // Resource requrements for node-agent pod. A value of "0" is treated as unbounded. + NodeAgentPodResources *corev1.ResourceRequirements `json:"nodeAgentPodResources,omitempty"` + // Resource requrements for Velero pod. A value of "0" is treated as unbounded. + VeleroPodResources *corev1.ResourceRequirements `json:"veleroPodResources,omitempty"` + + // Secret with credentials for backup and volume provider. + Secret *corev1.SecretReference `json:"secret"` + // Secret containing a certificate bundle to use when verifying TLS connections to the object store. + CACertFile *corev1.SecretReference `json:"caCertFile,omitempty"` + + // Annotations to add to the Velero and node agent pods + PodAnnotations map[string]string `json:"podAnnotations,omitempty"` + // Labels to add to the Velero and node agent pods + PodLabels map[string]string `json:"podLabels,omitempty"` + + // Annotations to add to the Velero ServiceAccount. Add iam.gke.io/gcp-service-account=[GSA_NAME]@[PROJECT_NAME].iam.gserviceaccount.com for workload identity. + // Requires ServiceAccountField to be set. + ServiceAccountAnnotations map[string]string `json:"serviceAccountAnnotations,omitempty"` + // ServiceAccountName to be set to the Velero and node agent pods, it should be created before the installation, and the user also needs to create the rolebinding for it. + ServiceAccountName string `json:"serviceAccountName,omitempty"` + + // Configuration to use for the backup storage location. + // Alternatively you could configure BackupStorageLocations and VolumeSnapshotLocations after installation. + // To do so, disable backup, configure and perform installation, and then enable backup. + BackupStorageConfig map[string]string `json:"backupStorageConfig,omitempty"` + // Configuration to use for the volume snapshot location. + VolumeSnapshotConfig map[string]string `json:"volumeSnapshotConfig,omitempty"` + // +kubebuilder:default=true + + // "Whether or not to create snapshot location automatically. Set to false if you do not plan to create volume snapshots via a storage provider. + UseVolumeSnapshots bool `json:"useVolumeSnapshots,omitempty"` + + // Create Velero node-agent daemonset. Velero node-agent hosts Velero modules that need to run in one or more nodes(i.e. Restic, Kopia). + UseNodeAgent bool `json:"useNodeAgent,omitempty"` + // Use privileged mode for the node agent. Required to backup block devices. + PrivilegedNodeAgent bool `json:"privilegedNodeAgent,omitempty"` + + // How often 'maintain' is run for backup repositories by default + DefaultRepoMaintenanceFrequency time.Duration `json:"defaultRepoMaintenanceFrequency,omitempty"` + // +kubebuilder:default=600000000000 + + // How often the garbage collection runs for expired backups. + // Default value is 1h. + GarbageCollectionFrequency time.Duration `json:"garbageCollectionFrequency,omitempty"` + // +kubebuilder:default=2400000000000 + + // How long to wait for pod volume operations to complete before timing out. + // Default value is 4h. + PodVolumeOperationTimeout time.Duration `json:"podVolumeOperationTimeout,omitempty"` + + // List of Velero feature flags to be set on the Velero deployment and the node-agent daemonset, if node-agent is enabled. + Features []string `json:"features,omitempty"` + + // Flag to configure Velero server to use pod volume file system backup by default for all volumes on all backups. + DefaultVolumesToFsBackup bool `json:"defaultVolumesToFsBackup,omitempty"` + // +kubebuilder:default="kopia" + // +kubebuilder:validation:Enum={"restic","kopia"} + + // The type of uploader to transfer the data of pod volumes. + UploaderType string `json:"uploaderType,omitempty"` + + // Flag to configure Velero server to move data by default for all snapshots supporting data movement. + DefaultSnapshotMoveData bool `json:"defaultSnapshotMoveData,omitempty"` + + // Skip the first scheduled backup immediately after creating a schedule. + ScheduleSkipImmediately bool `json:"scheduleSkipImmediately,omitempty"` +} + +const ( + // TODO: NOTE: the backup oneshot anno is just to improve the UX + BackupOneshotAnno = "hmc.mirantis.com/oneshot-backup-name" // create a single Backup object from the management.backup spec named from the given value +) + // Component represents HMC management component type Component struct { // Config allows to provide parameters for management component customization. diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 791685f4e..d1aa803dc 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -67,6 +67,36 @@ func (in *AvailableUpgrade) DeepCopy() *AvailableUpgrade { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Backup) DeepCopyInto(out *Backup) { + *out = *in + if in.CustomBackup != nil { + in, out := &in.CustomBackup, &out.CustomBackup + *out = new(v1.ObjectReference) + **out = **in + } + if in.InstallationParameters != nil { + in, out := &in.InstallationParameters, &out.InstallationParameters + *out = new(VeleroInstallationParameters) + (*in).DeepCopyInto(*out) + } + if in.OrLabelsSelectors != nil { + in, out := &in.OrLabelsSelectors, &out.OrLabelsSelectors + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Backup. +func (in *Backup) DeepCopy() *Backup { + if in == nil { + return nil + } + out := new(Backup) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterTemplate) DeepCopyInto(out *ClusterTemplate) { *out = *in @@ -641,6 +671,7 @@ func (in *ManagementSpec) DeepCopyInto(out *ManagementSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + in.Backup.DeepCopyInto(&out.Backup) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagementSpec. @@ -1482,3 +1513,83 @@ func (in *TemplateValidationStatus) DeepCopy() *TemplateValidationStatus { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VeleroInstallationParameters) DeepCopyInto(out *VeleroInstallationParameters) { + *out = *in + if in.Plugins != nil { + in, out := &in.Plugins, &out.Plugins + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.NodeAgentPodResources != nil { + in, out := &in.NodeAgentPodResources, &out.NodeAgentPodResources + *out = new(v1.ResourceRequirements) + (*in).DeepCopyInto(*out) + } + if in.VeleroPodResources != nil { + in, out := &in.VeleroPodResources, &out.VeleroPodResources + *out = new(v1.ResourceRequirements) + (*in).DeepCopyInto(*out) + } + if in.Secret != nil { + in, out := &in.Secret, &out.Secret + *out = new(v1.SecretReference) + **out = **in + } + if in.CACertFile != nil { + in, out := &in.CACertFile, &out.CACertFile + *out = new(v1.SecretReference) + **out = **in + } + if in.PodAnnotations != nil { + in, out := &in.PodAnnotations, &out.PodAnnotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.PodLabels != nil { + in, out := &in.PodLabels, &out.PodLabels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.ServiceAccountAnnotations != nil { + in, out := &in.ServiceAccountAnnotations, &out.ServiceAccountAnnotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.BackupStorageConfig != nil { + in, out := &in.BackupStorageConfig, &out.BackupStorageConfig + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.VolumeSnapshotConfig != nil { + in, out := &in.VolumeSnapshotConfig, &out.VolumeSnapshotConfig + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Features != nil { + in, out := &in.Features, &out.Features + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VeleroInstallationParameters. +func (in *VeleroInstallationParameters) DeepCopy() *VeleroInstallationParameters { + if in == nil { + return nil + } + out := new(VeleroInstallationParameters) + in.DeepCopyInto(out) + return out +} diff --git a/templates/provider/hmc/templates/crds/hmc.mirantis.com_managements.yaml b/templates/provider/hmc/templates/crds/hmc.mirantis.com_managements.yaml index 7ff679588..9eaf1dfeb 100644 --- a/templates/provider/hmc/templates/crds/hmc.mirantis.com_managements.yaml +++ b/templates/provider/hmc/templates/crds/hmc.mirantis.com_managements.yaml @@ -42,6 +42,368 @@ spec: spec: description: ManagementSpec defines the desired state of Management properties: + backup: + description: Backup enables a feature to backup HMC objects into a + cloud. + properties: + customBackup: + description: |- + NOTE: TODO: to avoid any dependencies it is just a ref for now + actually it must be the velero.ScheduleSpec to avoid creating an actual + objects and hence introducing other non-HMC-managed backups. + + Custom Schedule (and Backup) options to fetch parameters from. + The HMC-required options might override or precede the options from the field. + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: |- + If referring to a piece of an object instead of an entire object, this string + should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container within a pod, this would take on a value like: + "spec.containers{name}" (where "name" refers to the name of the container that triggered + the event) or if no container name is specified "spec.containers[2]" (container with + index 2 in this pod). This syntax is chosen only to have some well-defined way of + referencing a part of an object. + type: string + kind: + description: |- + Kind of the referent. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + namespace: + description: |- + Namespace of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ + type: string + resourceVersion: + description: |- + Specific resourceVersion to which this reference is made, if any. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency + type: string + uid: + description: |- + UID of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids + type: string + type: object + x-kubernetes-map-type: atomic + enabled: + default: false + description: |- + Flag to indicate whether the backup feature is enabled. + To make any post-install actions, disable the feature at first, + install Velero, perform actions and only then enable the feature back. + type: boolean + installationParameters: + description: |- + VeleroInstallationParameters declares a full list of options to configure Velero installation. + Changing options will lead to perform installation once again with the updated values. + properties: + backupStorageConfig: + additionalProperties: + type: string + description: |- + Configuration to use for the backup storage location. + Alternatively you could configure BackupStorageLocations and VolumeSnapshotLocations after installation. + To do so, disable backup, configure and perform installation, and then enable backup. + type: object + bucket: + description: Name of the object storage bucket where backups + should be stored. + type: string + caCertFile: + description: Secret containing a certificate bundle to use + when verifying TLS connections to the object store. + properties: + name: + description: name is unique within a namespace to reference + a secret resource. + type: string + namespace: + description: namespace defines the space within which + the secret name must be unique. + type: string + type: object + x-kubernetes-map-type: atomic + defaultRepoMaintenanceFrequency: + description: How often 'maintain' is run for backup repositories + by default + format: int64 + type: integer + defaultSnapshotMoveData: + description: Flag to configure Velero server to move data + by default for all snapshots supporting data movement. + type: boolean + defaultVolumesToFsBackup: + description: Flag to configure Velero server to use pod volume + file system backup by default for all volumes on all backups. + type: boolean + features: + description: List of Velero feature flags to be set on the + Velero deployment and the node-agent daemonset, if node-agent + is enabled. + items: + type: string + type: array + garbageCollectionFrequency: + default: 600000000000 + description: |- + How often the garbage collection runs for expired backups. + Default value is 1h. + format: int64 + type: integer + image: + description: Image to use for the Velero and node agent pods. + type: string + nodeAgentPodResources: + description: Resource requrements for node-agent pod. A value + of "0" is treated as unbounded. + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + plugins: + description: Plugin container images to install into the Velero + Deployment. + items: + type: string + type: array + podAnnotations: + additionalProperties: + type: string + description: Annotations to add to the Velero and node agent + pods + type: object + podLabels: + additionalProperties: + type: string + description: Labels to add to the Velero and node agent pods + type: object + podVolumeOperationTimeout: + default: 2400000000000 + description: |- + How long to wait for pod volume operations to complete before timing out. + Default value is 4h. + format: int64 + type: integer + prefix: + description: Prefix under which all Velero data should be + stored within the bucket + type: string + privilegedNodeAgent: + description: Use privileged mode for the node agent. Required + to backup block devices. + type: boolean + provider: + description: Provider name for backup and volume storage. + type: string + scheduleSkipImmediately: + description: Skip the first scheduled backup immediately after + creating a schedule. + type: boolean + secret: + description: Secret with credentials for backup and volume + provider. + properties: + name: + description: name is unique within a namespace to reference + a secret resource. + type: string + namespace: + description: namespace defines the space within which + the secret name must be unique. + type: string + type: object + x-kubernetes-map-type: atomic + serviceAccountAnnotations: + additionalProperties: + type: string + description: |- + Annotations to add to the Velero ServiceAccount. Add iam.gke.io/gcp-service-account=[GSA_NAME]@[PROJECT_NAME].iam.gserviceaccount.com for workload identity. + Requires ServiceAccountField to be set. + type: object + serviceAccountName: + description: ServiceAccountName to be set to the Velero and + node agent pods, it should be created before the installation, + and the user also needs to create the rolebinding for it. + type: string + uploaderType: + default: kopia + description: The type of uploader to transfer the data of + pod volumes. + enum: + - restic + - kopia + type: string + useNodeAgent: + description: Create Velero node-agent daemonset. Velero node-agent + hosts Velero modules that need to run in one or more nodes(i.e. + Restic, Kopia). + type: boolean + useVolumeSnapshots: + default: true + description: '"Whether or not to create snapshot location + automatically. Set to false if you do not plan to create + volume snapshots via a storage provider.' + type: boolean + veleroPodResources: + description: Resource requrements for Velero pod. A value + of "0" is treated as unbounded. + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + volumeSnapshotConfig: + additionalProperties: + type: string + description: Configuration to use for the volume snapshot + location. + type: object + required: + - bucket + - plugins + - provider + - secret + type: object + orLabelsSelectors: + 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. + A shortcut instead of filling customBackup field up. + If both this field and the customBackup are given, the orLabelsSelectors + from the latter will be utilized. + The HMC default values will be prefixed by default to any value provided. + items: + type: string + type: array + schedule: + default: 0 */6 * * * + description: |- + Schedule is a Cron expression defining when to run the Backup. + A shortcut instead of filling customBackup field up. + Default value is to backup every 6 hours. + If both this field and the customBackup are given, the schedule + from the latter will be utilized. + type: string + required: + - enabled + - schedule + type: object core: description: |- Core holds the core Management components that are mandatory.