@@ -13,6 +13,7 @@ import (
13
13
corev1 "k8s.io/api/core/v1"
14
14
rbacv1 "k8s.io/api/rbac/v1"
15
15
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
16
+ "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
16
17
k8serrors "k8s.io/apimachinery/pkg/api/errors"
17
18
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
18
19
"k8s.io/apimachinery/pkg/util/wait"
@@ -641,6 +642,184 @@ func TestCreateInstallPlanWithPreExistingCRDOwners(t *testing.T) {
641
642
})
642
643
}
643
644
645
+ func TestUpdateInstallPlan (t * testing.T ) {
646
+ defer cleaner .NotifyTestComplete (t , true )
647
+ t .Run ("UpdateSingleExistingCRDOwner" , func (t * testing.T ) {
648
+ defer cleaner .NotifyTestComplete (t , true )
649
+
650
+ mainPackageName := genName ("nginx-" )
651
+
652
+ mainPackageStable := fmt .Sprintf ("%s-stable" , mainPackageName )
653
+
654
+ stableChannel := "stable"
655
+
656
+ mainNamedStrategy := newNginxInstallStrategy (genName ("dep-" ), nil , nil )
657
+
658
+ crdPlural := genName ("ins-" )
659
+ crdName := crdPlural + ".cluster.com"
660
+ mainCRD := apiextensions.CustomResourceDefinition {
661
+ ObjectMeta : metav1.ObjectMeta {
662
+ Name : crdName ,
663
+ },
664
+ Spec : apiextensions.CustomResourceDefinitionSpec {
665
+ Group : "cluster.com" ,
666
+ Versions : []apiextensions.CustomResourceDefinitionVersion {
667
+ {
668
+ Name : "v1alpha1" ,
669
+ Served : true ,
670
+ Storage : true ,
671
+ },
672
+ },
673
+ Names : apiextensions.CustomResourceDefinitionNames {
674
+ Plural : crdPlural ,
675
+ Singular : crdPlural ,
676
+ Kind : crdPlural ,
677
+ ListKind : "list" + crdPlural ,
678
+ },
679
+ Scope : "Namespaced" ,
680
+ },
681
+ }
682
+
683
+ updatedCRD := apiextensions.CustomResourceDefinition {
684
+ ObjectMeta : metav1.ObjectMeta {
685
+ Name : crdName ,
686
+ },
687
+ Spec : apiextensions.CustomResourceDefinitionSpec {
688
+ Group : "cluster.com" ,
689
+ Versions : []apiextensions.CustomResourceDefinitionVersion {
690
+ {
691
+ Name : "v1alpha1" ,
692
+ Served : true ,
693
+ Storage : true ,
694
+ },
695
+ {
696
+ Name : "v1alpha2" ,
697
+ Served : true ,
698
+ Storage : false ,
699
+ },
700
+ },
701
+ Names : apiextensions.CustomResourceDefinitionNames {
702
+ Plural : crdPlural ,
703
+ Singular : crdPlural ,
704
+ Kind : crdPlural ,
705
+ ListKind : "list" + crdPlural ,
706
+ },
707
+ Scope : "Namespaced" ,
708
+ },
709
+ }
710
+
711
+ expectedCRDVersions := map [v1beta1.CustomResourceDefinitionVersion ]struct {}{}
712
+ for _ , version := range updatedCRD .Spec .Versions {
713
+ key := v1beta1.CustomResourceDefinitionVersion {
714
+ Name : version .Name ,
715
+ Served : version .Served ,
716
+ Storage : version .Storage ,
717
+ }
718
+ expectedCRDVersions [key ] = struct {}{}
719
+ }
720
+
721
+ mainCSV := newCSV (mainPackageStable , testNamespace , "" , semver .MustParse ("0.1.0" ), []apiextensions.CustomResourceDefinition {mainCRD }, nil , mainNamedStrategy )
722
+
723
+ c := newKubeClient (t )
724
+ crc := newCRClient (t )
725
+ defer func () {
726
+ require .NoError (t , crc .OperatorsV1alpha1 ().Subscriptions (testNamespace ).DeleteCollection (& metav1.DeleteOptions {}, metav1.ListOptions {}))
727
+ }()
728
+
729
+ mainCatalogName := genName ("mock-ocs-main-" )
730
+
731
+ // Create separate manifests for each CatalogSource
732
+ mainManifests := []registry.PackageManifest {
733
+ {
734
+ PackageName : mainPackageName ,
735
+ Channels : []registry.PackageChannel {
736
+ {Name : stableChannel , CurrentCSVName : mainPackageStable },
737
+ },
738
+ DefaultChannelName : stableChannel ,
739
+ },
740
+ }
741
+
742
+ // Create the catalog sources
743
+ _ , cleanupMainCatalogSource := createInternalCatalogSource (t , c , crc , mainCatalogName , testNamespace , mainManifests , []apiextensions.CustomResourceDefinition {mainCRD }, []v1alpha1.ClusterServiceVersion {mainCSV })
744
+ defer cleanupMainCatalogSource ()
745
+ // Attempt to get the catalog source before creating install plan
746
+ _ , err := fetchCatalogSource (t , crc , mainCatalogName , testNamespace , catalogSourceRegistryPodSynced )
747
+ require .NoError (t , err )
748
+
749
+ subscriptionName := genName ("sub-nginx-" )
750
+ subscriptionCleanup := createSubscriptionForCatalog (t , crc , testNamespace , subscriptionName , mainCatalogName , mainPackageName , stableChannel , "" , v1alpha1 .ApprovalAutomatic )
751
+ defer subscriptionCleanup ()
752
+
753
+ subscription , err := fetchSubscription (t , crc , testNamespace , subscriptionName , subscriptionHasInstallPlanChecker )
754
+ require .NoError (t , err )
755
+ require .NotNil (t , subscription )
756
+ require .NotNil (t , subscription .Status .InstallPlanRef )
757
+ require .Equal (t , mainCSV .GetName (), subscription .Status .CurrentCSV )
758
+
759
+ installPlanName := subscription .Status .InstallPlanRef .Name
760
+
761
+ // Wait for InstallPlan to be status: Complete before checking resource presence
762
+ fetchedInstallPlan , err := fetchInstallPlan (t , crc , installPlanName , buildInstallPlanPhaseCheckFunc (v1alpha1 .InstallPlanPhaseComplete ))
763
+ require .NoError (t , err )
764
+
765
+ require .Equal (t , v1alpha1 .InstallPlanPhaseComplete , fetchedInstallPlan .Status .Phase )
766
+
767
+ // Fetch installplan again to check for unnecessary control loops
768
+ fetchedInstallPlan , err = fetchInstallPlan (t , crc , fetchedInstallPlan .GetName (), func (fip * v1alpha1.InstallPlan ) bool {
769
+ compareResources (t , fetchedInstallPlan , fip )
770
+ return true
771
+ })
772
+ require .NoError (t , err )
773
+
774
+ // Verify CSV is created
775
+ _ , err = awaitCSV (t , crc , testNamespace , mainCSV .GetName (), csvAnyChecker )
776
+ require .NoError (t , err )
777
+
778
+ // Create new CSV to replace the one CSV
779
+ updatedCSV := newCSV (mainPackageStable + "-v2" , testNamespace , mainPackageStable , semver .MustParse ("0.1.1" ), []apiextensions.CustomResourceDefinition {mainCRD }, nil , mainNamedStrategy )
780
+
781
+ // Update manifest
782
+ updatedManifests := []registry.PackageManifest {
783
+ {
784
+ PackageName : mainPackageName ,
785
+ Channels : []registry.PackageChannel {
786
+ {Name : stableChannel , CurrentCSVName : updatedCSV .GetName ()},
787
+ },
788
+ DefaultChannelName : stableChannel ,
789
+ },
790
+ }
791
+
792
+ updateInternalCatalog (t , c , crc , mainCatalogName , testNamespace , []apiextensions.CustomResourceDefinition {updatedCRD }, []v1alpha1.ClusterServiceVersion {mainCSV , updatedCSV }, updatedManifests )
793
+
794
+ // Wait for subscription to update
795
+ updatedSubscription , err := fetchSubscription (t , crc , testNamespace , subscriptionName , subscriptionHasCurrentCSV (updatedCSV .GetName ()))
796
+ require .NoError (t , err )
797
+
798
+ // Verify installplan created and installed
799
+ fetchedUpdatedInstallPlan , err := fetchInstallPlan (t , crc , updatedSubscription .Status .InstallPlanRef .Name , buildInstallPlanPhaseCheckFunc (v1alpha1 .InstallPlanPhaseComplete ))
800
+ require .NoError (t , err )
801
+ require .NotEqual (t , fetchedInstallPlan .GetName (), fetchedUpdatedInstallPlan .GetName ())
802
+
803
+ // Wait for csv to update
804
+ _ , err = awaitCSV (t , crc , testNamespace , updatedCSV .GetName (), csvAnyChecker )
805
+ require .NoError (t , err )
806
+
807
+ // Get the CRD to see if it is updated
808
+ fetchedCRD , err := c .ApiextensionsV1beta1Interface ().ApiextensionsV1beta1 ().CustomResourceDefinitions ().Get (crdName , metav1.GetOptions {})
809
+ require .NoError (t , err )
810
+
811
+ for _ , version := range fetchedCRD .Spec .Versions {
812
+ key := v1beta1.CustomResourceDefinitionVersion {
813
+ Name : version .Name ,
814
+ Served : version .Served ,
815
+ Storage : version .Storage ,
816
+ }
817
+ _ , ok := expectedCRDVersions [key ]
818
+ require .True (t , ok , "couldn't find %v in expected CRD versions: %#v" , key , expectedCRDVersions )
819
+ }
820
+ })
821
+ }
822
+
644
823
// TestCreateInstallPlanWithPermissions creates an InstallPlan with a CSV containing a set of permissions to be resolved.
645
824
func TestCreateInstallPlanWithPermissions (t * testing.T ) {
646
825
defer cleaner .NotifyTestComplete (t , true )
0 commit comments