...

Source file src/sigs.k8s.io/cli-utils/test/stress/thousand_namespaces_test.go

Documentation: sigs.k8s.io/cli-utils/test/stress

     1  // Copyright 2020 The Kubernetes Authors.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package stress
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"time"
    10  
    11  	. "github.com/onsi/ginkgo/v2"
    12  	. "github.com/onsi/gomega"
    13  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    14  	"k8s.io/klog/v2"
    15  	"sigs.k8s.io/cli-utils/pkg/apply"
    16  	"sigs.k8s.io/cli-utils/pkg/apply/event"
    17  	"sigs.k8s.io/cli-utils/pkg/common"
    18  	"sigs.k8s.io/cli-utils/pkg/inventory"
    19  	"sigs.k8s.io/cli-utils/test/e2e/e2eutil"
    20  	"sigs.k8s.io/cli-utils/test/e2e/invconfig"
    21  	"sigs.k8s.io/controller-runtime/pkg/client"
    22  )
    23  
    24  // thousandNamespacesTest tests a CRD and 1,000 new namespaces, each with
    25  // 1 ConfigMap and 1 CronTab in it. This uses implicit dependencies and many
    26  // namespaces with custom resources (json storage) as well and built-in
    27  // resources (proto storage).
    28  //
    29  // With the StatusWatcher, this should only needs FOUR root-scoped informers
    30  // (CRD, Namespace, ConfigMap, CronTab), For comparison, the StatusPoller used
    31  // 2,002 LISTs for each attempt (two root-scoped and two namespace-scoped per
    32  // namespace).
    33  func thousandNamespacesTest(ctx context.Context, c client.Client, invConfig invconfig.InventoryConfig, inventoryName, namespaceName string) {
    34  	By("Apply LOTS of resources")
    35  	applier := invConfig.ApplierFactoryFunc()
    36  	inventoryID := fmt.Sprintf("%s-%s", inventoryName, namespaceName)
    37  
    38  	inventoryInfo := invconfig.CreateInventoryInfo(invConfig, inventoryName, namespaceName, inventoryID)
    39  
    40  	crdObj := e2eutil.ManifestToUnstructured([]byte(cronTabCRDYaml))
    41  
    42  	resources := []*unstructured.Unstructured{crdObj}
    43  
    44  	namespaceObjTemplate := e2eutil.ManifestToUnstructured([]byte(namespaceYaml))
    45  	namespaceObjTemplate.SetLabels(map[string]string{e2eutil.TestIDLabel: inventoryID})
    46  
    47  	configMapObjTemplate := e2eutil.ManifestToUnstructured([]byte(configMapYaml))
    48  	configMapObjTemplate.SetLabels(map[string]string{e2eutil.TestIDLabel: inventoryID})
    49  
    50  	cronTabObjTemplate := e2eutil.ManifestToUnstructured([]byte(cronTabYaml))
    51  	cronTabObjTemplate.SetLabels(map[string]string{e2eutil.TestIDLabel: inventoryID})
    52  
    53  	objectCount := 1000
    54  
    55  	for i := 1; i <= objectCount; i++ {
    56  		ns := fmt.Sprintf("%s-%d", namespaceName, i)
    57  		namespaceObj := namespaceObjTemplate.DeepCopy()
    58  		namespaceObj.SetName(ns)
    59  		resources = append(resources, namespaceObj)
    60  
    61  		configMapObj := configMapObjTemplate.DeepCopy()
    62  		configMapObj.SetName(fmt.Sprintf("configmap-%d", i))
    63  		configMapObj.SetNamespace(ns)
    64  		resources = append(resources, configMapObj)
    65  
    66  		cronTabObj := cronTabObjTemplate.DeepCopy()
    67  		cronTabObj.SetName(fmt.Sprintf("crontab-%d", i))
    68  		cronTabObj.SetNamespace(ns)
    69  		resources = append(resources, cronTabObj)
    70  	}
    71  
    72  	defer func() {
    73  		// Can't delete custom resources if the CRD is still terminating
    74  		if e2eutil.UnstructuredExistsAndIsNotTerminating(ctx, c, crdObj) {
    75  			By("Cleanup CronTabs")
    76  			e2eutil.DeleteAllUnstructuredIfExists(ctx, c, cronTabObjTemplate)
    77  			By("Cleanup CRD")
    78  			e2eutil.DeleteUnstructuredIfExists(ctx, c, crdObj)
    79  		}
    80  
    81  		By("Cleanup ConfigMaps")
    82  		e2eutil.DeleteAllUnstructuredIfExists(ctx, c, configMapObjTemplate)
    83  		By("Cleanup Namespaces")
    84  		e2eutil.DeleteAllUnstructuredIfExists(ctx, c, namespaceObjTemplate)
    85  	}()
    86  
    87  	start := time.Now()
    88  
    89  	applierEvents := e2eutil.RunCollect(applier.Run(ctx, inventoryInfo, resources, apply.ApplierOptions{
    90  		// SSA reduces GET+PATCH to just PATCH, which is faster
    91  		ServerSideOptions: common.ServerSideOptions{
    92  			ServerSideApply: true,
    93  			ForceConflicts:  true,
    94  			FieldManager:    "cli-utils.kubernetes.io",
    95  		},
    96  		ReconcileTimeout: 30 * time.Minute,
    97  		EmitStatusEvents: false,
    98  	}))
    99  
   100  	duration := time.Since(start)
   101  	klog.Infof("Applier.Run execution time: %v", duration)
   102  
   103  	for _, e := range applierEvents {
   104  		Expect(e.ErrorEvent.Err).To(BeNil())
   105  	}
   106  	for _, e := range applierEvents {
   107  		Expect(e.ApplyEvent.Error).To(BeNil(), "ApplyEvent: %v", e.ApplyEvent)
   108  	}
   109  	for _, e := range applierEvents {
   110  		if e.Type == event.WaitType {
   111  			Expect(e.WaitEvent.Status).To(BeElementOf(event.ReconcilePending, event.ReconcileSuccessful), "WaitEvent: %v", e.WaitEvent)
   112  		}
   113  	}
   114  
   115  	By("Verify inventory created")
   116  	invConfig.InvSizeVerifyFunc(ctx, c, inventoryName, namespaceName, inventoryID, len(resources), len(resources))
   117  
   118  	By("Verify CRD created")
   119  	e2eutil.AssertUnstructuredExists(ctx, c, crdObj)
   120  
   121  	By(fmt.Sprintf("Verify %d Namespaces created", objectCount))
   122  	e2eutil.AssertUnstructuredCount(ctx, c, namespaceObjTemplate, objectCount)
   123  
   124  	By(fmt.Sprintf("Verify %d ConfigMaps created", objectCount))
   125  	e2eutil.AssertUnstructuredCount(ctx, c, configMapObjTemplate, objectCount)
   126  
   127  	By(fmt.Sprintf("Verify %d CronTabs created", objectCount))
   128  	e2eutil.AssertUnstructuredCount(ctx, c, cronTabObjTemplate, objectCount)
   129  
   130  	By("Destroy LOTS of resources")
   131  	destroyer := invConfig.DestroyerFactoryFunc()
   132  
   133  	start = time.Now()
   134  
   135  	destroyerEvents := e2eutil.RunCollect(destroyer.Run(ctx, inventoryInfo, apply.DestroyerOptions{
   136  		InventoryPolicy: inventory.PolicyAdoptIfNoInventory,
   137  		DeleteTimeout:   30 * time.Minute,
   138  	}))
   139  
   140  	duration = time.Since(start)
   141  	klog.Infof("Destroyer.Run execution time: %v", duration)
   142  
   143  	for _, e := range destroyerEvents {
   144  		Expect(e.ErrorEvent.Err).To(BeNil())
   145  	}
   146  	for _, e := range destroyerEvents {
   147  		Expect(e.PruneEvent.Error).To(BeNil(), "PruneEvent: %v", e.PruneEvent)
   148  	}
   149  	for _, e := range destroyerEvents {
   150  		if e.Type == event.WaitType {
   151  			Expect(e.WaitEvent.Status).To(BeElementOf(event.ReconcilePending, event.ReconcileSuccessful), "WaitEvent: %v", e.WaitEvent)
   152  		}
   153  	}
   154  
   155  	By("Verify inventory deleted")
   156  	invConfig.InvNotExistsFunc(ctx, c, inventoryName, namespaceName, inventoryID)
   157  
   158  	By(fmt.Sprintf("Verify %d CronTabs deleted", objectCount))
   159  	e2eutil.AssertUnstructuredCount(ctx, c, cronTabObjTemplate, 0)
   160  
   161  	By(fmt.Sprintf("Verify %d ConfigMaps deleted", objectCount))
   162  	e2eutil.AssertUnstructuredCount(ctx, c, configMapObjTemplate, 0)
   163  
   164  	By(fmt.Sprintf("Verify %d Namespaces deleted", objectCount))
   165  	e2eutil.AssertUnstructuredCount(ctx, c, namespaceObjTemplate, 0)
   166  
   167  	By("Verify CRD deleted")
   168  	e2eutil.AssertUnstructuredDoesNotExist(ctx, c, crdObj)
   169  }
   170  

View as plain text