@@ -10,6 +10,7 @@ import (
10
10
"github.com/blang/semver"
11
11
"github.com/stretchr/testify/require"
12
12
appsv1 "k8s.io/api/apps/v1"
13
+ authorizationv1 "k8s.io/api/authorization/v1"
13
14
corev1 "k8s.io/api/core/v1"
14
15
rbacv1 "k8s.io/api/rbac/v1"
15
16
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
@@ -961,7 +962,7 @@ func TestInstallPlanWithCRDSchemaChange(t *testing.T) {
961
962
}
962
963
}
963
964
964
- func TestUpdateInstallPlan (t * testing.T ) {
965
+ func TestUpdateCatalogForSubscription (t * testing.T ) {
965
966
defer cleaner .NotifyTestComplete (t , true )
966
967
967
968
// crdVersionKey uniquely identifies a version within a CRD.
@@ -971,6 +972,381 @@ func TestUpdateInstallPlan(t *testing.T) {
971
972
storage bool
972
973
}
973
974
975
+ t .Run ("AmplifyPermissions" , func (t * testing.T ) {
976
+ defer cleaner .NotifyTestComplete (t , true )
977
+
978
+ c := newKubeClient (t )
979
+ crc := newCRClient (t )
980
+ defer func () {
981
+ require .NoError (t , crc .OperatorsV1alpha1 ().Subscriptions (testNamespace ).DeleteCollection (& metav1.DeleteOptions {}, metav1.ListOptions {}))
982
+ }()
983
+
984
+ // Build initial catalog
985
+ mainPackageName := genName ("nginx-amplify-" )
986
+ mainPackageStable := fmt .Sprintf ("%s-stable" , mainPackageName )
987
+ stableChannel := "stable"
988
+ crdPlural := genName ("ins-amplify-" )
989
+ crdName := crdPlural + ".cluster.com"
990
+ mainCRD := apiextensions.CustomResourceDefinition {
991
+ ObjectMeta : metav1.ObjectMeta {
992
+ Name : crdName ,
993
+ },
994
+ Spec : apiextensions.CustomResourceDefinitionSpec {
995
+ Group : "cluster.com" ,
996
+ Versions : []apiextensions.CustomResourceDefinitionVersion {
997
+ {
998
+ Name : "v1alpha1" ,
999
+ Served : true ,
1000
+ Storage : true ,
1001
+ },
1002
+ },
1003
+ Names : apiextensions.CustomResourceDefinitionNames {
1004
+ Plural : crdPlural ,
1005
+ Singular : crdPlural ,
1006
+ Kind : crdPlural ,
1007
+ ListKind : "list" + crdPlural ,
1008
+ },
1009
+ Scope : "Namespaced" ,
1010
+ },
1011
+ }
1012
+
1013
+ // Generate permissions
1014
+ serviceAccountName := genName ("nginx-sa" )
1015
+ permissions := []install.StrategyDeploymentPermissions {
1016
+ {
1017
+ ServiceAccountName : serviceAccountName ,
1018
+ Rules : []rbacv1.PolicyRule {
1019
+ {
1020
+ Verbs : []string {rbac .VerbAll },
1021
+ APIGroups : []string {"cluster.com" },
1022
+ Resources : []string {crdPlural },
1023
+ },
1024
+ },
1025
+ },
1026
+ }
1027
+ // Generate permissions
1028
+ clusterPermissions := []install.StrategyDeploymentPermissions {
1029
+ {
1030
+ ServiceAccountName : serviceAccountName ,
1031
+ Rules : []rbacv1.PolicyRule {
1032
+ {
1033
+ Verbs : []string {rbac .VerbAll },
1034
+ APIGroups : []string {"cluster.com" },
1035
+ Resources : []string {crdPlural },
1036
+ },
1037
+ },
1038
+ },
1039
+ }
1040
+
1041
+ // Create the catalog sources
1042
+ mainNamedStrategy := newNginxInstallStrategy (genName ("dep-" ), permissions , clusterPermissions )
1043
+ mainCSV := newCSV (mainPackageStable , testNamespace , "" , semver .MustParse ("0.1.0" ), nil , nil , mainNamedStrategy )
1044
+ mainCatalogName := genName ("mock-ocs-amplify-" )
1045
+ mainManifests := []registry.PackageManifest {
1046
+ {
1047
+ PackageName : mainPackageName ,
1048
+ Channels : []registry.PackageChannel {
1049
+ {Name : stableChannel , CurrentCSVName : mainCSV .GetName ()},
1050
+ },
1051
+ DefaultChannelName : stableChannel ,
1052
+ },
1053
+ }
1054
+ _ , cleanupMainCatalogSource := createInternalCatalogSource (t , c , crc , mainCatalogName , testNamespace , mainManifests , []apiextensions.CustomResourceDefinition {mainCRD }, []v1alpha1.ClusterServiceVersion {mainCSV })
1055
+ defer cleanupMainCatalogSource ()
1056
+ // Attempt to get the catalog source before creating install plan
1057
+ _ , err := fetchCatalogSource (t , crc , mainCatalogName , testNamespace , catalogSourceRegistryPodSynced )
1058
+ require .NoError (t , err )
1059
+
1060
+ subscriptionName := genName ("sub-nginx-update-perms1" )
1061
+ subscriptionCleanup := createSubscriptionForCatalog (t , crc , testNamespace , subscriptionName , mainCatalogName , mainPackageName , stableChannel , "" , v1alpha1 .ApprovalAutomatic )
1062
+ defer subscriptionCleanup ()
1063
+
1064
+ subscription , err := fetchSubscription (t , crc , testNamespace , subscriptionName , subscriptionHasInstallPlanChecker )
1065
+ require .NoError (t , err )
1066
+ require .NotNil (t , subscription )
1067
+ require .NotNil (t , subscription .Status .InstallPlanRef )
1068
+ require .Equal (t , mainCSV .GetName (), subscription .Status .CurrentCSV )
1069
+
1070
+ installPlanName := subscription .Status .InstallPlanRef .Name
1071
+
1072
+ // Wait for InstallPlan to be status: Complete before checking resource presence
1073
+ fetchedInstallPlan , err := fetchInstallPlan (t , crc , installPlanName , buildInstallPlanPhaseCheckFunc (v1alpha1 .InstallPlanPhaseComplete ))
1074
+ require .NoError (t , err )
1075
+
1076
+ require .Equal (t , v1alpha1 .InstallPlanPhaseComplete , fetchedInstallPlan .Status .Phase )
1077
+
1078
+ // Verify CSV is created
1079
+ _ , err = awaitCSV (t , crc , testNamespace , mainCSV .GetName (), csvSucceededChecker )
1080
+ require .NoError (t , err )
1081
+
1082
+ // Update CatalogSource with a new CSV with more permissions
1083
+ updatedPermissions := []install.StrategyDeploymentPermissions {
1084
+ {
1085
+ ServiceAccountName : serviceAccountName ,
1086
+ Rules : []rbacv1.PolicyRule {
1087
+ {
1088
+ Verbs : []string {rbac .VerbAll },
1089
+ APIGroups : []string {"cluster.com" },
1090
+ Resources : []string {crdPlural },
1091
+ },
1092
+ {
1093
+ Verbs : []string {rbac .VerbAll },
1094
+ APIGroups : []string {"local.cluster.com" },
1095
+ Resources : []string {"locals" },
1096
+ },
1097
+ },
1098
+ },
1099
+ }
1100
+ updatedClusterPermissions := []install.StrategyDeploymentPermissions {
1101
+ {
1102
+ ServiceAccountName : serviceAccountName ,
1103
+ Rules : []rbacv1.PolicyRule {
1104
+ {
1105
+ Verbs : []string {rbac .VerbAll },
1106
+ APIGroups : []string {"cluster.com" },
1107
+ Resources : []string {crdPlural },
1108
+ },
1109
+ {
1110
+ Verbs : []string {rbac .VerbAll },
1111
+ APIGroups : []string {"two.cluster.com" },
1112
+ Resources : []string {"twos" },
1113
+ },
1114
+ },
1115
+ },
1116
+ }
1117
+
1118
+ // Create the catalog sources
1119
+ updatedNamedStrategy := newNginxInstallStrategy (genName ("dep-" ), updatedPermissions , updatedClusterPermissions )
1120
+ updatedCSV := newCSV (mainPackageStable + "-next" , testNamespace , mainCSV .GetName (), semver .MustParse ("0.2.0" ), []apiextensions.CustomResourceDefinition {mainCRD }, nil , updatedNamedStrategy )
1121
+ updatedManifests := []registry.PackageManifest {
1122
+ {
1123
+ PackageName : mainPackageName ,
1124
+ Channels : []registry.PackageChannel {
1125
+ {Name : stableChannel , CurrentCSVName : updatedCSV .GetName ()},
1126
+ },
1127
+ DefaultChannelName : stableChannel ,
1128
+ },
1129
+ }
1130
+ // Update catalog with updated CSV with more permissions
1131
+ updateInternalCatalog (t , c , crc , mainCatalogName , testNamespace , []apiextensions.CustomResourceDefinition {mainCRD }, []v1alpha1.ClusterServiceVersion {mainCSV , updatedCSV }, updatedManifests )
1132
+
1133
+ _ , err = fetchSubscription (t , crc , testNamespace , subscriptionName , subscriptionHasInstallPlanDifferentChecker (fetchedInstallPlan .GetName ()))
1134
+ require .NoError (t , err )
1135
+
1136
+ updatedInstallPlanName := subscription .Status .InstallPlanRef .Name
1137
+
1138
+ // Wait for InstallPlan to be status: Complete before checking resource presence
1139
+ fetchedUpdatedInstallPlan , err := fetchInstallPlan (t , crc , updatedInstallPlanName , buildInstallPlanPhaseCheckFunc (v1alpha1 .InstallPlanPhaseComplete ))
1140
+ require .NoError (t , err )
1141
+ require .Equal (t , v1alpha1 .InstallPlanPhaseComplete , fetchedUpdatedInstallPlan .Status .Phase )
1142
+
1143
+ // Wait for csv to update
1144
+ _ , err = awaitCSV (t , crc , testNamespace , updatedCSV .GetName (), csvSucceededChecker )
1145
+ require .NoError (t , err )
1146
+
1147
+ // If the CSV is succeeded, we successfully rolled out the RBAC changes
1148
+ })
1149
+
1150
+ t .Run ("AttenuatePermissions" , func (t * testing.T ) {
1151
+ defer cleaner .NotifyTestComplete (t , true )
1152
+
1153
+ c := newKubeClient (t )
1154
+ crc := newCRClient (t )
1155
+ defer func () {
1156
+ require .NoError (t , crc .OperatorsV1alpha1 ().Subscriptions (testNamespace ).DeleteCollection (& metav1.DeleteOptions {}, metav1.ListOptions {}))
1157
+ }()
1158
+
1159
+ // Build initial catalog
1160
+ mainPackageName := genName ("nginx-attenuate-" )
1161
+ mainPackageStable := fmt .Sprintf ("%s-stable" , mainPackageName )
1162
+ stableChannel := "stable"
1163
+ crdPlural := genName ("ins-attenuate-" )
1164
+ crdName := crdPlural + ".cluster.com"
1165
+ mainCRD := apiextensions.CustomResourceDefinition {
1166
+ ObjectMeta : metav1.ObjectMeta {
1167
+ Name : crdName ,
1168
+ },
1169
+ Spec : apiextensions.CustomResourceDefinitionSpec {
1170
+ Group : "cluster.com" ,
1171
+ Versions : []apiextensions.CustomResourceDefinitionVersion {
1172
+ {
1173
+ Name : "v1alpha1" ,
1174
+ Served : true ,
1175
+ Storage : true ,
1176
+ },
1177
+ },
1178
+ Names : apiextensions.CustomResourceDefinitionNames {
1179
+ Plural : crdPlural ,
1180
+ Singular : crdPlural ,
1181
+ Kind : crdPlural ,
1182
+ ListKind : "list" + crdPlural ,
1183
+ },
1184
+ Scope : "Namespaced" ,
1185
+ },
1186
+ }
1187
+
1188
+ // Generate permissions
1189
+ serviceAccountName := genName ("nginx-sa" )
1190
+ permissions := []install.StrategyDeploymentPermissions {
1191
+ {
1192
+ ServiceAccountName : serviceAccountName ,
1193
+ Rules : []rbacv1.PolicyRule {
1194
+ {
1195
+ Verbs : []string {rbac .VerbAll },
1196
+ APIGroups : []string {"cluster.com" },
1197
+ Resources : []string {crdPlural },
1198
+ },
1199
+ {
1200
+ Verbs : []string {rbac .VerbAll },
1201
+ APIGroups : []string {"local.cluster.com" },
1202
+ Resources : []string {"locals" },
1203
+ },
1204
+ },
1205
+ },
1206
+ }
1207
+ // Generate permissions
1208
+ clusterPermissions := []install.StrategyDeploymentPermissions {
1209
+ {
1210
+ ServiceAccountName : serviceAccountName ,
1211
+ Rules : []rbacv1.PolicyRule {
1212
+ {
1213
+ Verbs : []string {rbac .VerbAll },
1214
+ APIGroups : []string {"cluster.com" },
1215
+ Resources : []string {crdPlural },
1216
+ },
1217
+ {
1218
+ Verbs : []string {rbac .VerbAll },
1219
+ APIGroups : []string {"two.cluster.com" },
1220
+ Resources : []string {"twos" },
1221
+ },
1222
+ },
1223
+ },
1224
+ }
1225
+
1226
+ // Create the catalog sources
1227
+ mainNamedStrategy := newNginxInstallStrategy (genName ("dep-" ), permissions , clusterPermissions )
1228
+ mainCSV := newCSV (mainPackageStable , testNamespace , "" , semver .MustParse ("0.1.0" ), nil , nil , mainNamedStrategy )
1229
+ mainCatalogName := genName ("mock-ocs-main-update-perms1-" )
1230
+ mainManifests := []registry.PackageManifest {
1231
+ {
1232
+ PackageName : mainPackageName ,
1233
+ Channels : []registry.PackageChannel {
1234
+ {Name : stableChannel , CurrentCSVName : mainCSV .GetName ()},
1235
+ },
1236
+ DefaultChannelName : stableChannel ,
1237
+ },
1238
+ }
1239
+ _ , cleanupMainCatalogSource := createInternalCatalogSource (t , c , crc , mainCatalogName , testNamespace , mainManifests , []apiextensions.CustomResourceDefinition {mainCRD }, []v1alpha1.ClusterServiceVersion {mainCSV })
1240
+ defer cleanupMainCatalogSource ()
1241
+ // Attempt to get the catalog source before creating install plan
1242
+ _ , err := fetchCatalogSource (t , crc , mainCatalogName , testNamespace , catalogSourceRegistryPodSynced )
1243
+ require .NoError (t , err )
1244
+
1245
+ subscriptionName := genName ("sub-nginx-update-perms1" )
1246
+ subscriptionCleanup := createSubscriptionForCatalog (t , crc , testNamespace , subscriptionName , mainCatalogName , mainPackageName , stableChannel , "" , v1alpha1 .ApprovalAutomatic )
1247
+ defer subscriptionCleanup ()
1248
+
1249
+ subscription , err := fetchSubscription (t , crc , testNamespace , subscriptionName , subscriptionHasInstallPlanChecker )
1250
+ require .NoError (t , err )
1251
+ require .NotNil (t , subscription )
1252
+ require .NotNil (t , subscription .Status .InstallPlanRef )
1253
+ require .Equal (t , mainCSV .GetName (), subscription .Status .CurrentCSV )
1254
+
1255
+ installPlanName := subscription .Status .InstallPlanRef .Name
1256
+
1257
+ // Wait for InstallPlan to be status: Complete before checking resource presence
1258
+ fetchedInstallPlan , err := fetchInstallPlan (t , crc , installPlanName , buildInstallPlanPhaseCheckFunc (v1alpha1 .InstallPlanPhaseComplete ))
1259
+ require .NoError (t , err )
1260
+
1261
+ require .Equal (t , v1alpha1 .InstallPlanPhaseComplete , fetchedInstallPlan .Status .Phase )
1262
+
1263
+ // Verify CSV is created
1264
+ _ , err = awaitCSV (t , crc , testNamespace , mainCSV .GetName (), csvSucceededChecker )
1265
+ require .NoError (t , err )
1266
+
1267
+ // Update CatalogSource with a new CSV with more permissions
1268
+ updatedPermissions := []install.StrategyDeploymentPermissions {
1269
+ {
1270
+ ServiceAccountName : serviceAccountName ,
1271
+ Rules : []rbacv1.PolicyRule {
1272
+ {
1273
+ Verbs : []string {rbac .VerbAll },
1274
+ APIGroups : []string {"local.cluster.com" },
1275
+ Resources : []string {"locals" },
1276
+ },
1277
+ },
1278
+ },
1279
+ }
1280
+ updatedClusterPermissions := []install.StrategyDeploymentPermissions {
1281
+ {
1282
+ ServiceAccountName : serviceAccountName ,
1283
+ Rules : []rbacv1.PolicyRule {
1284
+ {
1285
+ Verbs : []string {rbac .VerbAll },
1286
+ APIGroups : []string {"two.cluster.com" },
1287
+ Resources : []string {"twos" },
1288
+ },
1289
+ },
1290
+ },
1291
+ }
1292
+
1293
+ // Create the catalog sources
1294
+ updatedNamedStrategy := newNginxInstallStrategy (genName ("dep-" ), updatedPermissions , updatedClusterPermissions )
1295
+ updatedCSV := newCSV (mainPackageStable + "-next" , testNamespace , mainCSV .GetName (), semver .MustParse ("0.2.0" ), []apiextensions.CustomResourceDefinition {mainCRD }, nil , updatedNamedStrategy )
1296
+ updatedManifests := []registry.PackageManifest {
1297
+ {
1298
+ PackageName : mainPackageName ,
1299
+ Channels : []registry.PackageChannel {
1300
+ {Name : stableChannel , CurrentCSVName : updatedCSV .GetName ()},
1301
+ },
1302
+ DefaultChannelName : stableChannel ,
1303
+ },
1304
+ }
1305
+ // Update catalog with updated CSV with more permissions
1306
+ updateInternalCatalog (t , c , crc , mainCatalogName , testNamespace , []apiextensions.CustomResourceDefinition {mainCRD }, []v1alpha1.ClusterServiceVersion {mainCSV , updatedCSV }, updatedManifests )
1307
+
1308
+ // Wait for subscription to update its status
1309
+ _ , err = fetchSubscription (t , crc , testNamespace , subscriptionName , subscriptionHasInstallPlanDifferentChecker (fetchedInstallPlan .GetName ()))
1310
+ require .NoError (t , err )
1311
+
1312
+ updatedInstallPlanName := subscription .Status .InstallPlanRef .Name
1313
+
1314
+ // Wait for InstallPlan to be status: Complete before checking resource presence
1315
+ fetchedUpdatedInstallPlan , err := fetchInstallPlan (t , crc , updatedInstallPlanName , buildInstallPlanPhaseCheckFunc (v1alpha1 .InstallPlanPhaseComplete ))
1316
+ require .NoError (t , err )
1317
+ require .Equal (t , v1alpha1 .InstallPlanPhaseComplete , fetchedUpdatedInstallPlan .Status .Phase )
1318
+
1319
+ // Wait for csv to update
1320
+ _ , err = awaitCSV (t , crc , testNamespace , updatedCSV .GetName (), csvSucceededChecker )
1321
+ require .NoError (t , err )
1322
+
1323
+ // Wait for ServiceAccount to not have access anymore
1324
+ err = wait .Poll (pollInterval , pollDuration , func () (bool , error ) {
1325
+ res , err := c .KubernetesInterface ().AuthorizationV1 ().SubjectAccessReviews ().Create (& authorizationv1.SubjectAccessReview {
1326
+ Spec : authorizationv1.SubjectAccessReviewSpec {
1327
+ User : "system:serviceaccount:" + testNamespace + ":" + serviceAccountName ,
1328
+ ResourceAttributes : & authorizationv1.ResourceAttributes {
1329
+ Group : "cluster.com" ,
1330
+ Version : "v1alpha1" ,
1331
+ Resource : crdPlural ,
1332
+ Verb : rbac .VerbAll ,
1333
+ },
1334
+ },
1335
+ })
1336
+ if err != nil {
1337
+ return false , err
1338
+ }
1339
+ if res == nil {
1340
+ return false , nil
1341
+ }
1342
+ t .Log ("checking serviceaccount for permission" )
1343
+
1344
+ // should not be allowed
1345
+ return ! res .Status .Allowed , nil
1346
+ })
1347
+
1348
+ })
1349
+
974
1350
t .Run ("UpdateSingleExistingCRDOwner" , func (t * testing.T ) {
975
1351
defer cleaner .NotifyTestComplete (t , true )
976
1352
0 commit comments