From 506001aeaac069cacc3eede47ab7ca374a0b96c5 Mon Sep 17 00:00:00 2001 From: kevin-kho Date: Fri, 21 Feb 2025 14:20:19 -0800 Subject: [PATCH] feat: AzureRwxVolumeBackup CRD (#1039) --- PROJECT | 9 ++ .../v1beta1/azurerwxvolumebackup_types.go | 118 ++++++++++++++ .../v1beta1/zz_generated.deepcopy.go | 128 +++++++++++++++ cmd/main.go | 5 + ...kyma-project.io_azurerwxvolumebackups.yaml | 147 ++++++++++++++++++ config/crd/kustomization.yaml | 2 + ...kyma-project.io_azurerwxvolumebackups.yaml | 147 ++++++++++++++++++ config/patchAfterMakeManifests.sh | 1 + ...rces_azurerwxvolumebackup_editor_role.yaml | 27 ++++ ...rces_azurerwxvolumebackup_viewer_role.yaml | 23 +++ config/rbac/kustomization.yaml | 2 + config/rbac/role.yaml | 3 + ...esources_v1beta1_azurerwxvolumebackup.yaml | 9 ++ config/samples/kustomization.yaml | 1 + config/sync.sh | 1 + .../azurerwxvolumebackup_controller.go | 65 ++++++++ .../azurerwxvolumebackup_controller_test.go | 28 ++++ pkg/skr/azurerwxvolumebackup/reconciler.go | 43 +++++ pkg/skr/azurerwxvolumebackup/state.go | 43 +++++ 19 files changed, 802 insertions(+) create mode 100644 api/cloud-resources/v1beta1/azurerwxvolumebackup_types.go create mode 100644 config/crd/bases/cloud-resources.kyma-project.io_azurerwxvolumebackups.yaml create mode 100644 config/dist/skr/crd/bases/providers/azure/cloud-resources.kyma-project.io_azurerwxvolumebackups.yaml create mode 100644 config/rbac/cloud-resources_azurerwxvolumebackup_editor_role.yaml create mode 100644 config/rbac/cloud-resources_azurerwxvolumebackup_viewer_role.yaml create mode 100644 config/samples/cloud-resources_v1beta1_azurerwxvolumebackup.yaml create mode 100644 internal/controller/cloud-resources/azurerwxvolumebackup_controller.go create mode 100644 internal/controller/cloud-resources/azurerwxvolumebackup_controller_test.go create mode 100644 pkg/skr/azurerwxvolumebackup/reconciler.go create mode 100644 pkg/skr/azurerwxvolumebackup/state.go diff --git a/PROJECT b/PROJECT index e363d38b1..1f71c8e6e 100644 --- a/PROJECT +++ b/PROJECT @@ -220,4 +220,13 @@ resources: kind: RedisCluster path: github.com/kyma-project/cloud-manager/api/cloud-control/v1beta1 version: v1beta1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: kyma-project.io + group: cloud-resources + kind: AzureRwxVolumeBackup + path: github.com/kyma-project/cloud-manager/api/cloud-resources/v1beta1 + version: v1beta1 version: "3" diff --git a/api/cloud-resources/v1beta1/azurerwxvolumebackup_types.go b/api/cloud-resources/v1beta1/azurerwxvolumebackup_types.go new file mode 100644 index 000000000..13d787984 --- /dev/null +++ b/api/cloud-resources/v1beta1/azurerwxvolumebackup_types.go @@ -0,0 +1,118 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta1 + +import ( + featuretypes "github.com/kyma-project/cloud-manager/pkg/feature/types" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type AzureRwxBackupState string + +const ( + AzureRwxBackupReady AzureRwxBackupState = "Ready" + + AzureRwxBackupError AzureRwxBackupState = "Error" + + AzureRwxBackupCreating AzureRwxBackupState = "Creating" + + AzureRwxBackupDeleting AzureRwxBackupState = "Deleting" + + AzureRwxBackupDeleted AzureRwxBackupState = "Deleted" + + AzureRwxBackupFailed AzureRwxBackupState = "Failed" +) + +type PvcRef struct { + // Name speicfies the name of the PVC that a backup has to be made of. + // +kubebuilder:validation:Required + Name string `json:"name"` + + // Namespace specified the namespace of the AzureRwxVolume resource that a backup has to be made of. + // If not specified then namespace of the AzureRwxVolumeBackup is used. + // +optional + Namespace string `json:"namespace"` +} + +type PvcSource struct { + Pvc PvcRef `json:"pvc"` +} + +// AzureRwxVolumeBackupSpec defines the desired state of AzureRwxVolumeBackup +type AzureRwxVolumeBackupSpec struct { + + // +kubebuilder:validation:Required + // +kubebuilder:validation:XValidation:rule=(self == oldSelf), message="source is immutable." + Source PvcSource `json:"source"` + + Location string `json:"location"` +} + +// AzureRwxVolumeBackupStatus defines the observed state of AzureRwxVolumeBackup +type AzureRwxVolumeBackupStatus struct { + State AzureRwxBackupState `json:"state,omitempty"` + + // List of status conditions + // +optional + // +listType=map + // +listMapKey=type + Conditions []metav1.Condition `json:"conditions,omitempty"` + + // Operation Identifier to track the Hyperscaler Creation Operation + // +optional + OpIdentifier string `json:"opIdentifier,omitempty"` + + // +optional + Id string `json:"id,omitempty"` + + // RecoveryPointId specifies the corresponding snapshot used for restore + // +optional + RecoveryPointId string `json:"recoveryPointId,omitempty"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status + +// AzureRwxVolumeBackup is the Schema for the azurerwxvolumebackups API +type AzureRwxVolumeBackup struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec AzureRwxVolumeBackupSpec `json:"spec,omitempty"` + Status AzureRwxVolumeBackupStatus `json:"status,omitempty"` +} + +func (bu *AzureRwxVolumeBackup) SpecificToFeature() featuretypes.FeatureName { + return featuretypes.FeatureNfsBackup +} + +func (bu *AzureRwxVolumeBackup) SpecificToProviders() []string { + return []string{"azure"} +} + +// +kubebuilder:object:root=true + +// AzureRwxVolumeBackupList contains a list of AzureRwxVolumeBackup +type AzureRwxVolumeBackupList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []AzureRwxVolumeBackup `json:"items"` +} + +func init() { + SchemeBuilder.Register(&AzureRwxVolumeBackup{}, &AzureRwxVolumeBackupList{}) +} diff --git a/api/cloud-resources/v1beta1/zz_generated.deepcopy.go b/api/cloud-resources/v1beta1/zz_generated.deepcopy.go index 593f1f3de..8f8fc261a 100644 --- a/api/cloud-resources/v1beta1/zz_generated.deepcopy.go +++ b/api/cloud-resources/v1beta1/zz_generated.deepcopy.go @@ -888,6 +888,103 @@ func (in *AzureRedisInstanceStatus) DeepCopy() *AzureRedisInstanceStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AzureRwxVolumeBackup) DeepCopyInto(out *AzureRwxVolumeBackup) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureRwxVolumeBackup. +func (in *AzureRwxVolumeBackup) DeepCopy() *AzureRwxVolumeBackup { + if in == nil { + return nil + } + out := new(AzureRwxVolumeBackup) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AzureRwxVolumeBackup) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AzureRwxVolumeBackupList) DeepCopyInto(out *AzureRwxVolumeBackupList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]AzureRwxVolumeBackup, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureRwxVolumeBackupList. +func (in *AzureRwxVolumeBackupList) DeepCopy() *AzureRwxVolumeBackupList { + if in == nil { + return nil + } + out := new(AzureRwxVolumeBackupList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AzureRwxVolumeBackupList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AzureRwxVolumeBackupSpec) DeepCopyInto(out *AzureRwxVolumeBackupSpec) { + *out = *in + out.Source = in.Source +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureRwxVolumeBackupSpec. +func (in *AzureRwxVolumeBackupSpec) DeepCopy() *AzureRwxVolumeBackupSpec { + if in == nil { + return nil + } + out := new(AzureRwxVolumeBackupSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AzureRwxVolumeBackupStatus) DeepCopyInto(out *AzureRwxVolumeBackupStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureRwxVolumeBackupStatus. +func (in *AzureRwxVolumeBackupStatus) DeepCopy() *AzureRwxVolumeBackupStatus { + if in == nil { + return nil + } + out := new(AzureRwxVolumeBackupStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AzureVpcPeering) DeepCopyInto(out *AzureVpcPeering) { *out = *in @@ -2163,6 +2260,37 @@ func (in *NameLabelsAnnotationsSpec) DeepCopy() *NameLabelsAnnotationsSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PvcRef) DeepCopyInto(out *PvcRef) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PvcRef. +func (in *PvcRef) DeepCopy() *PvcRef { + if in == nil { + return nil + } + out := new(PvcRef) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PvcSource) DeepCopyInto(out *PvcSource) { + *out = *in + out.Pvc = in.Pvc +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PvcSource. +func (in *PvcSource) DeepCopy() *PvcSource { + if in == nil { + return nil + } + out := new(PvcSource) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RedisAuthSecretSpec) DeepCopyInto(out *RedisAuthSecretSpec) { *out = *in diff --git a/cmd/main.go b/cmd/main.go index 73b56edbe..218c5c039 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -262,6 +262,11 @@ func main() { os.Exit(1) } + //if err = cloudresourcescontroller.SetupAzureRwxBackupReconciler(skrRegistry); err != nil { + // setupLog.Error(err, "unable to create controller", "controller", "AzureRwxVolumeBackup") + // os.Exit(1) + //} + // KCP Controllers if err = cloudcontrolcontroller.SetupScopeReconciler(ctx, mgr, scopeclient.NewAwsStsGardenClientProvider(), skrLoop, gcpclient.NewServiceUsageClientProvider()); err != nil { setupLog.Error(err, "unable to create controller", "controller", "Scope") diff --git a/config/crd/bases/cloud-resources.kyma-project.io_azurerwxvolumebackups.yaml b/config/crd/bases/cloud-resources.kyma-project.io_azurerwxvolumebackups.yaml new file mode 100644 index 000000000..8aa32fb2e --- /dev/null +++ b/config/crd/bases/cloud-resources.kyma-project.io_azurerwxvolumebackups.yaml @@ -0,0 +1,147 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.5 + cloud-resources.kyma-project.io/version: v0.0.1 + name: azurerwxvolumebackups.cloud-resources.kyma-project.io +spec: + group: cloud-resources.kyma-project.io + names: + kind: AzureRwxVolumeBackup + listKind: AzureRwxVolumeBackupList + plural: azurerwxvolumebackups + singular: azurerwxvolumebackup + scope: Namespaced + versions: + - name: v1beta1 + schema: + openAPIV3Schema: + description: AzureRwxVolumeBackup is the Schema for the azurerwxvolumebackups API + 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: AzureRwxVolumeBackupSpec defines the desired state of AzureRwxVolumeBackup + properties: + location: + type: string + source: + properties: + pvc: + properties: + name: + description: Name speicfies the name of the PVC that a backup has to be made of. + type: string + namespace: + description: |- + Namespace specified the namespace of the AzureRwxVolume resource that a backup has to be made of. + If not specified then namespace of the AzureRwxVolumeBackup is used. + type: string + required: + - name + type: object + required: + - pvc + type: object + x-kubernetes-validations: + - message: source is immutable. + rule: (self == oldSelf) + required: + - location + - source + type: object + status: + description: AzureRwxVolumeBackupStatus defines the observed state of AzureRwxVolumeBackup + properties: + conditions: + description: List of status conditions + 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 + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + id: + type: string + opIdentifier: + description: Operation Identifier to track the Hyperscaler Creation Operation + type: string + recoveryPointId: + description: RecoveryPointId specifies the corresponding snapshot used for restore + type: string + state: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index ce74d7929..913f6d6fb 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -26,6 +26,7 @@ resources: - bases/cloud-resources.kyma-project.io_awsnfsvolumerestores.yaml - bases/cloud-control.kyma-project.io_skrstatuses.yaml - bases/cloud-control.kyma-project.io_redisclusters.yaml +- bases/cloud-resources.kyma-project.io_azurerwxvolumebackups.yaml #+kubebuilder:scaffold:crdkustomizeresource patches: @@ -79,6 +80,7 @@ patches: #- path: patches/cainjection_in_cloud-control_nukes.yaml #- path: patches/cainjection_in_cloud-resources_awsnfsvolumerestores.yaml #- path: patches/cainjection_in_cloud-control_redisclusters.yaml +#- path: patches/cainjection_in_cloud-resources_azurerwxvolumebackups.yaml #+kubebuilder:scaffold:crdkustomizecainjectionpatch # [WEBHOOK] To enable webhook, uncomment the following section diff --git a/config/dist/skr/crd/bases/providers/azure/cloud-resources.kyma-project.io_azurerwxvolumebackups.yaml b/config/dist/skr/crd/bases/providers/azure/cloud-resources.kyma-project.io_azurerwxvolumebackups.yaml new file mode 100644 index 000000000..8aa32fb2e --- /dev/null +++ b/config/dist/skr/crd/bases/providers/azure/cloud-resources.kyma-project.io_azurerwxvolumebackups.yaml @@ -0,0 +1,147 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.5 + cloud-resources.kyma-project.io/version: v0.0.1 + name: azurerwxvolumebackups.cloud-resources.kyma-project.io +spec: + group: cloud-resources.kyma-project.io + names: + kind: AzureRwxVolumeBackup + listKind: AzureRwxVolumeBackupList + plural: azurerwxvolumebackups + singular: azurerwxvolumebackup + scope: Namespaced + versions: + - name: v1beta1 + schema: + openAPIV3Schema: + description: AzureRwxVolumeBackup is the Schema for the azurerwxvolumebackups API + 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: AzureRwxVolumeBackupSpec defines the desired state of AzureRwxVolumeBackup + properties: + location: + type: string + source: + properties: + pvc: + properties: + name: + description: Name speicfies the name of the PVC that a backup has to be made of. + type: string + namespace: + description: |- + Namespace specified the namespace of the AzureRwxVolume resource that a backup has to be made of. + If not specified then namespace of the AzureRwxVolumeBackup is used. + type: string + required: + - name + type: object + required: + - pvc + type: object + x-kubernetes-validations: + - message: source is immutable. + rule: (self == oldSelf) + required: + - location + - source + type: object + status: + description: AzureRwxVolumeBackupStatus defines the observed state of AzureRwxVolumeBackup + properties: + conditions: + description: List of status conditions + 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 + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + id: + type: string + opIdentifier: + description: Operation Identifier to track the Hyperscaler Creation Operation + type: string + recoveryPointId: + description: RecoveryPointId specifies the corresponding snapshot used for restore + type: string + state: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/patchAfterMakeManifests.sh b/config/patchAfterMakeManifests.sh index d6b69498f..f8f9a523e 100755 --- a/config/patchAfterMakeManifests.sh +++ b/config/patchAfterMakeManifests.sh @@ -20,3 +20,4 @@ yq -i '.metadata.annotations."cloud-resources.kyma-project.io/version" = "v0.0.3 yq -i '.metadata.annotations."cloud-resources.kyma-project.io/version" = "v0.0.3"' $SCRIPT_DIR/crd/bases/cloud-resources.kyma-project.io_awsvpcpeerings.yaml yq -i '.metadata.annotations."cloud-resources.kyma-project.io/version" = "v0.0.1"' $SCRIPT_DIR/crd/bases/cloud-resources.kyma-project.io_cloudresources.yaml yq -i '.metadata.annotations."cloud-resources.kyma-project.io/version" = "v0.0.3"' $SCRIPT_DIR/crd/bases/cloud-resources.kyma-project.io_awsnfsbackupschedules.yaml +yq -i '.metadata.annotations."cloud-resources.kyma-project.io/version" = "v0.0.1"' $SCRIPT_DIR/crd/bases/cloud-resources.kyma-project.io_azurerwxvolumebackups.yaml diff --git a/config/rbac/cloud-resources_azurerwxvolumebackup_editor_role.yaml b/config/rbac/cloud-resources_azurerwxvolumebackup_editor_role.yaml new file mode 100644 index 000000000..a54a4b60d --- /dev/null +++ b/config/rbac/cloud-resources_azurerwxvolumebackup_editor_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to edit azurerwxvolumebackups. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: cloud-manager + app.kubernetes.io/managed-by: kustomize + name: cloud-resources-azurerwxvolumebackup-editor-role +rules: +- apiGroups: + - cloud-resources.kyma-project.io + resources: + - azurerwxvolumebackups + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - cloud-resources.kyma-project.io + resources: + - azurerwxvolumebackups/status + verbs: + - get diff --git a/config/rbac/cloud-resources_azurerwxvolumebackup_viewer_role.yaml b/config/rbac/cloud-resources_azurerwxvolumebackup_viewer_role.yaml new file mode 100644 index 000000000..eb7fc267f --- /dev/null +++ b/config/rbac/cloud-resources_azurerwxvolumebackup_viewer_role.yaml @@ -0,0 +1,23 @@ +# permissions for end users to view azurerwxvolumebackups. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: cloud-manager + app.kubernetes.io/managed-by: kustomize + name: cloud-resources-azurerwxvolumebackup-viewer-role +rules: +- apiGroups: + - cloud-resources.kyma-project.io + resources: + - azurerwxvolumebackups + verbs: + - get + - list + - watch +- apiGroups: + - cloud-resources.kyma-project.io + resources: + - azurerwxvolumebackups/status + verbs: + - get diff --git a/config/rbac/kustomization.yaml b/config/rbac/kustomization.yaml index da5af5957..a6aad7863 100644 --- a/config/rbac/kustomization.yaml +++ b/config/rbac/kustomization.yaml @@ -20,6 +20,8 @@ resources: # default, aiding admins in cluster management. Those roles are # not used by the Project itself. You can comment the following lines # if you do not want those helpers be installed with your Project. +- cloud-resources_azurerwxvolumebackup_editor_role.yaml +- cloud-resources_azurerwxvolumebackup_viewer_role.yaml - cloud-control_rediscluster_editor_role.yaml - cloud-control_rediscluster_viewer_role.yaml - cloud-control_nuke_editor_role.yaml diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 41d6ada39..1396b7504 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -69,6 +69,7 @@ rules: - awsredisinstances - awsvpcpeerings - azureredisinstances + - azurerwxvolumebackups - azurevpcpeerings - cceenfsvolumes - cloudresources @@ -97,6 +98,7 @@ rules: - awsredisinstances/finalizers - awsvpcpeerings/finalizers - azureredisinstances/finalizers + - azurerwxvolumebackups/finalizers - azurevpcpeerings/finalizers - cceenfsvolumes/finalizers - cloudresources/finalizers @@ -119,6 +121,7 @@ rules: - awsredisinstances/status - awsvpcpeerings/status - azureredisinstances/status + - azurerwxvolumebackups/status - azurevpcpeerings/status - cceenfsvolumes/status - cloudresources/status diff --git a/config/samples/cloud-resources_v1beta1_azurerwxvolumebackup.yaml b/config/samples/cloud-resources_v1beta1_azurerwxvolumebackup.yaml new file mode 100644 index 000000000..d743a4b37 --- /dev/null +++ b/config/samples/cloud-resources_v1beta1_azurerwxvolumebackup.yaml @@ -0,0 +1,9 @@ +apiVersion: cloud-resources.kyma-project.io/v1beta1 +kind: AzureRwxVolumeBackup +metadata: + labels: + app.kubernetes.io/name: cloud-manager + app.kubernetes.io/managed-by: kustomize + name: azurerwxvolumebackup-sample +spec: + # TODO(user): Add fields here diff --git a/config/samples/kustomization.yaml b/config/samples/kustomization.yaml index b52b4a5cb..46e64b852 100644 --- a/config/samples/kustomization.yaml +++ b/config/samples/kustomization.yaml @@ -24,4 +24,5 @@ resources: - cloud-resources_v1beta1_awsnfsvolumerestore.yaml - cloud-control_v1beta1_skrstatus.yaml - cloud-control_v1beta1_rediscluster.yaml +- cloud-resources_v1beta1_azurerwxvolumebackup.yaml #+kubebuilder:scaffold:manifestskustomizesamples diff --git a/config/sync.sh b/config/sync.sh index fd13b044b..ef246752f 100755 --- a/config/sync.sh +++ b/config/sync.sh @@ -54,6 +54,7 @@ cp $SCRIPT_DIR/ui-extensions/awsnfsbackupschedules/cloud-resources.kyma-project. cp $SCRIPT_DIR/crd/bases/cloud-resources.kyma-project.io_azurevpcpeerings.yaml $SCRIPT_DIR/dist/skr/crd/bases/providers/azure/cloud-resources.kyma-project.io_azurevpcpeerings.yaml cp $SCRIPT_DIR/crd/bases/cloud-resources.kyma-project.io_azureredisinstances.yaml $SCRIPT_DIR/dist/skr/crd/bases/providers/azure/cloud-resources.kyma-project.io_azureredisinstances.yaml cp $SCRIPT_DIR/crd/bases/cloud-resources.kyma-project.io_ipranges.yaml $SCRIPT_DIR/dist/skr/crd/bases/providers/azure/ +cp $SCRIPT_DIR/crd/bases/cloud-resources.kyma-project.io_azurerwxvolumebackups.yaml $SCRIPT_DIR/dist/skr/crd/bases/providers/azure/ # AZURE UI cp $SCRIPT_DIR/ui-extensions/azurevpcpeerings/cloud-resources.kyma-project.io_azurevpcpeerings_ui.yaml $SCRIPT_DIR/dist/skr/crd/bases/providers/azure diff --git a/internal/controller/cloud-resources/azurerwxvolumebackup_controller.go b/internal/controller/cloud-resources/azurerwxvolumebackup_controller.go new file mode 100644 index 000000000..94fccc7cd --- /dev/null +++ b/internal/controller/cloud-resources/azurerwxvolumebackup_controller.go @@ -0,0 +1,65 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cloudresources + +import ( + "context" + "github.com/kyma-project/cloud-manager/pkg/skr/azurerwxvolumebackup" + skrruntime "github.com/kyma-project/cloud-manager/pkg/skr/runtime" + skrreconciler "github.com/kyma-project/cloud-manager/pkg/skr/runtime/reconcile" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + cloudresourcesv1beta1 "github.com/kyma-project/cloud-manager/api/cloud-resources/v1beta1" + ctrl "sigs.k8s.io/controller-runtime" +) + +type AzureRwxVolumeBackupReconcilerFactory struct{} + +func (f *AzureRwxVolumeBackupReconcilerFactory) New(args skrreconciler.ReconcilerArguments) reconcile.Reconciler { + return &AzureRwxVolumeBackupReconciler{ + reconciler: azurerwxvolumebackup.NewReconcilerFactory().New(args), + } +} + +// AzureRwxVolumeBackupReconciler reconciles a AzureRwxVolumeBackup object +type AzureRwxVolumeBackupReconciler struct { + reconciler reconcile.Reconciler +} + +// +kubebuilder:rbac:groups=cloud-resources.kyma-project.io,resources=azurerwxvolumebackups,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=cloud-resources.kyma-project.io,resources=azurerwxvolumebackups/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=cloud-resources.kyma-project.io,resources=azurerwxvolumebackups/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the AzureRwxVolumeBackup object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.0/pkg/reconcile +func (r *AzureRwxVolumeBackupReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + return r.reconciler.Reconcile(ctx, req) +} + +func SetupAzureRwxBackupReconciler(reg skrruntime.SkrRegistry) error { + return reg.Register(). + WithFactory(&AzureRwxVolumeBackupReconcilerFactory{}). + For(&cloudresourcesv1beta1.AzureRwxVolumeBackup{}). + Complete() +} diff --git a/internal/controller/cloud-resources/azurerwxvolumebackup_controller_test.go b/internal/controller/cloud-resources/azurerwxvolumebackup_controller_test.go new file mode 100644 index 000000000..dad564be0 --- /dev/null +++ b/internal/controller/cloud-resources/azurerwxvolumebackup_controller_test.go @@ -0,0 +1,28 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cloudresources + +import ( + . "github.com/onsi/ginkgo/v2" +) + +// TODO: finish unit test +var _ = Describe("AzureRwxVolumeBackup Controller", func() { + Context("When reconciling a resource", func() { + + }) +}) diff --git a/pkg/skr/azurerwxvolumebackup/reconciler.go b/pkg/skr/azurerwxvolumebackup/reconciler.go new file mode 100644 index 000000000..016900f28 --- /dev/null +++ b/pkg/skr/azurerwxvolumebackup/reconciler.go @@ -0,0 +1,43 @@ +package azurerwxvolumebackup + +import ( + "context" + "github.com/kyma-project/cloud-manager/pkg/composed" + skrruntime "github.com/kyma-project/cloud-manager/pkg/skr/runtime/reconcile" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +type reconcilerFactory struct { +} + +type reconciler struct { + factory *stateFactory +} + +func (r *reconciler) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) { + state := r.factory.NewState(request) + action := r.newAction() + + return composed.Handle(action(ctx, state)) +} + +// TODO: fill out the rest of actions +func (r *reconciler) newAction() composed.Action { + return composed.ComposeActions( + "azureRwxVolumeBackup", + ) +} + +func NewReconcilerFactory() skrruntime.ReconcilerFactory { + return &reconcilerFactory{} +} + +func (f *reconcilerFactory) New(args skrruntime.ReconcilerArguments) reconcile.Reconciler { + return &reconciler{ + factory: newStateFactory( + composed.NewStateFactory(composed.NewStateClusterFromCluster(args.SkrCluster)), + args.KymaRef, + composed.NewStateClusterFromCluster(args.KcpCluster), + ), + } +} diff --git a/pkg/skr/azurerwxvolumebackup/state.go b/pkg/skr/azurerwxvolumebackup/state.go new file mode 100644 index 000000000..dec40b81d --- /dev/null +++ b/pkg/skr/azurerwxvolumebackup/state.go @@ -0,0 +1,43 @@ +package azurerwxvolumebackup + +import ( + cloudresourcesv1beta1 "github.com/kyma-project/cloud-manager/api/cloud-resources/v1beta1" + "github.com/kyma-project/cloud-manager/pkg/composed" + corev1 "k8s.io/api/core/v1" + "k8s.io/klog/v2" + ctrl "sigs.k8s.io/controller-runtime" +) + +type State struct { + composed.State + KymaRef klog.ObjectRef + KcpCluster composed.StateCluster + + AuthSecret *corev1.Secret +} + +type stateFactory struct { + baseStateFactory composed.StateFactory + kymaRef klog.ObjectRef + kcpCluster composed.StateCluster +} + +func (f *stateFactory) NewState(req ctrl.Request) *State { + return &State{ + State: f.baseStateFactory.NewState(req.NamespacedName, &cloudresourcesv1beta1.AzureRwxVolumeBackup{}), + KymaRef: f.kymaRef, + KcpCluster: f.kcpCluster, + } +} + +func newStateFactory( + baseStateFactory composed.StateFactory, + kymaRef klog.ObjectRef, + kcpCluster composed.StateCluster, +) *stateFactory { + return &stateFactory{ + baseStateFactory: baseStateFactory, + kymaRef: kymaRef, + kcpCluster: kcpCluster, + } +}