@@ -884,7 +884,7 @@ func TestOperatorGroupIntersection(t *testing.T) {
884
884
// Generate operatorGroupD in namespaceD that selects namespace D and E
885
885
// Generate csvD in namespaceD
886
886
// Wait for csvD to be successful
887
- // Wait for csvD to have a CSV with copied status in namespace D
887
+ // Wait for csvD to have a CSV with copied status in namespace E
888
888
// Wait for operatorGroupD to have providedAPI annotation with crdD's Kind.version.group
889
889
// Generate operatorGroupA in namespaceA that selects AllNamespaces
890
890
// Generate csvD in namespaceA
@@ -895,6 +895,8 @@ func TestOperatorGroupIntersection(t *testing.T) {
895
895
// Wait for csvA to be successful
896
896
// Ensure clusterroles created and aggregated for accessing provided APIs
897
897
// Wait for operatorGroupA to have providedAPI annotation with crdA's Kind.version.group in its providedAPIs annotation
898
+ // Wait for csvA to have a CSV with copied status in namespace D
899
+ // Ensure csvA retains the operatorgroup annotations for operatorgroupA
898
900
// Wait for csvA to have a CSV with copied status in namespace C
899
901
// Generate operatorGroupB in namespaceB that selects namespace C
900
902
// Generate csvB in namespaceB that owns crdA
@@ -1091,6 +1093,26 @@ func TestOperatorGroupIntersection(t *testing.T) {
1091
1093
}
1092
1094
require .NoError (t , awaitAnnotations (t , q , map [string ]string {v1 .OperatorGroupProvidedAPIsAnnotationKey : kvgA }))
1093
1095
1096
+ // Wait for csvA to have a CSV with copied status in namespace D
1097
+ csvAinNsD , err := awaitCSV (t , crc , nsD , csvA .GetName (), csvCopiedChecker )
1098
+ require .NoError (t , err )
1099
+
1100
+ // trigger a resync of operatorgropuD
1101
+ fetchedGroupD , err := crc .OperatorsV1 ().OperatorGroups (nsD ).Get (groupD .GetName (), metav1.GetOptions {})
1102
+ require .NoError (t , err )
1103
+
1104
+ fetchedGroupD .Annotations ["bump" ] = "update"
1105
+ _ , err = crc .OperatorsV1 ().OperatorGroups (nsD ).Update (fetchedGroupD )
1106
+ require .NoError (t , err )
1107
+
1108
+ // Ensure csvA retains the operatorgroup annotations for operatorgroupA
1109
+ csvAinNsD , err = awaitCSV (t , crc , nsD , csvA .GetName (), csvCopiedChecker )
1110
+ require .NoError (t , err )
1111
+
1112
+ require .Equal (t , groupA .GetName (), csvAinNsD .Annotations [v1 .OperatorGroupAnnotationKey ])
1113
+ require .Equal (t , nsA , csvAinNsD .Annotations [v1 .OperatorGroupNamespaceAnnotationKey ])
1114
+ require .Equal (t , nsA , csvAinNsD .Labels [v1alpha1 .CopiedLabelKey ])
1115
+
1094
1116
// Await csvA's copy in namespaceC
1095
1117
_ , err = awaitCSV (t , crc , nsC , csvA .GetName (), csvCopiedChecker )
1096
1118
require .NoError (t , err )
@@ -1849,3 +1871,253 @@ func TestOperatorGroupInsufficientPermissionsResolveViaServiceAccountRemoval(t *
1849
1871
})
1850
1872
require .NoError (t , err )
1851
1873
}
1874
+
1875
+ // Versions of OLM at 0.14.1 and older had a bug that would place the wrong namespace annotation on copied CSVs,
1876
+ // preventing them from being GCd. This ensures that any leftover CSVs in that state are properly cleared up.
1877
+ func TestCleanupCsvsWithBadOwnerOperatorGroups (t * testing.T ) {
1878
+ defer cleaner .NotifyTestComplete (t , true )
1879
+ c := newKubeClient (t )
1880
+ crc := newCRClient (t )
1881
+ csvName := genName ("another-csv-" ) // must be lowercase for DNS-1123 validation
1882
+
1883
+ opGroupNamespace := testNamespace
1884
+ matchingLabel := map [string ]string {"inGroup" : opGroupNamespace }
1885
+ otherNamespaceName := genName (opGroupNamespace + "-" )
1886
+
1887
+ t .Log ("Creating CRD" )
1888
+ mainCRDPlural := genName ("opgroup-" )
1889
+ mainCRD := newCRD (mainCRDPlural )
1890
+ cleanupCRD , err := createCRD (c , mainCRD )
1891
+ require .NoError (t , err )
1892
+ defer cleanupCRD ()
1893
+
1894
+ t .Logf ("Getting default operator group 'global-operators' installed via operatorgroup-default.yaml %v" , opGroupNamespace )
1895
+ operatorGroup , err := crc .OperatorsV1 ().OperatorGroups (opGroupNamespace ).Get ("global-operators" , metav1.GetOptions {})
1896
+ require .NoError (t , err )
1897
+
1898
+ expectedOperatorGroupStatus := v1.OperatorGroupStatus {
1899
+ Namespaces : []string {metav1 .NamespaceAll },
1900
+ }
1901
+
1902
+ t .Log ("Waiting on operator group to have correct status" )
1903
+ err = wait .Poll (pollInterval , pollDuration , func () (bool , error ) {
1904
+ fetched , fetchErr := crc .OperatorsV1 ().OperatorGroups (opGroupNamespace ).Get (operatorGroup .Name , metav1.GetOptions {})
1905
+ if fetchErr != nil {
1906
+ return false , fetchErr
1907
+ }
1908
+ if len (fetched .Status .Namespaces ) > 0 {
1909
+ require .ElementsMatch (t , expectedOperatorGroupStatus .Namespaces , fetched .Status .Namespaces )
1910
+ fmt .Println (fetched .Status .Namespaces )
1911
+ return true , nil
1912
+ }
1913
+ return false , nil
1914
+ })
1915
+ require .NoError (t , err )
1916
+
1917
+ t .Log ("Creating CSV" )
1918
+ // Generate permissions
1919
+ serviceAccountName := genName ("nginx-sa" )
1920
+ permissions := []v1alpha1.StrategyDeploymentPermissions {
1921
+ {
1922
+ ServiceAccountName : serviceAccountName ,
1923
+ Rules : []rbacv1.PolicyRule {
1924
+ {
1925
+ Verbs : []string {rbacv1 .VerbAll },
1926
+ APIGroups : []string {mainCRD .Spec .Group },
1927
+ Resources : []string {mainCRDPlural },
1928
+ },
1929
+ },
1930
+ },
1931
+ }
1932
+
1933
+ serviceAccount := & corev1.ServiceAccount {
1934
+ ObjectMeta : metav1.ObjectMeta {
1935
+ Namespace : opGroupNamespace ,
1936
+ Name : serviceAccountName ,
1937
+ },
1938
+ }
1939
+ role := & rbacv1.Role {
1940
+ ObjectMeta : metav1.ObjectMeta {
1941
+ Namespace : opGroupNamespace ,
1942
+ Name : serviceAccountName + "-role" ,
1943
+ },
1944
+ Rules : permissions [0 ].Rules ,
1945
+ }
1946
+ roleBinding := & rbacv1.RoleBinding {
1947
+ ObjectMeta : metav1.ObjectMeta {
1948
+ Namespace : opGroupNamespace ,
1949
+ Name : serviceAccountName + "-rb" ,
1950
+ },
1951
+ Subjects : []rbacv1.Subject {
1952
+ {
1953
+ Kind : "ServiceAccount" ,
1954
+ Name : serviceAccountName ,
1955
+ Namespace : opGroupNamespace ,
1956
+ },
1957
+ },
1958
+ RoleRef : rbacv1.RoleRef {
1959
+ Kind : "Role" ,
1960
+ Name : role .GetName (),
1961
+ },
1962
+ }
1963
+ _ , err = c .CreateServiceAccount (serviceAccount )
1964
+ require .NoError (t , err )
1965
+ defer func () {
1966
+ c .DeleteServiceAccount (serviceAccount .GetNamespace (), serviceAccount .GetName (), metav1 .NewDeleteOptions (0 ))
1967
+ }()
1968
+ createdRole , err := c .CreateRole (role )
1969
+ require .NoError (t , err )
1970
+ defer func () {
1971
+ c .DeleteRole (role .GetNamespace (), role .GetName (), metav1 .NewDeleteOptions (0 ))
1972
+ }()
1973
+ createdRoleBinding , err := c .CreateRoleBinding (roleBinding )
1974
+ require .NoError (t , err )
1975
+ defer func () {
1976
+ c .DeleteRoleBinding (roleBinding .GetNamespace (), roleBinding .GetName (), metav1 .NewDeleteOptions (0 ))
1977
+ }()
1978
+ // Create a new NamedInstallStrategy
1979
+ deploymentName := genName ("operator-deployment" )
1980
+ namedStrategy := newNginxInstallStrategy (deploymentName , permissions , nil )
1981
+
1982
+ aCSV := newCSV (csvName , opGroupNamespace , "" , semver .MustParse ("0.0.0" ), []apiextensions.CustomResourceDefinition {mainCRD }, nil , namedStrategy )
1983
+ aCSV .Labels = map [string ]string {"label" : t .Name ()}
1984
+ createdCSV , err := crc .OperatorsV1alpha1 ().ClusterServiceVersions (opGroupNamespace ).Create (& aCSV )
1985
+ require .NoError (t , err )
1986
+
1987
+ err = ownerutil .AddOwnerLabels (createdRole , createdCSV )
1988
+ require .NoError (t , err )
1989
+ _ , err = c .UpdateRole (createdRole )
1990
+ require .NoError (t , err )
1991
+
1992
+ err = ownerutil .AddOwnerLabels (createdRoleBinding , createdCSV )
1993
+ require .NoError (t , err )
1994
+ _ , err = c .UpdateRoleBinding (createdRoleBinding )
1995
+ require .NoError (t , err )
1996
+
1997
+ t .Log ("wait for CSV to succeed" )
1998
+ _ , err = fetchCSV (t , crc , createdCSV .GetName (), opGroupNamespace , csvSucceededChecker )
1999
+ require .NoError (t , err )
2000
+
2001
+ t .Log ("wait for roles to be promoted to clusterroles" )
2002
+ var fetchedRole * rbacv1.ClusterRole
2003
+ err = wait .Poll (pollInterval , pollDuration , func () (bool , error ) {
2004
+ fetchedRole , err = c .GetClusterRole (role .GetName ())
2005
+ if err != nil {
2006
+ if k8serrors .IsNotFound (err ) {
2007
+ return false , nil
2008
+ }
2009
+ return false , err
2010
+ }
2011
+ return true , nil
2012
+ })
2013
+ require .EqualValues (t , append (role .Rules , rbacv1.PolicyRule {
2014
+ Verbs : []string {"get" , "list" , "watch" },
2015
+ APIGroups : []string {"" },
2016
+ Resources : []string {"namespaces" },
2017
+ }), fetchedRole .Rules )
2018
+ var fetchedRoleBinding * rbacv1.ClusterRoleBinding
2019
+ err = wait .Poll (pollInterval , pollDuration , func () (bool , error ) {
2020
+ fetchedRoleBinding , err = c .GetClusterRoleBinding (roleBinding .GetName ())
2021
+ if err != nil {
2022
+ if k8serrors .IsNotFound (err ) {
2023
+ return false , nil
2024
+ }
2025
+ return false , err
2026
+ }
2027
+ return true , nil
2028
+ })
2029
+ require .EqualValues (t , roleBinding .Subjects , fetchedRoleBinding .Subjects )
2030
+ require .EqualValues (t , roleBinding .RoleRef .Name , fetchedRoleBinding .RoleRef .Name )
2031
+ require .EqualValues (t , "rbac.authorization.k8s.io" , fetchedRoleBinding .RoleRef .APIGroup )
2032
+ require .EqualValues (t , "ClusterRole" , fetchedRoleBinding .RoleRef .Kind )
2033
+
2034
+ t .Log ("ensure operator was granted namespace list permission" )
2035
+ res , err := c .KubernetesInterface ().AuthorizationV1 ().SubjectAccessReviews ().Create (& authorizationv1.SubjectAccessReview {
2036
+ Spec : authorizationv1.SubjectAccessReviewSpec {
2037
+ User : "system:serviceaccount:" + opGroupNamespace + ":" + serviceAccountName ,
2038
+ ResourceAttributes : & authorizationv1.ResourceAttributes {
2039
+ Group : corev1 .GroupName ,
2040
+ Version : "v1" ,
2041
+ Resource : "namespaces" ,
2042
+ Verb : "list" ,
2043
+ },
2044
+ },
2045
+ })
2046
+ require .NoError (t , err )
2047
+ require .True (t , res .Status .Allowed , "got %#v" , res .Status )
2048
+
2049
+ t .Log ("Waiting for operator namespace csv to have annotations" )
2050
+ err = wait .Poll (pollInterval , pollDuration , func () (bool , error ) {
2051
+ fetchedCSV , fetchErr := crc .OperatorsV1alpha1 ().ClusterServiceVersions (opGroupNamespace ).Get (csvName , metav1.GetOptions {})
2052
+ if fetchErr != nil {
2053
+ if errors .IsNotFound (fetchErr ) {
2054
+ return false , nil
2055
+ }
2056
+ t .Logf ("Error (in %v): %v" , testNamespace , fetchErr .Error ())
2057
+ return false , fetchErr
2058
+ }
2059
+ if checkOperatorGroupAnnotations (fetchedCSV , operatorGroup , true , corev1 .NamespaceAll ) == nil {
2060
+ return true , nil
2061
+ }
2062
+ return false , nil
2063
+ })
2064
+ require .NoError (t , err )
2065
+
2066
+ csvList , err := crc .OperatorsV1alpha1 ().ClusterServiceVersions (corev1 .NamespaceAll ).List (metav1.ListOptions {LabelSelector : fmt .Sprintf ("label=%s" , t .Name ())})
2067
+ require .NoError (t , err )
2068
+ t .Logf ("Found CSV count of %v" , len (csvList .Items ))
2069
+
2070
+ t .Logf ("Create other namespace %s" , otherNamespaceName )
2071
+ otherNamespace := corev1.Namespace {
2072
+ ObjectMeta : metav1.ObjectMeta {
2073
+ Name : otherNamespaceName ,
2074
+ Labels : matchingLabel ,
2075
+ },
2076
+ }
2077
+ _ , err = c .KubernetesInterface ().CoreV1 ().Namespaces ().Create (& otherNamespace )
2078
+ require .NoError (t , err )
2079
+ defer func () {
2080
+ err = c .KubernetesInterface ().CoreV1 ().Namespaces ().Delete (otherNamespaceName , & metav1.DeleteOptions {})
2081
+ require .NoError (t , err )
2082
+ }()
2083
+
2084
+ t .Log ("Waiting to ensure copied CSV shows up in other namespace" )
2085
+ err = wait .Poll (pollInterval , pollDuration , func () (bool , error ) {
2086
+ fetchedCSV , fetchErr := crc .OperatorsV1alpha1 ().ClusterServiceVersions (otherNamespaceName ).Get (csvName , metav1.GetOptions {})
2087
+ if fetchErr != nil {
2088
+ if errors .IsNotFound (fetchErr ) {
2089
+ return false , nil
2090
+ }
2091
+ t .Logf ("Error (in %v): %v" , otherNamespaceName , fetchErr .Error ())
2092
+ return false , fetchErr
2093
+ }
2094
+ if checkOperatorGroupAnnotations (fetchedCSV , operatorGroup , false , "" ) == nil {
2095
+ return true , nil
2096
+ }
2097
+ return false , nil
2098
+ })
2099
+ require .NoError (t , err )
2100
+
2101
+ // Give copied CSV a bad operatorgroup annotation
2102
+ fetchedCSV , err := crc .OperatorsV1alpha1 ().ClusterServiceVersions (otherNamespaceName ).Get (csvName , metav1.GetOptions {})
2103
+ require .NoError (t , err )
2104
+ fetchedCSV .Annotations [v1 .OperatorGroupNamespaceAnnotationKey ] = fetchedCSV .GetNamespace ()
2105
+ _ , err = crc .OperatorsV1alpha1 ().ClusterServiceVersions (otherNamespaceName ).Update (fetchedCSV )
2106
+ require .NoError (t , err )
2107
+
2108
+ // wait for CSV to be gc'd
2109
+ err = wait .Poll (pollInterval , 2 * pollDuration , func () (bool , error ) {
2110
+ csv , fetchErr := crc .OperatorsV1alpha1 ().ClusterServiceVersions (otherNamespaceName ).Get (csvName , metav1.GetOptions {})
2111
+ if fetchErr != nil {
2112
+ if errors .IsNotFound (fetchErr ) {
2113
+ return true , nil
2114
+ }
2115
+ t .Logf ("Error (in %v): %v" , opGroupNamespace , fetchErr .Error ())
2116
+ return false , fetchErr
2117
+ }
2118
+ t .Logf ("%#v" , csv .Annotations )
2119
+ t .Logf (csv .GetNamespace ())
2120
+ return false , nil
2121
+ })
2122
+ require .NoError (t , err )
2123
+ }
0 commit comments