Skip to content

Commit 51b3345

Browse files
committed
test(e2e): add test verifying permissions are updated during an operator
upgrade
1 parent 53524d1 commit 51b3345

File tree

2 files changed

+398
-16
lines changed

2 files changed

+398
-16
lines changed

test/e2e/installplan_e2e_test.go

Lines changed: 377 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/blang/semver"
1111
"github.com/stretchr/testify/require"
1212
appsv1 "k8s.io/api/apps/v1"
13+
authorizationv1 "k8s.io/api/authorization/v1"
1314
corev1 "k8s.io/api/core/v1"
1415
rbacv1 "k8s.io/api/rbac/v1"
1516
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
@@ -961,7 +962,7 @@ func TestInstallPlanWithCRDSchemaChange(t *testing.T) {
961962
}
962963
}
963964

964-
func TestUpdateInstallPlan(t *testing.T) {
965+
func TestUpdateCatalogForSubscription(t *testing.T) {
965966
defer cleaner.NotifyTestComplete(t, true)
966967

967968
// crdVersionKey uniquely identifies a version within a CRD.
@@ -971,6 +972,381 @@ func TestUpdateInstallPlan(t *testing.T) {
971972
storage bool
972973
}
973974

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+
9741350
t.Run("UpdateSingleExistingCRDOwner", func(t *testing.T) {
9751351
defer cleaner.NotifyTestComplete(t, true)
9761352

0 commit comments

Comments
 (0)