@@ -7,6 +7,7 @@ package e2e
7
7
import (
8
8
"fmt"
9
9
"strconv"
10
+ "time"
10
11
11
12
"github.com/google/go-cmp/cmp"
12
13
. "github.com/onsi/ginkgo/v2"
@@ -17,11 +18,19 @@ import (
17
18
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
18
19
"k8s.io/apimachinery/pkg/types"
19
20
"k8s.io/utils/pointer"
21
+ "sigs.k8s.io/controller-runtime/pkg/client"
20
22
21
23
placementv1beta1 "go.goms.io/fleet/apis/placement/v1beta1"
22
24
"go.goms.io/fleet/pkg/controllers/clusterresourceplacement"
23
25
"go.goms.io/fleet/pkg/controllers/work"
24
26
scheduler "go.goms.io/fleet/pkg/scheduler/framework"
27
+ "go.goms.io/fleet/pkg/utils"
28
+ "go.goms.io/fleet/test/e2e/framework"
29
+ )
30
+
31
+ var (
32
+ // we are propagating large secrets from hub to member clusters the timeout needs to be large.
33
+ largeEventuallyDuration = time .Minute * 5
25
34
)
26
35
27
36
// Note that this container will run in parallel with other containers.
@@ -1227,3 +1236,234 @@ var _ = Describe("validating CRP revision history allowing multiple revisions wh
1227
1236
Eventually (finalizerRemovedActual , eventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to remove controller finalizers from CRP %s" , crpName )
1228
1237
})
1229
1238
})
1239
+
1240
+ // running spec in parallel with other specs causes timeouts.
1241
+ var _ = Describe ("validating CRP when selected resources cross the 1MB limit" , Ordered , Serial , func () {
1242
+ crpName := fmt .Sprintf (crpNameTemplate , GinkgoParallelProcess ())
1243
+ BeforeAll (func () {
1244
+ By ("creating resources for multiple resource snapshots" )
1245
+ createResourcesForMultipleResourceSnapshots ()
1246
+
1247
+ // Create the CRP.
1248
+ crp := & placementv1beta1.ClusterResourcePlacement {
1249
+ ObjectMeta : metav1.ObjectMeta {
1250
+ Name : crpName ,
1251
+ // Add a custom finalizer; this would allow us to better observe
1252
+ // the behavior of the controllers.
1253
+ Finalizers : []string {customDeletionBlockerFinalizer },
1254
+ },
1255
+ Spec : placementv1beta1.ClusterResourcePlacementSpec {
1256
+ Policy : & placementv1beta1.PlacementPolicy {
1257
+ PlacementType : placementv1beta1 .PickFixedPlacementType ,
1258
+ ClusterNames : []string {memberCluster1EastProdName , memberCluster2EastCanaryName },
1259
+ },
1260
+ ResourceSelectors : []placementv1beta1.ClusterResourceSelector {
1261
+ {
1262
+ Group : "" ,
1263
+ Kind : "Namespace" ,
1264
+ Version : "v1" ,
1265
+ Name : fmt .Sprintf (workNamespaceNameTemplate , GinkgoParallelProcess ()),
1266
+ },
1267
+ },
1268
+ },
1269
+ }
1270
+ By (fmt .Sprintf ("creating placement %s" , crpName ))
1271
+ Expect (hubClient .Create (ctx , crp )).To (Succeed (), "Failed to create CRP %s" , crpName )
1272
+ })
1273
+
1274
+ AfterAll (func () {
1275
+ By (fmt .Sprintf ("deleting placement %s" , crpName ))
1276
+ cleanupCRP (crpName )
1277
+
1278
+ By ("deleting resources created for multiple resource snapshots" )
1279
+ cleanupWorkResources ()
1280
+ })
1281
+
1282
+ It ("check if created cluster resource snapshots are as expected" , func () {
1283
+ Eventually (multipleResourceSnapshotsCreatedActual ("2" , "2" , "0" ), largeEventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to check created cluster resource snapshots" , crpName )
1284
+ })
1285
+
1286
+ It ("should update CRP status as expected" , func () {
1287
+ crpStatusUpdatedActual := crpStatusUpdatedActual (resourceIdentifiersForMultipleResourcesSnapshots (), []string {memberCluster1EastProdName , memberCluster2EastCanaryName }, nil , "0" )
1288
+ Eventually (crpStatusUpdatedActual , largeEventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to update CRP %s status as expected" , crpName )
1289
+ })
1290
+
1291
+ It ("should place the selected resources on member clusters" , func () {
1292
+ targetMemberClusters := []* framework.Cluster {memberCluster1EastProd , memberCluster2EastCanary }
1293
+ checkIfPlacedWorkResourcesOnTargetMemberClusters (targetMemberClusters )
1294
+ checkIfPlacedLargeSecretResourcesOnTargetMemberClusters (targetMemberClusters )
1295
+ })
1296
+
1297
+ It ("can delete the CRP" , func () {
1298
+ // Delete the CRP.
1299
+ crp := & placementv1beta1.ClusterResourcePlacement {
1300
+ ObjectMeta : metav1.ObjectMeta {
1301
+ Name : crpName ,
1302
+ },
1303
+ }
1304
+ Expect (hubClient .Delete (ctx , crp )).To (Succeed (), "Failed to delete CRP %s" , crpName )
1305
+ })
1306
+
1307
+ It ("should remove placed resources from all member clusters" , func () {
1308
+ targetMemberClusters := []* framework.Cluster {memberCluster1EastProd , memberCluster2EastCanary }
1309
+ checkIfRemovedWorkResourcesFromTargetMemberClusters (targetMemberClusters )
1310
+ })
1311
+
1312
+ It ("should remove controller finalizers from CRP" , func () {
1313
+ finalizerRemovedActual := allFinalizersExceptForCustomDeletionBlockerRemovedFromCRPActual ()
1314
+ Eventually (finalizerRemovedActual , largeEventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to remove controller finalizers from CRP %s" , crpName )
1315
+ })
1316
+ })
1317
+
1318
+ func createResourcesForMultipleResourceSnapshots () {
1319
+ createWorkResources ()
1320
+
1321
+ for i := 0 ; i < 3 ; i ++ {
1322
+ var secret corev1.Secret
1323
+ Expect (utils .GetObjectFromManifest ("../integration/manifests/resources/test-large-secret.yaml" , & secret )).Should (Succeed (), "Failed to read large secret from file" )
1324
+ secret .Namespace = workNamespace ().Name
1325
+ secret .Name = fmt .Sprintf (appSecretNameTemplate , i )
1326
+ Expect (hubClient .Create (ctx , & secret )).To (Succeed (), "Failed to create secret %s/%s" , secret .Name , secret .Namespace )
1327
+ }
1328
+
1329
+ // sleep for 5 seconds to ensure secrets exist to prevent flake.
1330
+ <- time .After (5 * time .Second )
1331
+ }
1332
+
1333
+ func multipleResourceSnapshotsCreatedActual (wantTotalNumberOfResourceSnapshots , wantNumberOfMasterIndexedResourceSnapshots , wantResourceIndex string ) func () error {
1334
+ crpName := fmt .Sprintf (crpNameTemplate , GinkgoParallelProcess ())
1335
+
1336
+ return func () error {
1337
+ var resourceSnapshotList placementv1beta1.ClusterResourceSnapshotList
1338
+ masterResourceSnapshotLabels := client.MatchingLabels {
1339
+ placementv1beta1 .IsLatestSnapshotLabel : strconv .FormatBool (true ),
1340
+ placementv1beta1 .CRPTrackingLabel : crpName ,
1341
+ }
1342
+ if err := hubClient .List (ctx , & resourceSnapshotList , masterResourceSnapshotLabels ); err != nil {
1343
+ return err
1344
+ }
1345
+ // there should be only one master resource snapshot.
1346
+ if len (resourceSnapshotList .Items ) != 1 {
1347
+ return fmt .Errorf ("number of master cluster resource snapshots has unexpected value: got %d, want %d" , len (resourceSnapshotList .Items ), 1 )
1348
+ }
1349
+ masterResourceSnapshot := resourceSnapshotList .Items [0 ]
1350
+ // labels to list all existing cluster resource snapshots.
1351
+ resourceSnapshotListLabels := client.MatchingLabels {placementv1beta1 .CRPTrackingLabel : crpName }
1352
+ if err := hubClient .List (ctx , & resourceSnapshotList , resourceSnapshotListLabels ); err != nil {
1353
+ return err
1354
+ }
1355
+ // ensure total number of cluster resource snapshots equals to wanted number of cluster resource snapshots
1356
+ if strconv .Itoa (len (resourceSnapshotList .Items )) != wantTotalNumberOfResourceSnapshots {
1357
+ return fmt .Errorf ("total number of cluster resource snapshots has unexpected value: got %s, want %s" , strconv .Itoa (len (resourceSnapshotList .Items )), wantTotalNumberOfResourceSnapshots )
1358
+ }
1359
+ numberOfResourceSnapshots := masterResourceSnapshot .Annotations [placementv1beta1 .NumberOfResourceSnapshotsAnnotation ]
1360
+ if numberOfResourceSnapshots != wantNumberOfMasterIndexedResourceSnapshots {
1361
+ return fmt .Errorf ("NumberOfResourceSnapshotsAnnotation in master cluster resource snapshot has unexpected value: got %s, want %s" , numberOfResourceSnapshots , wantNumberOfMasterIndexedResourceSnapshots )
1362
+ }
1363
+ masterResourceIndex := masterResourceSnapshot .Labels [placementv1beta1 .ResourceIndexLabel ]
1364
+ if masterResourceIndex != wantResourceIndex {
1365
+ return fmt .Errorf ("resource index for master cluster resource snapshot %s has unexpected value: got %s, want %s" , masterResourceSnapshot .Name , masterResourceIndex , wantResourceIndex )
1366
+ }
1367
+ // labels to list all cluster resource snapshots with master resource index.
1368
+ resourceSnapshotListLabels = client.MatchingLabels {
1369
+ placementv1beta1 .ResourceIndexLabel : masterResourceIndex ,
1370
+ placementv1beta1 .CRPTrackingLabel : crpName ,
1371
+ }
1372
+ if err := hubClient .List (ctx , & resourceSnapshotList , resourceSnapshotListLabels ); err != nil {
1373
+ return err
1374
+ }
1375
+ if strconv .Itoa (len (resourceSnapshotList .Items )) != wantNumberOfMasterIndexedResourceSnapshots {
1376
+ return fmt .Errorf ("number of cluster resource snapshots with master resource index has unexpected value: got %s, want %s" , strconv .Itoa (len (resourceSnapshotList .Items )), wantNumberOfMasterIndexedResourceSnapshots )
1377
+ }
1378
+ return nil
1379
+ }
1380
+ }
1381
+
1382
+ func resourceIdentifiersForMultipleResourcesSnapshots () []placementv1beta1.ResourceIdentifier {
1383
+ workNamespaceName := fmt .Sprintf (workNamespaceNameTemplate , GinkgoParallelProcess ())
1384
+ var placementResourceIdentifiers []placementv1beta1.ResourceIdentifier
1385
+
1386
+ for i := 2 ; i >= 0 ; i -- {
1387
+ placementResourceIdentifiers = append (placementResourceIdentifiers , placementv1beta1.ResourceIdentifier {
1388
+ Kind : "Secret" ,
1389
+ Name : fmt .Sprintf (appSecretNameTemplate , i ),
1390
+ Namespace : workNamespaceName ,
1391
+ Version : "v1" ,
1392
+ })
1393
+ }
1394
+
1395
+ placementResourceIdentifiers = append (placementResourceIdentifiers , placementv1beta1.ResourceIdentifier {
1396
+ Kind : "Namespace" ,
1397
+ Name : workNamespaceName ,
1398
+ Version : "v1" ,
1399
+ })
1400
+ placementResourceIdentifiers = append (placementResourceIdentifiers , placementv1beta1.ResourceIdentifier {
1401
+ Kind : "ConfigMap" ,
1402
+ Name : fmt .Sprintf (appConfigMapNameTemplate , GinkgoParallelProcess ()),
1403
+ Version : "v1" ,
1404
+ Namespace : workNamespaceName ,
1405
+ })
1406
+
1407
+ return placementResourceIdentifiers
1408
+ }
1409
+
1410
+ func checkIfPlacedWorkResourcesOnTargetMemberClusters (targetMemberClusters []* framework.Cluster ) {
1411
+ for idx := range targetMemberClusters {
1412
+ memberCluster := targetMemberClusters [idx ]
1413
+
1414
+ workResourcesPlacedActual := workNamespaceAndConfigMapPlacedOnClusterActual (memberCluster )
1415
+ Eventually (workResourcesPlacedActual , largeEventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to place work resources on member cluster %s" , memberCluster .ClusterName )
1416
+ }
1417
+ }
1418
+
1419
+ func checkIfPlacedLargeSecretResourcesOnTargetMemberClusters (targetMemberClusters []* framework.Cluster ) {
1420
+ for idx := range targetMemberClusters {
1421
+ memberCluster := targetMemberClusters [idx ]
1422
+
1423
+ secretsPlacedActual := secretsPlacedOnClusterActual (memberCluster )
1424
+ Eventually (secretsPlacedActual (), largeEventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to place large secrets on member cluster %s" , memberCluster .ClusterName )
1425
+ }
1426
+ }
1427
+
1428
+ func checkIfRemovedWorkResourcesFromTargetMemberClusters (targetMemberClusters []* framework.Cluster ) {
1429
+ for idx := range targetMemberClusters {
1430
+ memberCluster := targetMemberClusters [idx ]
1431
+
1432
+ workResourcesRemovedActual := workNamespaceRemovedFromClusterActual (memberCluster )
1433
+ Eventually (workResourcesRemovedActual , largeEventuallyDuration , eventuallyInterval ).Should (Succeed (), "Failed to remove work resources from member cluster %s" , memberCluster .ClusterName )
1434
+ }
1435
+ }
1436
+
1437
+ func secretsPlacedOnClusterActual (cluster * framework.Cluster ) func () error {
1438
+ workNamespaceName := fmt .Sprintf (workNamespaceNameTemplate , GinkgoParallelProcess ())
1439
+ return func () error {
1440
+ for i := 0 ; i < 3 ; i ++ {
1441
+ if err := validateSecretOnCluster (cluster , types.NamespacedName {Name : fmt .Sprintf (appSecretNameTemplate , i ), Namespace : workNamespaceName }); err != nil {
1442
+ return err
1443
+ }
1444
+ }
1445
+ return nil
1446
+ }
1447
+ }
1448
+
1449
+ func validateSecretOnCluster (cluster * framework.Cluster , name types.NamespacedName ) error {
1450
+ secret := & corev1.Secret {}
1451
+ if err := cluster .KubeClient .Get (ctx , name , secret ); err != nil {
1452
+ return err
1453
+ }
1454
+
1455
+ // Use the object created in the hub cluster as reference.
1456
+ wantSecret := & corev1.Secret {}
1457
+ if err := hubClient .Get (ctx , name , wantSecret ); err != nil {
1458
+ return err
1459
+ }
1460
+ if diff := cmp .Diff (
1461
+ secret , wantSecret ,
1462
+ ignoreObjectMetaAutoGeneratedFields ,
1463
+ ignoreObjectMetaAnnotationField ,
1464
+ ); diff != "" {
1465
+ return fmt .Errorf ("app secret %s diff (-got, +want): %s" , name .Name , diff )
1466
+ }
1467
+
1468
+ return nil
1469
+ }
0 commit comments