@@ -23,6 +23,7 @@ import (
2323 "k8s.io/apimachinery/pkg/api/errors"
2424 apierrors "k8s.io/apimachinery/pkg/api/errors"
2525 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26+
2627 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2728 "k8s.io/apimachinery/pkg/runtime"
2829 "k8s.io/apimachinery/pkg/runtime/schema"
@@ -621,6 +622,196 @@ var _ = ginkgo.Describe("Certman Operator", ginkgo.Ordered, ginkgo.ContinueOnFai
621622 fmt .Sprintf ("Secret %q was not re-created within %v or timestamp did not change" , secretNameToDelete , pollingDuration ))
622623 })
623624
625+ ginkgo .It ("should automatically ensure finalizer is present on ClusterDeployment when not being deleted" , func (ctx context.Context ) {
626+ clusterDeploymentGVR := schema.GroupVersionResource {
627+ Group : "hive.openshift.io" ,
628+ Version : "v1" ,
629+ Resource : "clusterdeployments" ,
630+ }
631+
632+ ginkgo .By ("fetching ClusterDeployment" )
633+ cdList , err := dynamicClient .Resource (clusterDeploymentGVR ).Namespace ("certman-operator" ).List (ctx , metav1.ListOptions {})
634+ gomega .Expect (err ).ToNot (gomega .HaveOccurred (), "Error listing ClusterDeployments" )
635+ gomega .Expect (len (cdList .Items )).To (gomega .BeNumerically (">" , 0 ), "No ClusterDeployment found" )
636+
637+ clusterDeployment := cdList .Items [0 ]
638+ cdName := clusterDeployment .GetName ()
639+ logger .Info ("Processing ClusterDeployment" , "name" , cdName )
640+
641+ // Verify ClusterDeployment is not being deleted
642+ deletionTimestamp := clusterDeployment .GetDeletionTimestamp ()
643+ gomega .Expect (deletionTimestamp ).To (gomega .BeNil (), "ClusterDeployment should not be deleted for this test" )
644+
645+ // Check if the certman finalizer is missing (simulating a scenario where it was removed externally)
646+ // The operator should automatically add it back when reconciling
647+ finalizers := clusterDeployment .GetFinalizers ()
648+ hasCertmanFinalizer := false
649+ for _ , finalizer := range finalizers {
650+ if finalizer == "certificaterequests.certman.managed.openshift.io" {
651+ hasCertmanFinalizer = true
652+ break
653+ }
654+ }
655+
656+ if ! hasCertmanFinalizer {
657+ logger .Info ("Certman finalizer is missing, waiting for operator to add it" , "name" , cdName )
658+ } else {
659+ logger .Info ("Certman finalizer already present, verifying operator maintains it" , "name" , cdName )
660+ }
661+
662+ ginkgo .By ("verifying operator ensures the finalizer is present" )
663+ gomega .Eventually (func () bool {
664+ updatedCD , err := dynamicClient .Resource (clusterDeploymentGVR ).Namespace ("certman-operator" ).Get (ctx , cdName , metav1.GetOptions {})
665+ if err != nil {
666+ logger .Error (err , "Failed to get ClusterDeployment" , "name" , cdName )
667+ return false
668+ }
669+
670+ // Verify it's still not being deleted
671+ if updatedCD .GetDeletionTimestamp () != nil {
672+ logger .Info ("ClusterDeployment is being deleted, skipping finalizer check" , "name" , cdName )
673+ return false
674+ }
675+
676+ updatedFinalizers := updatedCD .GetFinalizers ()
677+ for _ , finalizer := range updatedFinalizers {
678+ if finalizer == "certificaterequests.certman.managed.openshift.io" {
679+ logger .Info ("Operator has ensured finalizer is present on ClusterDeployment" , "name" , cdName , "finalizer" , finalizer )
680+ return true
681+ }
682+ }
683+
684+ logger .Info ("Finalizer not yet present on ClusterDeployment, waiting for operator to add it" , "name" , cdName )
685+ return false
686+
687+ }, pollingDuration , 30 * time .Second ).Should (gomega .BeTrue (), "Operator should ensure ClusterDeployment has the certman finalizer when not being deleted" )
688+ })
689+
690+ ginkgo .It ("should automatically ensure finalizer is present on CertificateRequest when not being deleted" , func (ctx context.Context ) {
691+ certRequestGVR := schema.GroupVersionResource {
692+ Group : "certman.managed.openshift.io" ,
693+ Version : "v1alpha1" ,
694+ Resource : "certificaterequests" ,
695+ }
696+
697+ ginkgo .By ("fetching CertificateRequest" )
698+ crList , err := dynamicClient .Resource (certRequestGVR ).Namespace ("certman-operator" ).List (ctx , metav1.ListOptions {})
699+ gomega .Expect (err ).ToNot (gomega .HaveOccurred (), "Error listing CertificateRequests" )
700+ gomega .Expect (len (crList .Items )).To (gomega .BeNumerically (">" , 0 ), "No CertificateRequest found" )
701+
702+ certRequest := crList .Items [0 ]
703+ crName := certRequest .GetName ()
704+ logger .Info ("Processing CertificateRequest" , "name" , crName )
705+
706+ // Verify CertificateRequest is not being deleted
707+ deletionTimestamp := certRequest .GetDeletionTimestamp ()
708+ gomega .Expect (deletionTimestamp ).To (gomega .BeNil (), "CertificateRequest should not be deleted for this test" )
709+
710+ // Check if the certman finalizer is missing (simulating a scenario where it was removed externally)
711+ // The operator should automatically add it back when reconciling
712+ finalizers := certRequest .GetFinalizers ()
713+ hasCertmanFinalizer := false
714+ for _ , finalizer := range finalizers {
715+ if finalizer == "certificaterequests.certman.managed.openshift.io" {
716+ hasCertmanFinalizer = true
717+ break
718+ }
719+ }
720+
721+ if ! hasCertmanFinalizer {
722+ logger .Info ("Certman finalizer is missing, waiting for operator to add it" , "name" , crName )
723+ } else {
724+ logger .Info ("Certman finalizer already present, verifying operator maintains it" , "name" , crName )
725+ }
726+
727+ ginkgo .By ("verifying operator ensures the finalizer is present" )
728+ gomega .Eventually (func () bool {
729+ updatedCR , err := dynamicClient .Resource (certRequestGVR ).Namespace ("certman-operator" ).Get (ctx , crName , metav1.GetOptions {})
730+ if err != nil {
731+ logger .Error (err , "Failed to get CertificateRequest" , "name" , crName )
732+ return false
733+ }
734+
735+ // Verify it's still not being deleted
736+ if updatedCR .GetDeletionTimestamp () != nil {
737+ logger .Info ("CertificateRequest is being deleted, skipping finalizer check" , "name" , crName )
738+ return false
739+ }
740+
741+ updatedFinalizers := updatedCR .GetFinalizers ()
742+ for _ , finalizer := range updatedFinalizers {
743+ if finalizer == "certificaterequests.certman.managed.openshift.io" {
744+ logger .Info ("Operator has ensured finalizer is present on CertificateRequest" , "name" , crName , "finalizer" , finalizer )
745+ return true
746+ }
747+ }
748+
749+ logger .Info ("Finalizer not yet present on CertificateRequest, waiting for operator to add it" , "name" , crName )
750+ return false
751+
752+ }, pollingDuration , 30 * time .Second ).Should (gomega .BeTrue (), "Operator should ensure CertificateRequest has the certman finalizer when not being deleted" )
753+ })
754+
755+ ginkgo .It ("should have ClusterDeployment as the owner of the CertificateRequest" , func (ctx context.Context ) {
756+ logger .Info ("waiting to ckeck if finalizer is there or not" )
757+ clusterDeploymentGVR := schema.GroupVersionResource {
758+ Group : "hive.openshift.io" ,
759+ Version : "v1" ,
760+ Resource : "clusterdeployments" ,
761+ }
762+
763+ certRequestGVR := schema.GroupVersionResource {
764+ Group : "certman.managed.openshift.io" ,
765+ Version : "v1alpha1" ,
766+ Resource : "certificaterequests" ,
767+ }
768+
769+ ginkgo .By ("fetching ClusterDeployment to get its name and UID" )
770+ clusterDeploymentList , err := dynamicClient .Resource (clusterDeploymentGVR ).Namespace ("certman-operator" ).List (ctx , metav1.ListOptions {})
771+ gomega .Expect (err ).ToNot (gomega .HaveOccurred (), "Error fetching ClusterDeployments" )
772+ gomega .Expect (len (clusterDeploymentList .Items )).To (gomega .BeNumerically (">" , 0 ), "ClusterDeployment not found" )
773+
774+ clusterDeployment := clusterDeploymentList .Items [0 ]
775+ cdName := clusterDeployment .GetName ()
776+ cdUID := clusterDeployment .GetUID ()
777+ logger .Info ("Found ClusterDeployment" , "name" , cdName , "uid" , cdUID )
778+
779+ ginkgo .By ("fetching CertificateRequest" )
780+ crList , err := dynamicClient .Resource (certRequestGVR ).Namespace ("certman-operator" ).List (ctx , metav1.ListOptions {})
781+ gomega .Expect (err ).ToNot (gomega .HaveOccurred (), "Error fetching CertificateRequests" )
782+ gomega .Expect (len (crList .Items )).To (gomega .BeNumerically (">" , 0 ), "No CertificateRequest found" )
783+
784+ certRequest := crList .Items [0 ]
785+ crName := certRequest .GetName ()
786+ logger .Info ("Found CertificateRequest" , "name" , crName )
787+
788+ ginkgo .By ("removing owner reference from CertificateRequest to test operator functionality" )
789+ certRequest .SetOwnerReferences ([]metav1.OwnerReference {})
790+ _ , err = dynamicClient .Resource (certRequestGVR ).Namespace ("certman-operator" ).Update (ctx , & certRequest , metav1.UpdateOptions {})
791+ gomega .Expect (err ).ToNot (gomega .HaveOccurred (), "Failed to remove owner reference from CertificateRequest" )
792+ logger .Info ("Owner reference removed from CertificateRequest" , "name" , crName )
793+
794+ ginkgo .By ("verifying operator automatically adds ClusterDeployment as owner reference" )
795+ gomega .Eventually (func () bool {
796+ updatedCR , err := dynamicClient .Resource (certRequestGVR ).Namespace ("certman-operator" ).Get (ctx , crName , metav1.GetOptions {})
797+ if err != nil {
798+ logger .Error (err , "Failed to get CertificateRequest" , "name" , crName )
799+ return false
800+ }
801+
802+ ownerRefs := updatedCR .GetOwnerReferences ()
803+ for _ , owner := range ownerRefs {
804+ if owner .Kind == "ClusterDeployment" && owner .Name == cdName {
805+ logger .Info ("ClusterDeployment has been added as owner by operator" , "name" , crName , "owner" , owner .Name )
806+ return true
807+ }
808+ }
809+
810+ logger .Info ("Owner reference not yet added by operator" , "name" , crName )
811+ return false
812+ }, pollingDuration , 30 * time .Second ).Should (gomega .BeTrue (), "ClusterDeployment should be automatically added as owner of CertificateRequest by operator" )
813+ })
814+
624815 ginkgo .AfterAll (func (ctx context.Context ) {
625816
626817 logger .Info ("Cleanup: Running AfterAll cleanup" )
0 commit comments