From e3e99028c38446a3e56614f14df67e3e8f6c2c40 Mon Sep 17 00:00:00 2001 From: Mateus Oliveira Date: Tue, 9 Apr 2024 10:34:36 -0300 Subject: [PATCH] fixup! feat: Add Non Admin Restore controller Signed-off-by: Mateus Oliveira --- api/v1alpha1/nonadminrestore_types.go | 9 ++- api/v1alpha1/zz_generated.deepcopy.go | 9 ++- cmd/main.go | 1 - ...ac.oadp.openshift.io_nonadminrestores.yaml | 70 +++++++++++++++++++ .../controller/nonadminrestore_controller.go | 8 +-- .../nonadminrestore_controller_test.go | 31 ++++---- internal/controller/suite_test.go | 2 +- 7 files changed, 102 insertions(+), 28 deletions(-) diff --git a/api/v1alpha1/nonadminrestore_types.go b/api/v1alpha1/nonadminrestore_types.go index 3542775..a9935dc 100644 --- a/api/v1alpha1/nonadminrestore_types.go +++ b/api/v1alpha1/nonadminrestore_types.go @@ -34,12 +34,11 @@ type NonAdminRestoreSpec struct { // NonAdminRestoreStatus defines the observed state of NonAdminRestore type NonAdminRestoreStatus struct { - // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - // Important: Run "make" to regenerate code after modifying this file + Conditions []metav1.Condition `json:"conditions,omitempty"` } -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status // NonAdminRestore is the Schema for the nonadminrestores API type NonAdminRestore struct { @@ -50,7 +49,7 @@ type NonAdminRestore struct { Status NonAdminRestoreStatus `json:"status,omitempty"` } -//+kubebuilder:object:root=true +// +kubebuilder:object:root=true // NonAdminRestoreList contains a list of NonAdminRestore type NonAdminRestoreList struct { diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 32349b2..ace977b 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -138,7 +138,7 @@ func (in *NonAdminRestore) DeepCopyInto(out *NonAdminRestore) { out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) out.Spec = in.Spec - out.Status = in.Status + in.Status.DeepCopyInto(&out.Status) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NonAdminRestore. @@ -209,6 +209,13 @@ func (in *NonAdminRestoreSpec) DeepCopy() *NonAdminRestoreSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NonAdminRestoreStatus) DeepCopyInto(out *NonAdminRestoreStatus) { *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]metav1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NonAdminRestoreStatus. diff --git a/cmd/main.go b/cmd/main.go index a87dbe6..efb9bc3 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -26,7 +26,6 @@ import ( "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" clientgoscheme "k8s.io/client-go/kubernetes/scheme" - // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) // to ensure that exec-entrypoint and run can make use of them. _ "k8s.io/client-go/plugin/pkg/client/auth" diff --git a/config/crd/bases/nac.oadp.openshift.io_nonadminrestores.yaml b/config/crd/bases/nac.oadp.openshift.io_nonadminrestores.yaml index 5a8af11..dabd110 100644 --- a/config/crd/bases/nac.oadp.openshift.io_nonadminrestores.yaml +++ b/config/crd/bases/nac.oadp.openshift.io_nonadminrestores.yaml @@ -46,6 +46,76 @@ spec: type: object status: description: NonAdminRestoreStatus defines the observed state of NonAdminRestore + properties: + conditions: + items: + description: "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" + 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. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + 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 diff --git a/internal/controller/nonadminrestore_controller.go b/internal/controller/nonadminrestore_controller.go index 979faa3..964c774 100644 --- a/internal/controller/nonadminrestore_controller.go +++ b/internal/controller/nonadminrestore_controller.go @@ -33,9 +33,9 @@ type NonAdminRestoreReconciler struct { Scheme *runtime.Scheme } -//+kubebuilder:rbac:groups=nac.oadp.openshift.io,resources=nonadminrestores,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=nac.oadp.openshift.io,resources=nonadminrestores/status,verbs=get;update;patch -//+kubebuilder:rbac:groups=nac.oadp.openshift.io,resources=nonadminrestores/finalizers,verbs=update +// +kubebuilder:rbac:groups=nac.oadp.openshift.io,resources=nonadminrestores,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=nac.oadp.openshift.io,resources=nonadminrestores/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=nac.oadp.openshift.io,resources=nonadminrestores/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. @@ -46,7 +46,7 @@ type NonAdminRestoreReconciler struct { // // For more details, check Reconcile and its Result here: // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.17.0/pkg/reconcile -func (r *NonAdminRestoreReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { +func (*NonAdminRestoreReconciler) Reconcile(ctx context.Context, _ ctrl.Request) (ctrl.Result, error) { _ = log.FromContext(ctx) // TODO(user): your logic here diff --git a/internal/controller/nonadminrestore_controller_test.go b/internal/controller/nonadminrestore_controller_test.go index 7037554..5d6f76e 100644 --- a/internal/controller/nonadminrestore_controller_test.go +++ b/internal/controller/nonadminrestore_controller_test.go @@ -19,19 +19,18 @@ package controller import ( "context" - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" + "github.com/onsi/ginkgo/v2" + "github.com/onsi/gomega" "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/reconcile" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - nacv1alpha1 "github.com/migtools/oadp-non-admin/api/v1alpha1" ) -var _ = Describe("NonAdminRestore Controller", func() { - Context("When reconciling a resource", func() { +var _ = ginkgo.Describe("NonAdminRestore Controller", func() { + ginkgo.Context("When reconciling a resource", func() { const resourceName = "test-resource" ctx := context.Background() @@ -42,8 +41,8 @@ var _ = Describe("NonAdminRestore Controller", func() { } nonadminrestore := &nacv1alpha1.NonAdminRestore{} - BeforeEach(func() { - By("creating the custom resource for the Kind NonAdminRestore") + ginkgo.BeforeEach(func() { + ginkgo.By("creating the custom resource for the Kind NonAdminRestore") err := k8sClient.Get(ctx, typeNamespacedName, nonadminrestore) if err != nil && errors.IsNotFound(err) { resource := &nacv1alpha1.NonAdminRestore{ @@ -53,21 +52,21 @@ var _ = Describe("NonAdminRestore Controller", func() { }, // TODO(user): Specify other spec details if needed. } - Expect(k8sClient.Create(ctx, resource)).To(Succeed()) + gomega.Expect(k8sClient.Create(ctx, resource)).To(gomega.Succeed()) } }) - AfterEach(func() { + ginkgo.AfterEach(func() { // TODO(user): Cleanup logic after each test, like removing the resource instance. resource := &nacv1alpha1.NonAdminRestore{} err := k8sClient.Get(ctx, typeNamespacedName, resource) - Expect(err).NotTo(HaveOccurred()) + gomega.Expect(err).NotTo(gomega.HaveOccurred()) - By("Cleanup the specific resource instance NonAdminRestore") - Expect(k8sClient.Delete(ctx, resource)).To(Succeed()) + ginkgo.By("Cleanup the specific resource instance NonAdminRestore") + gomega.Expect(k8sClient.Delete(ctx, resource)).To(gomega.Succeed()) }) - It("should successfully reconcile the resource", func() { - By("Reconciling the created resource") + ginkgo.It("should successfully reconcile the resource", func() { + ginkgo.By("Reconciling the created resource") controllerReconciler := &NonAdminRestoreReconciler{ Client: k8sClient, Scheme: k8sClient.Scheme(), @@ -76,7 +75,7 @@ var _ = Describe("NonAdminRestore Controller", func() { _, err := controllerReconciler.Reconcile(ctx, reconcile.Request{ NamespacedName: typeNamespacedName, }) - Expect(err).NotTo(HaveOccurred()) + gomega.Expect(err).NotTo(gomega.HaveOccurred()) // TODO(user): Add more specific assertions depending on your controller's reconciliation logic. // Example: If you expect a certain status condition after reconciliation, verify it here. }) diff --git a/internal/controller/suite_test.go b/internal/controller/suite_test.go index ff5f04a..c200c59 100644 --- a/internal/controller/suite_test.go +++ b/internal/controller/suite_test.go @@ -74,7 +74,7 @@ var _ = ginkgov2.BeforeSuite(func() { gomega.Expect(err).NotTo(gomega.HaveOccurred()) err = nacv1alpha1.AddToScheme(scheme.Scheme) - Expect(err).NotTo(HaveOccurred()) + gomega.Expect(err).NotTo(gomega.HaveOccurred()) // +kubebuilder:scaffold:scheme