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