@@ -18,13 +18,15 @@ import (
18
18
"k8s.io/apimachinery/pkg/util/rand"
19
19
ctrl "sigs.k8s.io/controller-runtime"
20
20
"sigs.k8s.io/controller-runtime/pkg/client"
21
+ crfinalizer "sigs.k8s.io/controller-runtime/pkg/finalizer"
21
22
"sigs.k8s.io/controller-runtime/pkg/reconcile"
22
23
23
24
"github.com/operator-framework/operator-registry/alpha/declcfg"
24
25
25
26
ocv1alpha1 "github.com/operator-framework/operator-controller/api/v1alpha1"
26
27
"github.com/operator-framework/operator-controller/internal/conditionsets"
27
28
"github.com/operator-framework/operator-controller/internal/controllers"
29
+ "github.com/operator-framework/operator-controller/internal/finalizers"
28
30
"github.com/operator-framework/operator-controller/internal/resolve"
29
31
"github.com/operator-framework/operator-controller/internal/rukpak/source"
30
32
)
@@ -336,6 +338,105 @@ func TestClusterExtensionResolutionAndUnpackSuccessfulApplierFails(t *testing.T)
336
338
require .NoError (t , cl .DeleteAllOf (ctx , & ocv1alpha1.ClusterExtension {}))
337
339
}
338
340
341
+ func TestClusterExtensionApplierFailsWithBundleInstalled (t * testing.T ) {
342
+ cl , reconciler := newClientAndReconciler (t )
343
+ reconciler .Unpacker = & MockUnpacker {
344
+ result : & source.Result {
345
+ State : source .StateUnpacked ,
346
+ Bundle : fstest.MapFS {},
347
+ },
348
+ }
349
+
350
+ ctx := context .Background ()
351
+ extKey := types.NamespacedName {Name : fmt .Sprintf ("cluster-extension-test-%s" , rand .String (8 ))}
352
+
353
+ t .Log ("When the cluster extension specifies a channel with version that exist" )
354
+ t .Log ("By initializing cluster state" )
355
+ pkgName := "prometheus"
356
+ pkgVer := "1.0.0"
357
+ pkgChan := "beta"
358
+ namespace := fmt .Sprintf ("test-ns-%s" , rand .String (8 ))
359
+ serviceAccount := fmt .Sprintf ("test-sa-%s" , rand .String (8 ))
360
+
361
+ clusterExtension := & ocv1alpha1.ClusterExtension {
362
+ ObjectMeta : metav1.ObjectMeta {Name : extKey .Name },
363
+ Spec : ocv1alpha1.ClusterExtensionSpec {
364
+ Source : ocv1alpha1.SourceConfig {
365
+ SourceType : "Catalog" ,
366
+ Catalog : & ocv1alpha1.CatalogSource {
367
+ PackageName : pkgName ,
368
+ Version : pkgVer ,
369
+ Channels : []string {pkgChan },
370
+ },
371
+ },
372
+ Install : ocv1alpha1.ClusterExtensionInstallConfig {
373
+ Namespace : namespace ,
374
+ ServiceAccount : ocv1alpha1.ServiceAccountReference {
375
+ Name : serviceAccount ,
376
+ },
377
+ },
378
+ },
379
+ }
380
+ err := cl .Create (ctx , clusterExtension )
381
+ require .NoError (t , err )
382
+
383
+ t .Log ("It sets resolution success status" )
384
+ t .Log ("By running reconcile" )
385
+ reconciler .Resolver = resolve .Func (func (_ context.Context , _ * ocv1alpha1.ClusterExtension , _ * ocv1alpha1.BundleMetadata ) (* declcfg.Bundle , * bsemver.Version , * declcfg.Deprecation , error ) {
386
+ v := bsemver .MustParse ("1.0.0" )
387
+ return & declcfg.Bundle {
388
+ Name : "prometheus.v1.0.0" ,
389
+ Package : "prometheus" ,
390
+ Image :
"quay.io/operatorhubio/[email protected] " ,
391
+ }, & v , nil , nil
392
+ })
393
+
394
+ reconciler .Manager = & MockManagedContentCacheManager {
395
+ cache : & MockManagedContentCache {},
396
+ }
397
+ reconciler .InstalledBundleGetter = & MockInstalledBundleGetter {
398
+ bundle : & ocv1alpha1.BundleMetadata {Name : "prometheus.v1.0.0" , Version : "1.0.0" },
399
+ }
400
+ reconciler .Applier = & MockApplier {
401
+ objs : []client.Object {},
402
+ }
403
+
404
+ res , err := reconciler .Reconcile (ctx , ctrl.Request {NamespacedName : extKey })
405
+ require .Equal (t , ctrl.Result {}, res )
406
+ require .NoError (t , err )
407
+
408
+ reconciler .Applier = & MockApplier {
409
+ err : errors .New ("apply failure" ),
410
+ }
411
+
412
+ res , err = reconciler .Reconcile (ctx , ctrl.Request {NamespacedName : extKey })
413
+ require .Equal (t , ctrl.Result {}, res )
414
+ require .Error (t , err )
415
+
416
+ t .Log ("By fetching updated cluster extension after reconcile" )
417
+ require .NoError (t , cl .Get (ctx , extKey , clusterExtension ))
418
+
419
+ t .Log ("By checking the status fields" )
420
+ expectedBundleMetadata := ocv1alpha1.BundleMetadata {Name : "prometheus.v1.0.0" , Version : "1.0.0" }
421
+ require .Equal (t , expectedBundleMetadata , clusterExtension .Status .Resolution .Bundle )
422
+ require .Equal (t , expectedBundleMetadata , clusterExtension .Status .Install .Bundle )
423
+
424
+ t .Log ("By checking the expected installed conditions" )
425
+ installedCond := apimeta .FindStatusCondition (clusterExtension .Status .Conditions , ocv1alpha1 .TypeInstalled )
426
+ require .NotNil (t , installedCond )
427
+ require .Equal (t , metav1 .ConditionTrue , installedCond .Status )
428
+ require .Equal (t , ocv1alpha1 .ReasonSuccess , installedCond .Reason )
429
+
430
+ t .Log ("By checking the expected progressing conditions" )
431
+ progressingCond := apimeta .FindStatusCondition (clusterExtension .Status .Conditions , ocv1alpha1 .TypeProgressing )
432
+ require .NotNil (t , progressingCond )
433
+ require .Equal (t , metav1 .ConditionTrue , progressingCond .Status )
434
+ require .Equal (t , ocv1alpha1 .ReasonRetrying , progressingCond .Reason )
435
+ require .Contains (t , progressingCond .Message , fmt .Sprintf ("for resolved bundle %q with version %q" , expectedBundleMetadata .Name , expectedBundleMetadata .Version ))
436
+
437
+ require .NoError (t , cl .DeleteAllOf (ctx , & ocv1alpha1.ClusterExtension {}))
438
+ }
439
+
339
440
func TestClusterExtensionManagerFailed (t * testing.T ) {
340
441
cl , reconciler := newClientAndReconciler (t )
341
442
reconciler .Unpacker = & MockUnpacker {
@@ -591,6 +692,107 @@ func TestClusterExtensionInstallationSucceeds(t *testing.T) {
591
692
require .NoError (t , cl .DeleteAllOf (ctx , & ocv1alpha1.ClusterExtension {}))
592
693
}
593
694
695
+ func TestClusterExtensionDeleteFinalizerFails (t * testing.T ) {
696
+ cl , reconciler := newClientAndReconciler (t )
697
+ reconciler .Unpacker = & MockUnpacker {
698
+ result : & source.Result {
699
+ State : source .StateUnpacked ,
700
+ Bundle : fstest.MapFS {},
701
+ },
702
+ }
703
+
704
+ ctx := context .Background ()
705
+ extKey := types.NamespacedName {Name : fmt .Sprintf ("cluster-extension-test-%s" , rand .String (8 ))}
706
+
707
+ t .Log ("When the cluster extension specifies a channel with version that exist" )
708
+ t .Log ("By initializing cluster state" )
709
+ pkgName := "prometheus"
710
+ pkgVer := "1.0.0"
711
+ pkgChan := "beta"
712
+ namespace := fmt .Sprintf ("test-ns-%s" , rand .String (8 ))
713
+ serviceAccount := fmt .Sprintf ("test-sa-%s" , rand .String (8 ))
714
+
715
+ clusterExtension := & ocv1alpha1.ClusterExtension {
716
+ ObjectMeta : metav1.ObjectMeta {Name : extKey .Name },
717
+ Spec : ocv1alpha1.ClusterExtensionSpec {
718
+ Source : ocv1alpha1.SourceConfig {
719
+ SourceType : "Catalog" ,
720
+ Catalog : & ocv1alpha1.CatalogSource {
721
+ PackageName : pkgName ,
722
+ Version : pkgVer ,
723
+ Channels : []string {pkgChan },
724
+ },
725
+ },
726
+ Install : ocv1alpha1.ClusterExtensionInstallConfig {
727
+ Namespace : namespace ,
728
+ ServiceAccount : ocv1alpha1.ServiceAccountReference {
729
+ Name : serviceAccount ,
730
+ },
731
+ },
732
+ },
733
+ }
734
+ err := cl .Create (ctx , clusterExtension )
735
+ require .NoError (t , err )
736
+ t .Log ("It sets resolution success status" )
737
+ t .Log ("By running reconcile" )
738
+ reconciler .Resolver = resolve .Func (func (_ context.Context , _ * ocv1alpha1.ClusterExtension , _ * ocv1alpha1.BundleMetadata ) (* declcfg.Bundle , * bsemver.Version , * declcfg.Deprecation , error ) {
739
+ v := bsemver .MustParse ("1.0.0" )
740
+ return & declcfg.Bundle {
741
+ Name : "prometheus.v1.0.0" ,
742
+ Package : "prometheus" ,
743
+ Image :
"quay.io/operatorhubio/[email protected] " ,
744
+ }, & v , nil , nil
745
+ })
746
+ fakeFinalizer := "fake.testfinalizer.io"
747
+ finalizersMessage := "still have finalizers"
748
+ reconciler .Applier = & MockApplier {
749
+ objs : []client.Object {},
750
+ }
751
+ reconciler .Manager = & MockManagedContentCacheManager {
752
+ cache : & MockManagedContentCache {},
753
+ }
754
+ reconciler .InstalledBundleGetter = & MockInstalledBundleGetter {
755
+ bundle : & ocv1alpha1.BundleMetadata {Name : "prometheus.v1.0.0" , Version : "1.0.0" },
756
+ }
757
+ err = reconciler .Finalizers .Register (fakeFinalizer , finalizers .FinalizerFunc (func (ctx context.Context , obj client.Object ) (crfinalizer.Result , error ) {
758
+ return crfinalizer.Result {}, errors .New (finalizersMessage )
759
+ }))
760
+
761
+ require .NoError (t , err )
762
+
763
+ // Reconcile twice to simulate installing the ClusterExtension and loading in the finalizers
764
+ res , err := reconciler .Reconcile (ctx , ctrl.Request {NamespacedName : extKey })
765
+ require .Equal (t , ctrl.Result {}, res )
766
+ require .NoError (t , err )
767
+ res , err = reconciler .Reconcile (ctx , ctrl.Request {NamespacedName : extKey })
768
+ require .Equal (t , ctrl.Result {}, res )
769
+ require .NoError (t , err )
770
+
771
+ t .Log ("By fetching updated cluster extension after first reconcile" )
772
+ require .NoError (t , cl .Get (ctx , extKey , clusterExtension ))
773
+ cond := apimeta .FindStatusCondition (clusterExtension .Status .Conditions , ocv1alpha1 .TypeInstalled )
774
+ expectedBundleMetadata := ocv1alpha1.BundleMetadata {Name : "prometheus.v1.0.0" , Version : "1.0.0" }
775
+ require .Equal (t , expectedBundleMetadata , clusterExtension .Status .Install .Bundle )
776
+ require .NotNil (t , cond )
777
+ require .Equal (t , metav1 .ConditionTrue , cond .Status )
778
+
779
+ require .NoError (t , cl .DeleteAllOf (ctx , & ocv1alpha1.ClusterExtension {}))
780
+ res , err = reconciler .Reconcile (ctx , ctrl.Request {NamespacedName : extKey })
781
+ require .Error (t , err , res )
782
+
783
+ t .Log ("By fetching updated cluster extension after second reconcile" )
784
+ require .NoError (t , cl .Get (ctx , extKey , clusterExtension ))
785
+ cond = apimeta .FindStatusCondition (clusterExtension .Status .Conditions , ocv1alpha1 .TypeInstalled )
786
+ require .Equal (t , expectedBundleMetadata , clusterExtension .Status .Install .Bundle )
787
+ require .NotNil (t , cond )
788
+ require .Equal (t , metav1 .ConditionTrue , cond .Status )
789
+ require .Equal (t , fakeFinalizer , clusterExtension .Finalizers [0 ])
790
+ cond = apimeta .FindStatusCondition (clusterExtension .Status .Conditions , ocv1alpha1 .TypeProgressing )
791
+ require .NotNil (t , cond )
792
+ require .Equal (t , metav1 .ConditionTrue , cond .Status )
793
+ require .Contains (t , cond .Message , finalizersMessage )
794
+ }
795
+
594
796
func verifyInvariants (ctx context.Context , t * testing.T , c client.Client , ext * ocv1alpha1.ClusterExtension ) {
595
797
key := client .ObjectKeyFromObject (ext )
596
798
require .NoError (t , c .Get (ctx , key , ext ))
0 commit comments