mirror of https://github.com/fluxcd/cli-utils.git
chore: add stress test
- Stress test tests 1,000 Namespaces, CofnigMaps, & CronTabs (CR) - Stress test is a new test suite with its own make entrypoint - Refactor shared test code so the e2e and stress tests can both use it - Update test client QPS to 20 (from 5)
This commit is contained in:
parent
d84328fc3c
commit
34a8a7b334
4
Makefile
4
Makefile
|
|
@ -63,6 +63,10 @@ test-e2e: $(MYGOBIN)/ginkgo $(MYGOBIN)/kind
|
|||
kind delete cluster --name=cli-utils-e2e && kind create cluster --name=cli-utils-e2e
|
||||
$(GOPATH)/bin/ginkgo ./test/e2e/...
|
||||
|
||||
test-stress: $(MYGOBIN)/ginkgo $(MYGOBIN)/kind
|
||||
kind delete cluster --name=cli-utils-e2e && kind create cluster --name=cli-utils-e2e
|
||||
$(GOPATH)/bin/ginkgo -v ./test/stress/... -- -v 5
|
||||
|
||||
vet:
|
||||
go vet ./...
|
||||
|
||||
|
|
|
|||
|
|
@ -17,22 +17,24 @@ import (
|
|||
"sigs.k8s.io/cli-utils/pkg/kstatus/status"
|
||||
"sigs.k8s.io/cli-utils/pkg/object"
|
||||
"sigs.k8s.io/cli-utils/pkg/testutil"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/e2eutil"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/invconfig"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
func applyAndDestroyTest(ctx context.Context, c client.Client, invConfig InventoryConfig, inventoryName, namespaceName string) {
|
||||
func applyAndDestroyTest(ctx context.Context, c client.Client, invConfig invconfig.InventoryConfig, inventoryName, namespaceName string) {
|
||||
By("Apply resources")
|
||||
applier := invConfig.ApplierFactoryFunc()
|
||||
inventoryID := fmt.Sprintf("%s-%s", inventoryName, namespaceName)
|
||||
|
||||
inventoryInfo := createInventoryInfo(invConfig, inventoryName, namespaceName, inventoryID)
|
||||
inventoryInfo := invconfig.CreateInventoryInfo(invConfig, inventoryName, namespaceName, inventoryID)
|
||||
|
||||
deployment1Obj := withNamespace(manifestToUnstructured(deployment1), namespaceName)
|
||||
deployment1Obj := e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(deployment1), namespaceName)
|
||||
resources := []*unstructured.Unstructured{
|
||||
deployment1Obj,
|
||||
}
|
||||
|
||||
applierEvents := runCollect(applier.Run(ctx, inventoryInfo, resources, apply.ApplierOptions{
|
||||
applierEvents := e2eutil.RunCollect(applier.Run(ctx, inventoryInfo, resources, apply.ApplierOptions{
|
||||
ReconcileTimeout: 2 * time.Minute,
|
||||
EmitStatusEvents: true,
|
||||
}))
|
||||
|
|
@ -184,7 +186,7 @@ func applyAndDestroyTest(ctx context.Context, c client.Client, invConfig Invento
|
|||
Expect(received).To(testutil.Equal(expEvents))
|
||||
|
||||
By("Verify deployment created")
|
||||
assertUnstructuredExists(ctx, c, deployment1Obj)
|
||||
e2eutil.AssertUnstructuredExists(ctx, c, deployment1Obj)
|
||||
|
||||
By("Verify inventory")
|
||||
invConfig.InvSizeVerifyFunc(ctx, c, inventoryName, namespaceName, inventoryID, 1, 1)
|
||||
|
|
@ -193,7 +195,7 @@ func applyAndDestroyTest(ctx context.Context, c client.Client, invConfig Invento
|
|||
destroyer := invConfig.DestroyerFactoryFunc()
|
||||
|
||||
options := apply.DestroyerOptions{InventoryPolicy: inventory.PolicyAdoptIfNoInventory}
|
||||
destroyerEvents := runCollect(destroyer.Run(ctx, inventoryInfo, options))
|
||||
destroyerEvents := e2eutil.RunCollect(destroyer.Run(ctx, inventoryInfo, options))
|
||||
|
||||
expEvents = []testutil.ExpEvent{
|
||||
{
|
||||
|
|
@ -288,16 +290,5 @@ func applyAndDestroyTest(ctx context.Context, c client.Client, invConfig Invento
|
|||
Expect(testutil.EventsToExpEvents(destroyerEvents)).To(testutil.Equal(expEvents))
|
||||
|
||||
By("Verify deployment deleted")
|
||||
assertUnstructuredDoesNotExist(ctx, c, deployment1Obj)
|
||||
}
|
||||
|
||||
func createInventoryInfo(invConfig InventoryConfig, inventoryName, namespaceName, inventoryID string) inventory.Info {
|
||||
switch invConfig.Strategy {
|
||||
case inventory.NameStrategy:
|
||||
return invConfig.InvWrapperFunc(invConfig.FactoryFunc(inventoryName, namespaceName, randomString("inventory-")))
|
||||
case inventory.LabelStrategy:
|
||||
return invConfig.InvWrapperFunc(invConfig.FactoryFunc(randomString("inventory-"), namespaceName, inventoryID))
|
||||
default:
|
||||
panic(fmt.Errorf("unknown inventory strategy %q", invConfig.Strategy))
|
||||
}
|
||||
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, deployment1Obj)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,23 +16,25 @@ import (
|
|||
"sigs.k8s.io/cli-utils/pkg/apply/event"
|
||||
"sigs.k8s.io/cli-utils/pkg/object"
|
||||
"sigs.k8s.io/cli-utils/pkg/testutil"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/e2eutil"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/invconfig"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
func continueOnErrorTest(ctx context.Context, c client.Client, invConfig InventoryConfig, inventoryName, namespaceName string) {
|
||||
func continueOnErrorTest(ctx context.Context, c client.Client, invConfig invconfig.InventoryConfig, inventoryName, namespaceName string) {
|
||||
By("apply an invalid CRD")
|
||||
applier := invConfig.ApplierFactoryFunc()
|
||||
|
||||
inv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(inventoryName, namespaceName, "test"))
|
||||
|
||||
invalidCrdObj := manifestToUnstructured(invalidCrd)
|
||||
pod1Obj := withNamespace(manifestToUnstructured(pod1), namespaceName)
|
||||
invalidCrdObj := e2eutil.ManifestToUnstructured(invalidCrd)
|
||||
pod1Obj := e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod1), namespaceName)
|
||||
resources := []*unstructured.Unstructured{
|
||||
invalidCrdObj,
|
||||
pod1Obj,
|
||||
}
|
||||
|
||||
applierEvents := runCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{}))
|
||||
applierEvents := e2eutil.RunCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{}))
|
||||
|
||||
expEvents := []testutil.ExpEvent{
|
||||
{
|
||||
|
|
@ -167,8 +169,8 @@ func continueOnErrorTest(ctx context.Context, c client.Client, invConfig Invento
|
|||
Expect(receivedEvents).To(testutil.Equal(expEvents))
|
||||
|
||||
By("Verify pod1 created")
|
||||
assertUnstructuredExists(ctx, c, pod1Obj)
|
||||
e2eutil.AssertUnstructuredExists(ctx, c, pod1Obj)
|
||||
|
||||
By("Verify CRD not created")
|
||||
assertUnstructuredDoesNotExist(ctx, c, invalidCrdObj)
|
||||
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, invalidCrdObj)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,25 +16,27 @@ import (
|
|||
"sigs.k8s.io/cli-utils/pkg/inventory"
|
||||
"sigs.k8s.io/cli-utils/pkg/object"
|
||||
"sigs.k8s.io/cli-utils/pkg/testutil"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/e2eutil"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/invconfig"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
//nolint:dupl // expEvents similar to mutation tests
|
||||
func crdTest(ctx context.Context, _ client.Client, invConfig InventoryConfig, inventoryName, namespaceName string) {
|
||||
func crdTest(ctx context.Context, _ client.Client, invConfig invconfig.InventoryConfig, inventoryName, namespaceName string) {
|
||||
By("apply a set of resources that includes both a crd and a cr")
|
||||
applier := invConfig.ApplierFactoryFunc()
|
||||
|
||||
inv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(inventoryName, namespaceName, "test"))
|
||||
|
||||
crdObj := manifestToUnstructured(crd)
|
||||
crObj := manifestToUnstructured(cr)
|
||||
crdObj := e2eutil.ManifestToUnstructured(crd)
|
||||
crObj := e2eutil.ManifestToUnstructured(cr)
|
||||
|
||||
resources := []*unstructured.Unstructured{
|
||||
crObj,
|
||||
crdObj,
|
||||
}
|
||||
|
||||
applierEvents := runCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
||||
applierEvents := e2eutil.RunCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
||||
ReconcileTimeout: 2 * time.Minute,
|
||||
EmitStatusEvents: false,
|
||||
}))
|
||||
|
|
@ -215,7 +217,7 @@ func crdTest(ctx context.Context, _ client.Client, invConfig InventoryConfig, in
|
|||
By("destroy the resources, including the crd")
|
||||
destroyer := invConfig.DestroyerFactoryFunc()
|
||||
options := apply.DestroyerOptions{InventoryPolicy: inventory.PolicyAdoptIfNoInventory}
|
||||
destroyerEvents := runCollect(destroyer.Run(ctx, inv, options))
|
||||
destroyerEvents := e2eutil.RunCollect(destroyer.Run(ctx, inv, options))
|
||||
|
||||
expEvents = []testutil.ExpEvent{
|
||||
{
|
||||
|
|
|
|||
|
|
@ -36,12 +36,6 @@ spec:
|
|||
openAPIV3Schema:
|
||||
description: Example for cli-utils e2e tests
|
||||
properties:
|
||||
apiVersion:
|
||||
type: string
|
||||
kind:
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
properties:
|
||||
objects:
|
||||
|
|
|
|||
|
|
@ -14,36 +14,38 @@ import (
|
|||
"sigs.k8s.io/cli-utils/pkg/apply"
|
||||
"sigs.k8s.io/cli-utils/pkg/common"
|
||||
"sigs.k8s.io/cli-utils/pkg/inventory"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/e2eutil"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/invconfig"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
func deletionPreventionTest(ctx context.Context, c client.Client, invConfig InventoryConfig, inventoryName, namespaceName string) {
|
||||
func deletionPreventionTest(ctx context.Context, c client.Client, invConfig invconfig.InventoryConfig, inventoryName, namespaceName string) {
|
||||
By("Apply resources")
|
||||
applier := invConfig.ApplierFactoryFunc()
|
||||
inventoryID := fmt.Sprintf("%s-%s", inventoryName, namespaceName)
|
||||
|
||||
inventoryInfo := createInventoryInfo(invConfig, inventoryName, namespaceName, inventoryID)
|
||||
inventoryInfo := invconfig.CreateInventoryInfo(invConfig, inventoryName, namespaceName, inventoryID)
|
||||
|
||||
resources := []*unstructured.Unstructured{
|
||||
withNamespace(manifestToUnstructured(deployment1), namespaceName),
|
||||
withAnnotation(withNamespace(manifestToUnstructured(pod1), namespaceName), common.OnRemoveAnnotation, common.OnRemoveKeep),
|
||||
withAnnotation(withNamespace(manifestToUnstructured(pod2), namespaceName), common.LifecycleDeleteAnnotation, common.PreventDeletion),
|
||||
e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(deployment1), namespaceName),
|
||||
e2eutil.WithAnnotation(e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod1), namespaceName), common.OnRemoveAnnotation, common.OnRemoveKeep),
|
||||
e2eutil.WithAnnotation(e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod2), namespaceName), common.LifecycleDeleteAnnotation, common.PreventDeletion),
|
||||
}
|
||||
|
||||
runCollect(applier.Run(ctx, inventoryInfo, resources, apply.ApplierOptions{
|
||||
e2eutil.RunCollect(applier.Run(ctx, inventoryInfo, resources, apply.ApplierOptions{
|
||||
ReconcileTimeout: 2 * time.Minute,
|
||||
}))
|
||||
|
||||
By("Verify deployment created")
|
||||
obj := assertUnstructuredExists(ctx, c, withNamespace(manifestToUnstructured(deployment1), namespaceName))
|
||||
obj := e2eutil.AssertUnstructuredExists(ctx, c, e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(deployment1), namespaceName))
|
||||
Expect(obj.GetAnnotations()[inventory.OwningInventoryKey]).To(Equal(inventoryInfo.ID()))
|
||||
|
||||
By("Verify pod1 created")
|
||||
obj = assertUnstructuredExists(ctx, c, withNamespace(manifestToUnstructured(pod1), namespaceName))
|
||||
obj = e2eutil.AssertUnstructuredExists(ctx, c, e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod1), namespaceName))
|
||||
Expect(obj.GetAnnotations()[inventory.OwningInventoryKey]).To(Equal(inventoryInfo.ID()))
|
||||
|
||||
By("Verify pod2 created")
|
||||
obj = assertUnstructuredExists(ctx, c, withNamespace(manifestToUnstructured(pod2), namespaceName))
|
||||
obj = e2eutil.AssertUnstructuredExists(ctx, c, e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod2), namespaceName))
|
||||
Expect(obj.GetAnnotations()[inventory.OwningInventoryKey]).To(Equal(inventoryInfo.ID()))
|
||||
|
||||
By("Verify the inventory size is 3")
|
||||
|
|
@ -51,24 +53,24 @@ func deletionPreventionTest(ctx context.Context, c client.Client, invConfig Inve
|
|||
|
||||
By("Dry-run apply resources")
|
||||
resources = []*unstructured.Unstructured{
|
||||
withNamespace(manifestToUnstructured(deployment1), namespaceName),
|
||||
e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(deployment1), namespaceName),
|
||||
}
|
||||
|
||||
runCollect(applier.Run(ctx, inventoryInfo, resources, apply.ApplierOptions{
|
||||
e2eutil.RunCollect(applier.Run(ctx, inventoryInfo, resources, apply.ApplierOptions{
|
||||
ReconcileTimeout: 2 * time.Minute,
|
||||
DryRunStrategy: common.DryRunClient,
|
||||
}))
|
||||
|
||||
By("Verify deployment still exists and has the config.k8s.io/owning-inventory annotation")
|
||||
obj = assertUnstructuredExists(ctx, c, withNamespace(manifestToUnstructured(deployment1), namespaceName))
|
||||
obj = e2eutil.AssertUnstructuredExists(ctx, c, e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(deployment1), namespaceName))
|
||||
Expect(obj.GetAnnotations()[inventory.OwningInventoryKey]).To(Equal(inventoryInfo.ID()))
|
||||
|
||||
By("Verify pod1 still exits and does not have the config.k8s.io/owning-inventory annotation")
|
||||
obj = assertUnstructuredExists(ctx, c, withNamespace(manifestToUnstructured(pod1), namespaceName))
|
||||
obj = e2eutil.AssertUnstructuredExists(ctx, c, e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod1), namespaceName))
|
||||
Expect(obj.GetAnnotations()[inventory.OwningInventoryKey]).To(Equal(inventoryInfo.ID()))
|
||||
|
||||
By("Verify pod2 still exits and does not have the config.k8s.io/owning-inventory annotation")
|
||||
obj = assertUnstructuredExists(ctx, c, withNamespace(manifestToUnstructured(pod2), namespaceName))
|
||||
obj = e2eutil.AssertUnstructuredExists(ctx, c, e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod2), namespaceName))
|
||||
Expect(obj.GetAnnotations()[inventory.OwningInventoryKey]).To(Equal(inventoryInfo.ID()))
|
||||
|
||||
By("Verify the inventory size is still 3")
|
||||
|
|
@ -76,23 +78,23 @@ func deletionPreventionTest(ctx context.Context, c client.Client, invConfig Inve
|
|||
|
||||
By("Apply resources")
|
||||
resources = []*unstructured.Unstructured{
|
||||
withNamespace(manifestToUnstructured(deployment1), namespaceName),
|
||||
e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(deployment1), namespaceName),
|
||||
}
|
||||
|
||||
runCollect(applier.Run(ctx, inventoryInfo, resources, apply.ApplierOptions{
|
||||
e2eutil.RunCollect(applier.Run(ctx, inventoryInfo, resources, apply.ApplierOptions{
|
||||
ReconcileTimeout: 2 * time.Minute,
|
||||
}))
|
||||
|
||||
By("Verify deployment still exists and has the config.k8s.io/owning-inventory annotation")
|
||||
obj = assertUnstructuredExists(ctx, c, withNamespace(manifestToUnstructured(deployment1), namespaceName))
|
||||
obj = e2eutil.AssertUnstructuredExists(ctx, c, e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(deployment1), namespaceName))
|
||||
Expect(obj.GetAnnotations()[inventory.OwningInventoryKey]).To(Equal(inventoryInfo.ID()))
|
||||
|
||||
By("Verify pod1 still exits and does not have the config.k8s.io/owning-inventory annotation")
|
||||
obj = assertUnstructuredExists(ctx, c, withNamespace(manifestToUnstructured(pod1), namespaceName))
|
||||
obj = e2eutil.AssertUnstructuredExists(ctx, c, e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod1), namespaceName))
|
||||
Expect(obj.GetAnnotations()[inventory.OwningInventoryKey]).To(Equal(""))
|
||||
|
||||
By("Verify pod2 still exits and does not have the config.k8s.io/owning-inventory annotation")
|
||||
obj = assertUnstructuredExists(ctx, c, withNamespace(manifestToUnstructured(pod2), namespaceName))
|
||||
obj = e2eutil.AssertUnstructuredExists(ctx, c, e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod2), namespaceName))
|
||||
Expect(obj.GetAnnotations()[inventory.OwningInventoryKey]).To(Equal(""))
|
||||
|
||||
By("Verify the inventory size is 1")
|
||||
|
|
|
|||
|
|
@ -15,18 +15,20 @@ import (
|
|||
"sigs.k8s.io/cli-utils/pkg/object"
|
||||
"sigs.k8s.io/cli-utils/pkg/object/validation"
|
||||
"sigs.k8s.io/cli-utils/pkg/testutil"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/e2eutil"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/invconfig"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
//nolint:dupl // expEvents similar to other tests
|
||||
func dependencyFilterTest(ctx context.Context, c client.Client, invConfig InventoryConfig, inventoryName, namespaceName string) {
|
||||
func dependencyFilterTest(ctx context.Context, c client.Client, invConfig invconfig.InventoryConfig, inventoryName, namespaceName string) {
|
||||
By("apply resources in order based on depends-on annotation")
|
||||
applier := invConfig.ApplierFactoryFunc()
|
||||
|
||||
inv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(inventoryName, namespaceName, "test"))
|
||||
|
||||
pod1Obj := withDependsOn(withNamespace(manifestToUnstructured(pod1), namespaceName), fmt.Sprintf("/namespaces/%s/Pod/pod2", namespaceName))
|
||||
pod2Obj := withNamespace(manifestToUnstructured(pod2), namespaceName)
|
||||
pod1Obj := e2eutil.WithDependsOn(e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod1), namespaceName), fmt.Sprintf("/namespaces/%s/Pod/pod2", namespaceName))
|
||||
pod2Obj := e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod2), namespaceName)
|
||||
|
||||
// Dependency order: pod1 -> pod2
|
||||
// Apply order: pod2, pod1
|
||||
|
|
@ -37,11 +39,11 @@ func dependencyFilterTest(ctx context.Context, c client.Client, invConfig Invent
|
|||
|
||||
// Cleanup
|
||||
defer func(ctx context.Context, c client.Client) {
|
||||
deleteUnstructuredIfExists(ctx, c, pod1Obj)
|
||||
deleteUnstructuredIfExists(ctx, c, pod2Obj)
|
||||
e2eutil.DeleteUnstructuredIfExists(ctx, c, pod1Obj)
|
||||
e2eutil.DeleteUnstructuredIfExists(ctx, c, pod2Obj)
|
||||
}(ctx, c)
|
||||
|
||||
applierEvents := runCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
||||
applierEvents := e2eutil.RunCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
||||
EmitStatusEvents: false,
|
||||
}))
|
||||
|
||||
|
|
@ -219,14 +221,14 @@ func dependencyFilterTest(ctx context.Context, c client.Client, invConfig Invent
|
|||
Expect(testutil.EventsToExpEvents(applierEvents)).To(testutil.Equal(expEvents))
|
||||
|
||||
By("verify pod1 created and ready")
|
||||
result := assertUnstructuredExists(ctx, c, pod1Obj)
|
||||
result := e2eutil.AssertUnstructuredExists(ctx, c, pod1Obj)
|
||||
podIP, found, err := object.NestedField(result.Object, "status", "podIP")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(found).To(BeTrue())
|
||||
Expect(podIP).NotTo(BeEmpty()) // use podIP as proxy for readiness
|
||||
|
||||
By("verify pod2 created and ready")
|
||||
result = assertUnstructuredExists(ctx, c, pod2Obj)
|
||||
result = e2eutil.AssertUnstructuredExists(ctx, c, pod2Obj)
|
||||
podIP, found, err = object.NestedField(result.Object, "status", "podIP")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(found).To(BeTrue())
|
||||
|
|
@ -237,7 +239,7 @@ func dependencyFilterTest(ctx context.Context, c client.Client, invConfig Invent
|
|||
pod1Obj,
|
||||
}
|
||||
|
||||
applierEvents = runCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
||||
applierEvents = e2eutil.RunCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
||||
EmitStatusEvents: false,
|
||||
ValidationPolicy: validation.SkipInvalid,
|
||||
}))
|
||||
|
|
@ -398,13 +400,13 @@ func dependencyFilterTest(ctx context.Context, c client.Client, invConfig Invent
|
|||
Expect(testutil.EventsToExpEvents(applierEvents)).To(testutil.Equal(expEvents))
|
||||
|
||||
By("verify pod1 not deleted")
|
||||
result = assertUnstructuredExists(ctx, c, pod1Obj)
|
||||
result = e2eutil.AssertUnstructuredExists(ctx, c, pod1Obj)
|
||||
ts, found, err := object.NestedField(result.Object, "metadata", "deletionTimestamp")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(found).To(BeFalse(), "deletionTimestamp found: ", ts)
|
||||
|
||||
By("verify pod2 not deleted")
|
||||
result = assertUnstructuredExists(ctx, c, pod2Obj)
|
||||
result = e2eutil.AssertUnstructuredExists(ctx, c, pod2Obj)
|
||||
ts, found, err = object.NestedField(result.Object, "metadata", "deletionTimestamp")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(found).To(BeFalse(), "deletionTimestamp found: ", ts)
|
||||
|
|
|
|||
|
|
@ -15,18 +15,20 @@ import (
|
|||
"sigs.k8s.io/cli-utils/pkg/inventory"
|
||||
"sigs.k8s.io/cli-utils/pkg/object"
|
||||
"sigs.k8s.io/cli-utils/pkg/testutil"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/e2eutil"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/invconfig"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
func dependsOnTest(ctx context.Context, c client.Client, invConfig InventoryConfig, inventoryName, namespaceName string) {
|
||||
func dependsOnTest(ctx context.Context, c client.Client, invConfig invconfig.InventoryConfig, inventoryName, namespaceName string) {
|
||||
By("apply resources in order based on depends-on annotation")
|
||||
applier := invConfig.ApplierFactoryFunc()
|
||||
|
||||
inv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(inventoryName, namespaceName, "test"))
|
||||
|
||||
pod1Obj := withDependsOn(withNamespace(manifestToUnstructured(pod1), namespaceName), fmt.Sprintf("/namespaces/%s/Pod/pod3", namespaceName))
|
||||
pod2Obj := withNamespace(manifestToUnstructured(pod2), namespaceName)
|
||||
pod3Obj := withDependsOn(withNamespace(manifestToUnstructured(pod3), namespaceName), fmt.Sprintf("/namespaces/%s/Pod/pod2", namespaceName))
|
||||
pod1Obj := e2eutil.WithDependsOn(e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod1), namespaceName), fmt.Sprintf("/namespaces/%s/Pod/pod3", namespaceName))
|
||||
pod2Obj := e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod2), namespaceName)
|
||||
pod3Obj := e2eutil.WithDependsOn(e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod3), namespaceName), fmt.Sprintf("/namespaces/%s/Pod/pod2", namespaceName))
|
||||
|
||||
// Dependency order: pod1 -> pod3 -> pod2
|
||||
// Apply order: pod2, pod3, pod1
|
||||
|
|
@ -36,7 +38,7 @@ func dependsOnTest(ctx context.Context, c client.Client, invConfig InventoryConf
|
|||
pod3Obj,
|
||||
}
|
||||
|
||||
applierEvents := runCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
||||
applierEvents := e2eutil.RunCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
||||
EmitStatusEvents: false,
|
||||
}))
|
||||
|
||||
|
|
@ -278,21 +280,21 @@ func dependsOnTest(ctx context.Context, c client.Client, invConfig InventoryConf
|
|||
Expect(testutil.EventsToExpEvents(applierEvents)).To(testutil.Equal(expEvents))
|
||||
|
||||
By("verify pod1 created and ready")
|
||||
result := assertUnstructuredExists(ctx, c, pod1Obj)
|
||||
result := e2eutil.AssertUnstructuredExists(ctx, c, pod1Obj)
|
||||
podIP, found, err := object.NestedField(result.Object, "status", "podIP")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(found).To(BeTrue())
|
||||
Expect(podIP).NotTo(BeEmpty()) // use podIP as proxy for readiness
|
||||
|
||||
By("verify pod2 created and ready")
|
||||
result = assertUnstructuredExists(ctx, c, pod2Obj)
|
||||
result = e2eutil.AssertUnstructuredExists(ctx, c, pod2Obj)
|
||||
podIP, found, err = object.NestedField(result.Object, "status", "podIP")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(found).To(BeTrue())
|
||||
Expect(podIP).NotTo(BeEmpty()) // use podIP as proxy for readiness
|
||||
|
||||
By("verify pod3 created and ready")
|
||||
result = assertUnstructuredExists(ctx, c, pod3Obj)
|
||||
result = e2eutil.AssertUnstructuredExists(ctx, c, pod3Obj)
|
||||
podIP, found, err = object.NestedField(result.Object, "status", "podIP")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(found).To(BeTrue())
|
||||
|
|
@ -301,7 +303,7 @@ func dependsOnTest(ctx context.Context, c client.Client, invConfig InventoryConf
|
|||
By("destroy resources in opposite order")
|
||||
destroyer := invConfig.DestroyerFactoryFunc()
|
||||
options := apply.DestroyerOptions{InventoryPolicy: inventory.PolicyAdoptIfNoInventory}
|
||||
destroyerEvents := runCollect(destroyer.Run(ctx, inv, options))
|
||||
destroyerEvents := e2eutil.RunCollect(destroyer.Run(ctx, inv, options))
|
||||
|
||||
expEvents = []testutil.ExpEvent{
|
||||
{
|
||||
|
|
@ -523,11 +525,11 @@ func dependsOnTest(ctx context.Context, c client.Client, invConfig InventoryConf
|
|||
Expect(testutil.EventsToExpEvents(destroyerEvents)).To(testutil.Equal(expEvents))
|
||||
|
||||
By("verify pod1 deleted")
|
||||
assertUnstructuredDoesNotExist(ctx, c, pod1Obj)
|
||||
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, pod1Obj)
|
||||
|
||||
By("verify pod2 deleted")
|
||||
assertUnstructuredDoesNotExist(ctx, c, pod2Obj)
|
||||
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, pod2Obj)
|
||||
|
||||
By("verify pod3 deleted")
|
||||
assertUnstructuredDoesNotExist(ctx, c, pod3Obj)
|
||||
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, pod3Obj)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,21 +18,23 @@ import (
|
|||
"sigs.k8s.io/cli-utils/pkg/kstatus/status"
|
||||
"sigs.k8s.io/cli-utils/pkg/object"
|
||||
"sigs.k8s.io/cli-utils/pkg/testutil"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/e2eutil"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/invconfig"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
func dryRunTest(ctx context.Context, c client.Client, invConfig InventoryConfig, inventoryName, namespaceName string) {
|
||||
func dryRunTest(ctx context.Context, c client.Client, invConfig invconfig.InventoryConfig, inventoryName, namespaceName string) {
|
||||
By("Apply with DryRun")
|
||||
applier := invConfig.ApplierFactoryFunc()
|
||||
inventoryID := fmt.Sprintf("%s-%s", inventoryName, namespaceName)
|
||||
|
||||
inventoryInfo := createInventoryInfo(invConfig, inventoryName, namespaceName, inventoryID)
|
||||
inventoryInfo := invconfig.CreateInventoryInfo(invConfig, inventoryName, namespaceName, inventoryID)
|
||||
|
||||
namespace1Name := fmt.Sprintf("%s-ns1", namespaceName)
|
||||
|
||||
fields := struct{ Namespace string }{Namespace: namespace1Name}
|
||||
namespace1Obj := templateToUnstructured(namespaceTemplate, fields)
|
||||
podBObj := templateToUnstructured(podBTemplate, fields)
|
||||
namespace1Obj := e2eutil.TemplateToUnstructured(namespaceTemplate, fields)
|
||||
podBObj := e2eutil.TemplateToUnstructured(podBTemplate, fields)
|
||||
|
||||
// Dependency order: podB -> namespace1
|
||||
// Apply order: namespace1, podB
|
||||
|
|
@ -41,7 +43,7 @@ func dryRunTest(ctx context.Context, c client.Client, invConfig InventoryConfig,
|
|||
podBObj,
|
||||
}
|
||||
|
||||
applierEvents := runCollect(applier.Run(ctx, inventoryInfo, resources, apply.ApplierOptions{
|
||||
applierEvents := e2eutil.RunCollect(applier.Run(ctx, inventoryInfo, resources, apply.ApplierOptions{
|
||||
ReconcileTimeout: 2 * time.Minute,
|
||||
EmitStatusEvents: true,
|
||||
DryRunStrategy: common.DryRunClient,
|
||||
|
|
@ -176,18 +178,18 @@ func dryRunTest(ctx context.Context, c client.Client, invConfig InventoryConfig,
|
|||
Expect(received).To(testutil.Equal(expEvents))
|
||||
|
||||
By("Verify pod NotFound")
|
||||
assertUnstructuredDoesNotExist(ctx, c, podBObj)
|
||||
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, podBObj)
|
||||
|
||||
By("Verify inventory NotFound")
|
||||
invConfig.InvNotExistsFunc(ctx, c, inventoryName, namespaceName, inventoryID)
|
||||
|
||||
By("Apply")
|
||||
runWithNoErr(applier.Run(ctx, inventoryInfo, resources, apply.ApplierOptions{
|
||||
e2eutil.RunWithNoErr(applier.Run(ctx, inventoryInfo, resources, apply.ApplierOptions{
|
||||
ReconcileTimeout: 2 * time.Minute,
|
||||
}))
|
||||
|
||||
By("Verify pod created")
|
||||
assertUnstructuredExists(ctx, c, podBObj)
|
||||
e2eutil.AssertUnstructuredExists(ctx, c, podBObj)
|
||||
|
||||
By("Verify inventory size")
|
||||
invConfig.InvSizeVerifyFunc(ctx, c, inventoryName, namespaceName, inventoryID, 2, 2)
|
||||
|
|
@ -195,7 +197,7 @@ func dryRunTest(ctx context.Context, c client.Client, invConfig InventoryConfig,
|
|||
By("Destroy with DryRun")
|
||||
destroyer := invConfig.DestroyerFactoryFunc()
|
||||
|
||||
destroyerEvents := runCollect(destroyer.Run(ctx, inventoryInfo, apply.DestroyerOptions{
|
||||
destroyerEvents := e2eutil.RunCollect(destroyer.Run(ctx, inventoryInfo, apply.DestroyerOptions{
|
||||
InventoryPolicy: inventory.PolicyAdoptIfNoInventory,
|
||||
EmitStatusEvents: true,
|
||||
DryRunStrategy: common.DryRunClient,
|
||||
|
|
@ -286,15 +288,15 @@ func dryRunTest(ctx context.Context, c client.Client, invConfig InventoryConfig,
|
|||
Expect(testutil.EventsToExpEvents(destroyerEvents)).To(testutil.Equal(expEvents))
|
||||
|
||||
By("Verify pod still exists")
|
||||
assertUnstructuredExists(ctx, c, podBObj)
|
||||
e2eutil.AssertUnstructuredExists(ctx, c, podBObj)
|
||||
|
||||
By("Destroy")
|
||||
runWithNoErr(destroyer.Run(ctx, inventoryInfo, apply.DestroyerOptions{
|
||||
e2eutil.RunWithNoErr(destroyer.Run(ctx, inventoryInfo, apply.DestroyerOptions{
|
||||
InventoryPolicy: inventory.PolicyAdoptIfNoInventory,
|
||||
}))
|
||||
|
||||
By("Verify pod deleted")
|
||||
assertUnstructuredDoesNotExist(ctx, c, podBObj)
|
||||
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, podBObj)
|
||||
|
||||
By("Verify inventory deleted")
|
||||
invConfig.InvNotExistsFunc(ctx, c, inventoryName, namespaceName, inventoryID)
|
||||
|
|
|
|||
|
|
@ -12,69 +12,25 @@ import (
|
|||
. "github.com/onsi/gomega"
|
||||
"github.com/onsi/gomega/format"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
"k8s.io/klog/v2"
|
||||
"k8s.io/kubectl/pkg/cmd/util"
|
||||
"k8s.io/kubectl/pkg/scheme"
|
||||
"sigs.k8s.io/cli-utils/pkg/apply"
|
||||
"sigs.k8s.io/cli-utils/pkg/common"
|
||||
"sigs.k8s.io/cli-utils/pkg/inventory"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/customprovider"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/e2eutil"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/invconfig"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
|
||||
)
|
||||
|
||||
type inventoryFactoryFunc func(name, namespace, id string) *unstructured.Unstructured
|
||||
type invWrapperFunc func(*unstructured.Unstructured) inventory.Info
|
||||
type applierFactoryFunc func() *apply.Applier
|
||||
type destroyerFactoryFunc func() *apply.Destroyer
|
||||
type invSizeVerifyFunc func(ctx context.Context, c client.Client, name, namespace, id string, specCount, statusCount int)
|
||||
type invCountVerifyFunc func(ctx context.Context, c client.Client, namespace string, count int)
|
||||
type invNotExistsFunc func(ctx context.Context, c client.Client, name, namespace, id string)
|
||||
|
||||
type InventoryConfig struct {
|
||||
Strategy inventory.Strategy
|
||||
FactoryFunc inventoryFactoryFunc
|
||||
InvWrapperFunc invWrapperFunc
|
||||
ApplierFactoryFunc applierFactoryFunc
|
||||
DestroyerFactoryFunc destroyerFactoryFunc
|
||||
InvSizeVerifyFunc invSizeVerifyFunc
|
||||
InvCountVerifyFunc invCountVerifyFunc
|
||||
InvNotExistsFunc invNotExistsFunc
|
||||
}
|
||||
|
||||
const (
|
||||
ConfigMapTypeInvConfig = "ConfigMap"
|
||||
CustomTypeInvConfig = "Custom"
|
||||
)
|
||||
|
||||
var inventoryConfigs = map[string]InventoryConfig{
|
||||
ConfigMapTypeInvConfig: {
|
||||
Strategy: inventory.LabelStrategy,
|
||||
FactoryFunc: cmInventoryManifest,
|
||||
InvWrapperFunc: inventory.WrapInventoryInfoObj,
|
||||
ApplierFactoryFunc: newDefaultInvApplier,
|
||||
DestroyerFactoryFunc: newDefaultInvDestroyer,
|
||||
InvSizeVerifyFunc: defaultInvSizeVerifyFunc,
|
||||
InvCountVerifyFunc: defaultInvCountVerifyFunc,
|
||||
InvNotExistsFunc: defaultInvNotExistsFunc,
|
||||
},
|
||||
CustomTypeInvConfig: {
|
||||
Strategy: inventory.NameStrategy,
|
||||
FactoryFunc: customInventoryManifest,
|
||||
InvWrapperFunc: customprovider.WrapInventoryInfoObj,
|
||||
ApplierFactoryFunc: newCustomInvApplier,
|
||||
DestroyerFactoryFunc: newCustomInvDestroyer,
|
||||
InvSizeVerifyFunc: customInvSizeVerifyFunc,
|
||||
InvCountVerifyFunc: customInvCountVerifyFunc,
|
||||
InvNotExistsFunc: customInvNotExistsFunc,
|
||||
},
|
||||
var inventoryConfigs = map[string]invconfig.InventoryConfig{}
|
||||
var inventoryConfigTypes = []string{
|
||||
ConfigMapTypeInvConfig,
|
||||
CustomTypeInvConfig,
|
||||
}
|
||||
|
||||
// Parse optional logging flags
|
||||
|
|
@ -101,6 +57,14 @@ var _ = Describe("Applier", func() {
|
|||
cfg, err := ctrl.GetConfig()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
// increase QPS from 5 to 20
|
||||
cfg.QPS = 20
|
||||
// increase Burst QPS from 10 to 40
|
||||
cfg.Burst = 40
|
||||
|
||||
inventoryConfigs[ConfigMapTypeInvConfig] = invconfig.NewConfigMapTypeInvConfig(cfg)
|
||||
inventoryConfigs[CustomTypeInvConfig] = invconfig.NewCustomTypeInvConfig(cfg)
|
||||
|
||||
mapper, err := apiutil.NewDynamicRESTMapper(cfg)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
|
|
@ -112,20 +76,26 @@ var _ = Describe("Applier", func() {
|
|||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultBeforeTestTimeout)
|
||||
defer cancel()
|
||||
createInventoryCRD(ctx, c)
|
||||
e2eutil.CreateInventoryCRD(ctx, c)
|
||||
Expect(ctx.Err()).To(BeNil(), "BeforeSuite context cancelled or timed out")
|
||||
})
|
||||
|
||||
AfterSuite(func() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultAfterTestTimeout)
|
||||
defer cancel()
|
||||
deleteInventoryCRD(ctx, c)
|
||||
e2eutil.DeleteInventoryCRD(ctx, c)
|
||||
Expect(ctx.Err()).To(BeNil(), "AfterSuite context cancelled or timed out")
|
||||
})
|
||||
|
||||
for name := range inventoryConfigs {
|
||||
invConfig := inventoryConfigs[name]
|
||||
Context(fmt.Sprintf("Inventory: %s", name), func() {
|
||||
for i := range inventoryConfigTypes {
|
||||
invType := inventoryConfigTypes[i]
|
||||
Context(fmt.Sprintf("Inventory: %s", invType), func() {
|
||||
var invConfig invconfig.InventoryConfig
|
||||
|
||||
BeforeEach(func() {
|
||||
invConfig = inventoryConfigs[invType]
|
||||
})
|
||||
|
||||
Context("Apply and destroy", func() {
|
||||
var namespace *v1.Namespace
|
||||
var inventoryName string
|
||||
|
|
@ -134,8 +104,8 @@ var _ = Describe("Applier", func() {
|
|||
|
||||
BeforeEach(func() {
|
||||
ctx, cancel = context.WithTimeout(context.Background(), defaultTestTimeout)
|
||||
inventoryName = randomString("test-inv-")
|
||||
namespace = createRandomNamespace(ctx, c)
|
||||
inventoryName = e2eutil.RandomString("test-inv-")
|
||||
namespace = e2eutil.CreateRandomNamespace(ctx, c)
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
|
|
@ -147,20 +117,20 @@ var _ = Describe("Applier", func() {
|
|||
// clean up resources created by the tests
|
||||
fields := struct{ Namespace string }{Namespace: namespace.GetName()}
|
||||
objs := []*unstructured.Unstructured{
|
||||
manifestToUnstructured(cr),
|
||||
manifestToUnstructured(crd),
|
||||
withNamespace(manifestToUnstructured(pod1), namespace.GetName()),
|
||||
withNamespace(manifestToUnstructured(pod2), namespace.GetName()),
|
||||
withNamespace(manifestToUnstructured(pod3), namespace.GetName()),
|
||||
templateToUnstructured(podATemplate, fields),
|
||||
templateToUnstructured(podBTemplate, fields),
|
||||
withNamespace(manifestToUnstructured(deployment1), namespace.GetName()),
|
||||
manifestToUnstructured(apiservice1),
|
||||
e2eutil.ManifestToUnstructured(cr),
|
||||
e2eutil.ManifestToUnstructured(crd),
|
||||
e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod1), namespace.GetName()),
|
||||
e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod2), namespace.GetName()),
|
||||
e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod3), namespace.GetName()),
|
||||
e2eutil.TemplateToUnstructured(podATemplate, fields),
|
||||
e2eutil.TemplateToUnstructured(podBTemplate, fields),
|
||||
e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(deployment1), namespace.GetName()),
|
||||
e2eutil.ManifestToUnstructured(apiservice1),
|
||||
}
|
||||
for _, obj := range objs {
|
||||
deleteUnstructuredIfExists(ctx, c, obj)
|
||||
e2eutil.DeleteUnstructuredIfExists(ctx, c, obj)
|
||||
}
|
||||
deleteNamespace(ctx, c, namespace)
|
||||
e2eutil.DeleteNamespace(ctx, c, namespace)
|
||||
})
|
||||
|
||||
It("Apply and destroy", func() {
|
||||
|
|
@ -235,7 +205,7 @@ var _ = Describe("Applier", func() {
|
|||
|
||||
BeforeEach(func() {
|
||||
ctx, cancel = context.WithTimeout(context.Background(), defaultTestTimeout)
|
||||
namespace = createRandomNamespace(ctx, c)
|
||||
namespace = e2eutil.CreateRandomNamespace(ctx, c)
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
|
|
@ -244,8 +214,8 @@ var _ = Describe("Applier", func() {
|
|||
// new timeout for cleanup
|
||||
ctx, cancel = context.WithTimeout(context.Background(), defaultAfterTestTimeout)
|
||||
defer cancel()
|
||||
deleteUnstructuredIfExists(ctx, c, withNamespace(manifestToUnstructured(deployment1), namespace.GetName()))
|
||||
deleteNamespace(ctx, c, namespace)
|
||||
e2eutil.DeleteUnstructuredIfExists(ctx, c, e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(deployment1), namespace.GetName()))
|
||||
e2eutil.DeleteNamespace(ctx, c, namespace)
|
||||
})
|
||||
|
||||
It("MustMatch policy", func() {
|
||||
|
|
@ -271,8 +241,8 @@ var _ = Describe("Applier", func() {
|
|||
|
||||
BeforeEach(func() {
|
||||
ctx, cancel = context.WithTimeout(context.Background(), defaultTestTimeout)
|
||||
inventoryName = randomString("test-inv-")
|
||||
namespace = createRandomNamespace(ctx, c)
|
||||
inventoryName = e2eutil.RandomString("test-inv-")
|
||||
namespace = e2eutil.CreateRandomNamespace(ctx, c)
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
|
|
@ -281,8 +251,8 @@ var _ = Describe("Applier", func() {
|
|||
// new timeout for cleanup
|
||||
ctx, cancel = context.WithTimeout(context.Background(), defaultAfterTestTimeout)
|
||||
defer cancel()
|
||||
deleteUnstructuredIfExists(ctx, c, withNamespace(manifestToUnstructured(deployment1), namespace.GetName()))
|
||||
deleteNamespace(ctx, c, namespace)
|
||||
e2eutil.DeleteUnstructuredIfExists(ctx, c, e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(deployment1), namespace.GetName()))
|
||||
e2eutil.DeleteNamespace(ctx, c, namespace)
|
||||
})
|
||||
|
||||
It("Apply with existing inventory", func() {
|
||||
|
|
@ -290,175 +260,3 @@ var _ = Describe("Applier", func() {
|
|||
})
|
||||
})
|
||||
})
|
||||
|
||||
func createInventoryCRD(ctx context.Context, c client.Client) {
|
||||
invCRD := manifestToUnstructured(customprovider.InventoryCRD)
|
||||
var u unstructured.Unstructured
|
||||
u.SetGroupVersionKind(invCRD.GroupVersionKind())
|
||||
err := c.Get(ctx, types.NamespacedName{
|
||||
Name: invCRD.GetName(),
|
||||
}, &u)
|
||||
if apierrors.IsNotFound(err) {
|
||||
err = c.Create(ctx, invCRD)
|
||||
}
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
}
|
||||
|
||||
func createRandomNamespace(ctx context.Context, c client.Client) *v1.Namespace {
|
||||
namespaceName := randomString("e2e-test-")
|
||||
namespace := &v1.Namespace{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: v1.SchemeGroupVersion.String(),
|
||||
Kind: "Namespace",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: namespaceName,
|
||||
},
|
||||
}
|
||||
|
||||
err := c.Create(ctx, namespace)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
return namespace
|
||||
}
|
||||
|
||||
func deleteInventoryCRD(ctx context.Context, c client.Client) {
|
||||
invCRD := manifestToUnstructured(customprovider.InventoryCRD)
|
||||
deleteUnstructuredIfExists(ctx, c, invCRD)
|
||||
}
|
||||
|
||||
func deleteUnstructuredIfExists(ctx context.Context, c client.Client, obj *unstructured.Unstructured) {
|
||||
err := c.Delete(ctx, obj)
|
||||
if err != nil {
|
||||
Expect(err).To(Or(
|
||||
BeAssignableToTypeOf(&meta.NoKindMatchError{}),
|
||||
BeAssignableToTypeOf(&apierrors.StatusError{}),
|
||||
))
|
||||
if se, ok := err.(*apierrors.StatusError); ok {
|
||||
Expect(se.ErrStatus.Reason).To(Equal(metav1.StatusReasonNotFound))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func deleteNamespace(ctx context.Context, c client.Client, namespace *v1.Namespace) {
|
||||
err := c.Delete(ctx, namespace)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
func newDefaultInvApplier() *apply.Applier {
|
||||
return newApplierFromInvFactory(inventory.ClusterClientFactory{StatusPolicy: inventory.StatusPolicyAll})
|
||||
}
|
||||
|
||||
func newDefaultInvDestroyer() *apply.Destroyer {
|
||||
return newDestroyerFromInvFactory(inventory.ClusterClientFactory{StatusPolicy: inventory.StatusPolicyAll})
|
||||
}
|
||||
|
||||
func defaultInvNotExistsFunc(ctx context.Context, c client.Client, name, namespace, id string) {
|
||||
var cmList v1.ConfigMapList
|
||||
err := c.List(ctx, &cmList,
|
||||
client.MatchingLabels(map[string]string{common.InventoryLabel: id}),
|
||||
client.InNamespace(namespace))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(cmList.Items).To(HaveLen(0), "expected inventory list to be empty")
|
||||
}
|
||||
|
||||
func defaultInvSizeVerifyFunc(ctx context.Context, c client.Client, name, namespace, id string, specCount, _ int) {
|
||||
var cmList v1.ConfigMapList
|
||||
err := c.List(ctx, &cmList,
|
||||
client.MatchingLabels(map[string]string{common.InventoryLabel: id}),
|
||||
client.InNamespace(namespace))
|
||||
Expect(err).WithOffset(1).ToNot(HaveOccurred(), "listing ConfigMap inventory from cluster")
|
||||
|
||||
Expect(len(cmList.Items)).WithOffset(1).To(Equal(1), "number of inventory objects by label")
|
||||
|
||||
data := cmList.Items[0].Data
|
||||
Expect(len(data)).WithOffset(1).To(Equal(specCount), "inventory spec.data length")
|
||||
|
||||
// Don't validate status size.
|
||||
// ConfigMap provider uses inventory.StatusPolicyNone.
|
||||
}
|
||||
|
||||
func defaultInvCountVerifyFunc(ctx context.Context, c client.Client, namespace string, count int) {
|
||||
var cmList v1.ConfigMapList
|
||||
err := c.List(ctx, &cmList, client.InNamespace(namespace), client.HasLabels{common.InventoryLabel})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(len(cmList.Items)).To(Equal(count))
|
||||
}
|
||||
|
||||
func newCustomInvApplier() *apply.Applier {
|
||||
return newApplierFromInvFactory(customprovider.CustomClientFactory{})
|
||||
}
|
||||
|
||||
func newCustomInvDestroyer() *apply.Destroyer {
|
||||
return newDestroyerFromInvFactory(customprovider.CustomClientFactory{})
|
||||
}
|
||||
|
||||
func newFactory() util.Factory {
|
||||
kubeConfigFlags := genericclioptions.NewConfigFlags(true).WithDeprecatedPasswordFlag()
|
||||
matchVersionKubeConfigFlags := util.NewMatchVersionFlags(kubeConfigFlags)
|
||||
return util.NewFactory(matchVersionKubeConfigFlags)
|
||||
}
|
||||
|
||||
func customInvNotExistsFunc(ctx context.Context, c client.Client, name, namespace, id string) {
|
||||
var u unstructured.Unstructured
|
||||
u.SetGroupVersionKind(customprovider.InventoryGVK)
|
||||
u.SetName(name)
|
||||
u.SetNamespace(namespace)
|
||||
assertUnstructuredDoesNotExist(ctx, c, &u)
|
||||
}
|
||||
|
||||
func customInvSizeVerifyFunc(ctx context.Context, c client.Client, name, namespace, _ string, specCount, statusCount int) {
|
||||
var u unstructured.Unstructured
|
||||
u.SetGroupVersionKind(customprovider.InventoryGVK)
|
||||
err := c.Get(ctx, types.NamespacedName{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
}, &u)
|
||||
Expect(err).WithOffset(1).ToNot(HaveOccurred(), "getting custom inventory from cluster")
|
||||
|
||||
s, found, err := unstructured.NestedSlice(u.Object, "spec", "objects")
|
||||
Expect(err).WithOffset(1).ToNot(HaveOccurred(), "reading inventory spec.objects")
|
||||
if found {
|
||||
Expect(len(s)).WithOffset(1).To(Equal(specCount), "inventory status.objects length")
|
||||
} else {
|
||||
Expect(specCount).WithOffset(1).To(Equal(0), "inventory spec.objects not found")
|
||||
}
|
||||
|
||||
s, found, err = unstructured.NestedSlice(u.Object, "status", "objects")
|
||||
Expect(err).WithOffset(1).ToNot(HaveOccurred(), "reading inventory status.objects")
|
||||
if found {
|
||||
Expect(len(s)).WithOffset(1).To(Equal(statusCount), "inventory status.objects length")
|
||||
} else {
|
||||
Expect(statusCount).WithOffset(1).To(Equal(0), "inventory status.objects not found")
|
||||
}
|
||||
}
|
||||
|
||||
func customInvCountVerifyFunc(ctx context.Context, c client.Client, namespace string, count int) {
|
||||
var u unstructured.UnstructuredList
|
||||
u.SetGroupVersionKind(customprovider.InventoryGVK)
|
||||
err := c.List(ctx, &u, client.InNamespace(namespace))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(len(u.Items)).To(Equal(count))
|
||||
}
|
||||
|
||||
func newApplierFromInvFactory(invFactory inventory.ClientFactory) *apply.Applier {
|
||||
f := newFactory()
|
||||
invClient, err := invFactory.NewClient(f)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
a, err := apply.NewApplierBuilder().
|
||||
WithFactory(f).
|
||||
WithInventoryClient(invClient).
|
||||
Build()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
return a
|
||||
}
|
||||
|
||||
func newDestroyerFromInvFactory(invFactory inventory.ClientFactory) *apply.Destroyer {
|
||||
f := newFactory()
|
||||
invClient, err := invFactory.NewClient(f)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
d, err := apply.NewDestroyer(f, invClient)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
return d
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,22 @@
|
|||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package e2e
|
||||
package e2eutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/onsi/ginkgo"
|
||||
"github.com/onsi/gomega"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/yaml"
|
||||
"sigs.k8s.io/cli-utils/pkg/apply/event"
|
||||
|
|
@ -25,24 +24,25 @@ import (
|
|||
"sigs.k8s.io/cli-utils/pkg/kstatus/status"
|
||||
"sigs.k8s.io/cli-utils/pkg/object/dependson"
|
||||
"sigs.k8s.io/cli-utils/pkg/object/mutation"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/customprovider"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
func withReplicas(obj *unstructured.Unstructured, replicas int) *unstructured.Unstructured {
|
||||
func WithReplicas(obj *unstructured.Unstructured, replicas int) *unstructured.Unstructured {
|
||||
err := unstructured.SetNestedField(obj.Object, int64(replicas), "spec", "replicas")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
return obj
|
||||
}
|
||||
|
||||
func withNamespace(obj *unstructured.Unstructured, namespace string) *unstructured.Unstructured {
|
||||
func WithNamespace(obj *unstructured.Unstructured, namespace string) *unstructured.Unstructured {
|
||||
obj.SetNamespace(namespace)
|
||||
return obj
|
||||
}
|
||||
|
||||
func podWithImage(obj *unstructured.Unstructured, containerName, image string) *unstructured.Unstructured {
|
||||
func PodWithImage(obj *unstructured.Unstructured, containerName, image string) *unstructured.Unstructured {
|
||||
containers, found, err := unstructured.NestedSlice(obj.Object, "spec", "containers")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(found).To(BeTrue())
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
gomega.Expect(found).To(gomega.BeTrue())
|
||||
|
||||
containerFound := false
|
||||
for i := range containers {
|
||||
|
|
@ -54,26 +54,26 @@ func podWithImage(obj *unstructured.Unstructured, containerName, image string) *
|
|||
containerFound = true
|
||||
container["image"] = image
|
||||
}
|
||||
Expect(containerFound).To(BeTrue())
|
||||
gomega.Expect(containerFound).To(gomega.BeTrue())
|
||||
err = unstructured.SetNestedSlice(obj.Object, containers, "spec", "containers")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
return obj
|
||||
}
|
||||
|
||||
func withNodeSelector(obj *unstructured.Unstructured, key, value string) *unstructured.Unstructured {
|
||||
func WithNodeSelector(obj *unstructured.Unstructured, key, value string) *unstructured.Unstructured {
|
||||
selectors, found, err := unstructured.NestedMap(obj.Object, "spec", "nodeSelector")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
|
||||
if !found {
|
||||
selectors = make(map[string]interface{})
|
||||
}
|
||||
selectors[key] = value
|
||||
err = unstructured.SetNestedMap(obj.Object, selectors, "spec", "nodeSelector")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
return obj
|
||||
}
|
||||
|
||||
func withAnnotation(obj *unstructured.Unstructured, key, value string) *unstructured.Unstructured {
|
||||
func WithAnnotation(obj *unstructured.Unstructured, key, value string) *unstructured.Unstructured {
|
||||
annotations := obj.GetAnnotations()
|
||||
if annotations == nil {
|
||||
annotations = make(map[string]string)
|
||||
|
|
@ -83,7 +83,7 @@ func withAnnotation(obj *unstructured.Unstructured, key, value string) *unstruct
|
|||
return obj
|
||||
}
|
||||
|
||||
func withDependsOn(obj *unstructured.Unstructured, dep string) *unstructured.Unstructured {
|
||||
func WithDependsOn(obj *unstructured.Unstructured, dep string) *unstructured.Unstructured {
|
||||
a := obj.GetAnnotations()
|
||||
if a == nil {
|
||||
a = make(map[string]string, 1)
|
||||
|
|
@ -93,18 +93,18 @@ func withDependsOn(obj *unstructured.Unstructured, dep string) *unstructured.Uns
|
|||
return obj
|
||||
}
|
||||
|
||||
func deleteUnstructuredAndWait(ctx context.Context, c client.Client, obj *unstructured.Unstructured) {
|
||||
func DeleteUnstructuredAndWait(ctx context.Context, c client.Client, obj *unstructured.Unstructured) {
|
||||
ref := mutation.ResourceReferenceFromUnstructured(obj)
|
||||
|
||||
err := c.Delete(ctx, obj,
|
||||
client.PropagationPolicy(metav1.DeletePropagationForeground))
|
||||
Expect(err).NotTo(HaveOccurred(),
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred(),
|
||||
"expected DELETE to not error (%s): %s", ref, err)
|
||||
|
||||
waitForDeletion(ctx, c, obj)
|
||||
WaitForDeletion(ctx, c, obj)
|
||||
}
|
||||
|
||||
func waitForDeletion(ctx context.Context, c client.Client, obj *unstructured.Unstructured) {
|
||||
func WaitForDeletion(ctx context.Context, c client.Client, obj *unstructured.Unstructured) {
|
||||
ref := mutation.ResourceReferenceFromUnstructured(obj)
|
||||
resultObj := ref.ToUnstructured()
|
||||
|
||||
|
|
@ -118,7 +118,7 @@ func waitForDeletion(ctx context.Context, c client.Client, obj *unstructured.Uns
|
|||
for {
|
||||
select {
|
||||
case <-t.C:
|
||||
Fail("timed out waiting for resource to be fully deleted")
|
||||
ginkgo.Fail("timed out waiting for resource to be fully deleted")
|
||||
return
|
||||
case <-s.C:
|
||||
err := c.Get(ctx, types.NamespacedName{
|
||||
|
|
@ -126,7 +126,7 @@ func waitForDeletion(ctx context.Context, c client.Client, obj *unstructured.Uns
|
|||
Name: obj.GetName(),
|
||||
}, resultObj)
|
||||
if err != nil {
|
||||
Expect(apierrors.ReasonForError(err)).To(Equal(metav1.StatusReasonNotFound),
|
||||
gomega.Expect(apierrors.ReasonForError(err)).To(gomega.Equal(metav1.StatusReasonNotFound),
|
||||
"expected GET to error with NotFound (%s): %s", ref, err)
|
||||
return
|
||||
}
|
||||
|
|
@ -135,17 +135,17 @@ func waitForDeletion(ctx context.Context, c client.Client, obj *unstructured.Uns
|
|||
}
|
||||
}
|
||||
|
||||
func createUnstructuredAndWait(ctx context.Context, c client.Client, obj *unstructured.Unstructured) {
|
||||
func CreateUnstructuredAndWait(ctx context.Context, c client.Client, obj *unstructured.Unstructured) {
|
||||
ref := mutation.ResourceReferenceFromUnstructured(obj)
|
||||
|
||||
err := c.Create(ctx, obj)
|
||||
Expect(err).NotTo(HaveOccurred(),
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred(),
|
||||
"expected CREATE to not error (%s): %s", ref, err)
|
||||
|
||||
waitForCreation(ctx, c, obj)
|
||||
WaitForCreation(ctx, c, obj)
|
||||
}
|
||||
|
||||
func waitForCreation(ctx context.Context, c client.Client, obj *unstructured.Unstructured) {
|
||||
func WaitForCreation(ctx context.Context, c client.Client, obj *unstructured.Unstructured) {
|
||||
ref := mutation.ResourceReferenceFromUnstructured(obj)
|
||||
resultObj := ref.ToUnstructured()
|
||||
|
||||
|
|
@ -159,7 +159,7 @@ func waitForCreation(ctx context.Context, c client.Client, obj *unstructured.Uns
|
|||
for {
|
||||
select {
|
||||
case <-t.C:
|
||||
Fail("timed out waiting for resource to be fully created")
|
||||
ginkgo.Fail("timed out waiting for resource to be fully created")
|
||||
return
|
||||
case <-s.C:
|
||||
err := c.Get(ctx, types.NamespacedName{
|
||||
|
|
@ -169,7 +169,7 @@ func waitForCreation(ctx context.Context, c client.Client, obj *unstructured.Uns
|
|||
if err == nil {
|
||||
return
|
||||
}
|
||||
Expect(apierrors.ReasonForError(err)).To(Equal(metav1.StatusReasonNotFound),
|
||||
gomega.Expect(apierrors.ReasonForError(err)).To(gomega.Equal(metav1.StatusReasonNotFound),
|
||||
"expected GET to error with NotFound (%s): %s", ref, err)
|
||||
// if NotFound, sleep and retry
|
||||
s = time.NewTimer(retry)
|
||||
|
|
@ -177,7 +177,7 @@ func waitForCreation(ctx context.Context, c client.Client, obj *unstructured.Uns
|
|||
}
|
||||
}
|
||||
|
||||
func assertUnstructuredExists(ctx context.Context, c client.Client, obj *unstructured.Unstructured) *unstructured.Unstructured {
|
||||
func AssertUnstructuredExists(ctx context.Context, c client.Client, obj *unstructured.Unstructured) *unstructured.Unstructured {
|
||||
ref := mutation.ResourceReferenceFromUnstructured(obj)
|
||||
resultObj := ref.ToUnstructured()
|
||||
|
||||
|
|
@ -185,12 +185,12 @@ func assertUnstructuredExists(ctx context.Context, c client.Client, obj *unstruc
|
|||
Namespace: obj.GetNamespace(),
|
||||
Name: obj.GetName(),
|
||||
}, resultObj)
|
||||
Expect(err).NotTo(HaveOccurred(),
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred(),
|
||||
"expected GET not to error (%s): %s", ref, err)
|
||||
return resultObj
|
||||
}
|
||||
|
||||
func assertUnstructuredDoesNotExist(ctx context.Context, c client.Client, obj *unstructured.Unstructured) {
|
||||
func AssertUnstructuredDoesNotExist(ctx context.Context, c client.Client, obj *unstructured.Unstructured) {
|
||||
ref := mutation.ResourceReferenceFromUnstructured(obj)
|
||||
resultObj := ref.ToUnstructured()
|
||||
|
||||
|
|
@ -198,13 +198,13 @@ func assertUnstructuredDoesNotExist(ctx context.Context, c client.Client, obj *u
|
|||
Namespace: obj.GetNamespace(),
|
||||
Name: obj.GetName(),
|
||||
}, resultObj)
|
||||
Expect(err).To(HaveOccurred(),
|
||||
gomega.Expect(err).To(gomega.HaveOccurred(),
|
||||
"expected GET to error (%s)", ref)
|
||||
Expect(apierrors.ReasonForError(err)).To(Equal(metav1.StatusReasonNotFound),
|
||||
gomega.Expect(apierrors.ReasonForError(err)).To(gomega.Equal(metav1.StatusReasonNotFound),
|
||||
"expected GET to error with NotFound (%s): %s", ref, err)
|
||||
}
|
||||
|
||||
func applyUnstructured(ctx context.Context, c client.Client, obj *unstructured.Unstructured) {
|
||||
func ApplyUnstructured(ctx context.Context, c client.Client, obj *unstructured.Unstructured) {
|
||||
ref := mutation.ResourceReferenceFromUnstructured(obj)
|
||||
resultObj := ref.ToUnstructured()
|
||||
|
||||
|
|
@ -212,18 +212,18 @@ func applyUnstructured(ctx context.Context, c client.Client, obj *unstructured.U
|
|||
Namespace: obj.GetNamespace(),
|
||||
Name: obj.GetName(),
|
||||
}, resultObj)
|
||||
Expect(err).NotTo(HaveOccurred(),
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred(),
|
||||
"expected GET not to error (%s)", ref)
|
||||
|
||||
err = c.Patch(ctx, obj, client.MergeFrom(resultObj))
|
||||
Expect(err).NotTo(HaveOccurred(),
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred(),
|
||||
"expected PATCH not to error (%s): %s", ref, err)
|
||||
}
|
||||
|
||||
func assertUnstructuredAvailable(obj *unstructured.Unstructured) {
|
||||
func AssertUnstructuredAvailable(obj *unstructured.Unstructured) {
|
||||
ref := mutation.ResourceReferenceFromUnstructured(obj)
|
||||
objc, err := status.GetObjectWithConditions(obj.Object)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
available := false
|
||||
for _, c := range objc.Status.Conditions {
|
||||
// appsv1.DeploymentAvailable && corev1.ConditionTrue
|
||||
|
|
@ -232,16 +232,30 @@ func assertUnstructuredAvailable(obj *unstructured.Unstructured) {
|
|||
break
|
||||
}
|
||||
}
|
||||
Expect(available).To(BeTrue(),
|
||||
gomega.Expect(available).To(gomega.BeTrue(),
|
||||
"expected Available condition to be True (%s)", ref)
|
||||
}
|
||||
|
||||
func randomString(prefix string) string {
|
||||
func AssertUnstructuredCount(ctx context.Context, c client.Client, obj *unstructured.Unstructured, count int) {
|
||||
var u unstructured.UnstructuredList
|
||||
u.SetGroupVersionKind(obj.GetObjectKind().GroupVersionKind())
|
||||
err := c.List(ctx, &u,
|
||||
client.InNamespace(obj.GetNamespace()),
|
||||
client.MatchingLabels(obj.GetLabels()))
|
||||
if err != nil && count == 0 {
|
||||
expectNotFoundError(err)
|
||||
return
|
||||
}
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
gomega.Expect(len(u.Items)).To(gomega.Equal(count), "unexpected number of %s", obj.GetKind())
|
||||
}
|
||||
|
||||
func RandomString(prefix string) string {
|
||||
randomSuffix := common.RandomStr()
|
||||
return fmt.Sprintf("%s%s", prefix, randomSuffix)
|
||||
}
|
||||
|
||||
func run(ch <-chan event.Event) error {
|
||||
func Run(ch <-chan event.Event) error {
|
||||
var err error
|
||||
for e := range ch {
|
||||
if e.Type == event.ErrorType {
|
||||
|
|
@ -251,11 +265,11 @@ func run(ch <-chan event.Event) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func runWithNoErr(ch <-chan event.Event) {
|
||||
runCollectNoErr(ch)
|
||||
func RunWithNoErr(ch <-chan event.Event) {
|
||||
RunCollectNoErr(ch)
|
||||
}
|
||||
|
||||
func runCollect(ch <-chan event.Event) []event.Event {
|
||||
func RunCollect(ch <-chan event.Event) []event.Event {
|
||||
var events []event.Event
|
||||
for e := range ch {
|
||||
events = append(events, e)
|
||||
|
|
@ -263,53 +277,15 @@ func runCollect(ch <-chan event.Event) []event.Event {
|
|||
return events
|
||||
}
|
||||
|
||||
func runCollectNoErr(ch <-chan event.Event) []event.Event {
|
||||
events := runCollect(ch)
|
||||
func RunCollectNoErr(ch <-chan event.Event) []event.Event {
|
||||
events := RunCollect(ch)
|
||||
for _, e := range events {
|
||||
Expect(e.Type).NotTo(Equal(event.ErrorType))
|
||||
gomega.Expect(e.Type).NotTo(gomega.Equal(event.ErrorType))
|
||||
}
|
||||
return events
|
||||
}
|
||||
|
||||
func cmInventoryManifest(name, namespace, id string) *unstructured.Unstructured {
|
||||
cm := &v1.ConfigMap{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: v1.SchemeGroupVersion.String(),
|
||||
Kind: "ConfigMap",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
Labels: map[string]string{
|
||||
common.InventoryLabel: id,
|
||||
},
|
||||
},
|
||||
}
|
||||
u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(cm)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return &unstructured.Unstructured{
|
||||
Object: u,
|
||||
}
|
||||
}
|
||||
|
||||
func customInventoryManifest(name, namespace, id string) *unstructured.Unstructured {
|
||||
u := manifestToUnstructured([]byte(strings.TrimSpace(`
|
||||
apiVersion: cli-utils.example.io/v1alpha1
|
||||
kind: Inventory
|
||||
metadata:
|
||||
name: PLACEHOLDER
|
||||
`)))
|
||||
u.SetName(name)
|
||||
u.SetNamespace(namespace)
|
||||
u.SetLabels(map[string]string{
|
||||
common.InventoryLabel: id,
|
||||
})
|
||||
return u
|
||||
}
|
||||
|
||||
func manifestToUnstructured(manifest []byte) *unstructured.Unstructured {
|
||||
func ManifestToUnstructured(manifest []byte) *unstructured.Unstructured {
|
||||
u := make(map[string]interface{})
|
||||
err := yaml.Unmarshal(manifest, &u)
|
||||
if err != nil {
|
||||
|
|
@ -320,7 +296,7 @@ func manifestToUnstructured(manifest []byte) *unstructured.Unstructured {
|
|||
}
|
||||
}
|
||||
|
||||
func templateToUnstructured(tmpl string, data interface{}) *unstructured.Unstructured {
|
||||
func TemplateToUnstructured(tmpl string, data interface{}) *unstructured.Unstructured {
|
||||
t, err := template.New("manifest").Parse(tmpl)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to parse manifest go-template: %w", err))
|
||||
|
|
@ -330,5 +306,99 @@ func templateToUnstructured(tmpl string, data interface{}) *unstructured.Unstruc
|
|||
if err != nil {
|
||||
panic(fmt.Errorf("failed to execute manifest go-template: %w", err))
|
||||
}
|
||||
return manifestToUnstructured(buffer.Bytes())
|
||||
return ManifestToUnstructured(buffer.Bytes())
|
||||
}
|
||||
|
||||
func CreateInventoryCRD(ctx context.Context, c client.Client) {
|
||||
invCRD := ManifestToUnstructured(customprovider.InventoryCRD)
|
||||
var u unstructured.Unstructured
|
||||
u.SetGroupVersionKind(invCRD.GroupVersionKind())
|
||||
err := c.Get(ctx, types.NamespacedName{
|
||||
Name: invCRD.GetName(),
|
||||
}, &u)
|
||||
if apierrors.IsNotFound(err) {
|
||||
err = c.Create(ctx, invCRD)
|
||||
}
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
}
|
||||
|
||||
func CreateRandomNamespace(ctx context.Context, c client.Client) *v1.Namespace {
|
||||
namespaceName := RandomString("e2e-test-")
|
||||
namespace := &v1.Namespace{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: v1.SchemeGroupVersion.String(),
|
||||
Kind: "Namespace",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: namespaceName,
|
||||
},
|
||||
}
|
||||
|
||||
err := c.Create(ctx, namespace)
|
||||
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
||||
return namespace
|
||||
}
|
||||
|
||||
func DeleteInventoryCRD(ctx context.Context, c client.Client) {
|
||||
invCRD := ManifestToUnstructured(customprovider.InventoryCRD)
|
||||
DeleteUnstructuredIfExists(ctx, c, invCRD)
|
||||
}
|
||||
|
||||
func DeleteUnstructuredIfExists(ctx context.Context, c client.Client, obj *unstructured.Unstructured) {
|
||||
err := c.Delete(ctx, obj)
|
||||
if err != nil {
|
||||
expectNotFoundError(err)
|
||||
}
|
||||
}
|
||||
|
||||
func DeleteAllUnstructuredIfExists(ctx context.Context, c client.Client, obj *unstructured.Unstructured) {
|
||||
err := c.DeleteAllOf(ctx, obj,
|
||||
client.InNamespace(obj.GetNamespace()),
|
||||
client.MatchingLabels(obj.GetLabels()))
|
||||
if err != nil {
|
||||
expectNotFoundError(err)
|
||||
}
|
||||
}
|
||||
|
||||
func DeleteNamespace(ctx context.Context, c client.Client, namespace *v1.Namespace) {
|
||||
err := c.Delete(ctx, namespace)
|
||||
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
||||
}
|
||||
|
||||
func UnstructuredExistsAndIsNotTerminating(ctx context.Context, c client.Client, obj *unstructured.Unstructured) bool {
|
||||
serverObj := obj.DeepCopy()
|
||||
err := c.Get(ctx, types.NamespacedName{
|
||||
Namespace: obj.GetNamespace(),
|
||||
Name: obj.GetName(),
|
||||
}, serverObj)
|
||||
if err != nil {
|
||||
expectNotFoundError(err)
|
||||
return false
|
||||
}
|
||||
return !UnstructuredIsTerminating(serverObj)
|
||||
}
|
||||
|
||||
func expectNotFoundError(err error) {
|
||||
gomega.Expect(err).To(gomega.Or(
|
||||
gomega.BeAssignableToTypeOf(&meta.NoKindMatchError{}),
|
||||
gomega.BeAssignableToTypeOf(&apierrors.StatusError{}),
|
||||
))
|
||||
if se, ok := err.(*apierrors.StatusError); ok {
|
||||
gomega.Expect(se.ErrStatus.Reason).To(gomega.Or(
|
||||
gomega.Equal(metav1.StatusReasonNotFound),
|
||||
// custom resources dissalow deletion if the CRD is terminating
|
||||
gomega.Equal(metav1.StatusReasonMethodNotAllowed),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
func UnstructuredIsTerminating(obj *unstructured.Unstructured) bool {
|
||||
objc, err := status.GetObjectWithConditions(obj.Object)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
for _, c := range objc.Status.Conditions {
|
||||
if c.Type == "Terminating" && c.Status == "True" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
@ -14,11 +14,13 @@ import (
|
|||
"sigs.k8s.io/cli-utils/pkg/apply/event"
|
||||
"sigs.k8s.io/cli-utils/pkg/inventory"
|
||||
"sigs.k8s.io/cli-utils/pkg/testutil"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/e2eutil"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/invconfig"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
//nolint:dupl // expEvents similar to other tests
|
||||
func emptySetTest(ctx context.Context, c client.Client, invConfig InventoryConfig, inventoryName, namespaceName string) {
|
||||
func emptySetTest(ctx context.Context, c client.Client, invConfig invconfig.InventoryConfig, inventoryName, namespaceName string) {
|
||||
By("Apply zero resources")
|
||||
applier := invConfig.ApplierFactoryFunc()
|
||||
|
||||
|
|
@ -27,7 +29,7 @@ func emptySetTest(ctx context.Context, c client.Client, invConfig InventoryConfi
|
|||
|
||||
resources := []*unstructured.Unstructured{}
|
||||
|
||||
applierEvents := runCollect(applier.Run(ctx, inventoryInfo, resources, apply.ApplierOptions{
|
||||
applierEvents := e2eutil.RunCollect(applier.Run(ctx, inventoryInfo, resources, apply.ApplierOptions{
|
||||
EmitStatusEvents: true,
|
||||
}))
|
||||
|
||||
|
|
@ -83,7 +85,7 @@ func emptySetTest(ctx context.Context, c client.Client, invConfig InventoryConfi
|
|||
destroyer := invConfig.DestroyerFactoryFunc()
|
||||
|
||||
options := apply.DestroyerOptions{InventoryPolicy: inventory.PolicyAdoptIfNoInventory}
|
||||
destroyerEvents := runCollect(destroyer.Run(ctx, inventoryInfo, options))
|
||||
destroyerEvents := e2eutil.RunCollect(destroyer.Run(ctx, inventoryInfo, options))
|
||||
|
||||
expEvents = []testutil.ExpEvent{
|
||||
{
|
||||
|
|
|
|||
|
|
@ -16,10 +16,12 @@ import (
|
|||
"sigs.k8s.io/cli-utils/pkg/object"
|
||||
"sigs.k8s.io/cli-utils/pkg/object/validation"
|
||||
"sigs.k8s.io/cli-utils/pkg/testutil"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/e2eutil"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/invconfig"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
func exitEarlyTest(ctx context.Context, c client.Client, invConfig InventoryConfig, inventoryName, namespaceName string) {
|
||||
func exitEarlyTest(ctx context.Context, c client.Client, invConfig invconfig.InventoryConfig, inventoryName, namespaceName string) {
|
||||
By("exit early on invalid object")
|
||||
applier := invConfig.ApplierFactoryFunc()
|
||||
|
||||
|
|
@ -27,12 +29,12 @@ func exitEarlyTest(ctx context.Context, c client.Client, invConfig InventoryConf
|
|||
|
||||
fields := struct{ Namespace string }{Namespace: namespaceName}
|
||||
// valid pod
|
||||
pod1Obj := withNamespace(manifestToUnstructured(pod1), namespaceName)
|
||||
pod1Obj := e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod1), namespaceName)
|
||||
// valid deployment with dependency
|
||||
deployment1Obj := withDependsOn(withNamespace(manifestToUnstructured(deployment1), namespaceName),
|
||||
deployment1Obj := e2eutil.WithDependsOn(e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(deployment1), namespaceName),
|
||||
fmt.Sprintf("/namespaces/%s/Pod/%s", namespaceName, pod1Obj.GetName()))
|
||||
// missing name
|
||||
invalidPodObj := templateToUnstructured(invalidPodTemplate, fields)
|
||||
invalidPodObj := e2eutil.TemplateToUnstructured(invalidPodTemplate, fields)
|
||||
|
||||
resources := []*unstructured.Unstructured{
|
||||
pod1Obj,
|
||||
|
|
@ -40,7 +42,7 @@ func exitEarlyTest(ctx context.Context, c client.Client, invConfig InventoryConf
|
|||
invalidPodObj,
|
||||
}
|
||||
|
||||
applierEvents := runCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
||||
applierEvents := e2eutil.RunCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
||||
EmitStatusEvents: false,
|
||||
ValidationPolicy: validation.ExitEarly,
|
||||
}))
|
||||
|
|
@ -60,8 +62,8 @@ func exitEarlyTest(ctx context.Context, c client.Client, invConfig InventoryConf
|
|||
Expect(testutil.EventsToExpEvents(applierEvents)).To(testutil.Equal(expEvents))
|
||||
|
||||
By("verify pod1 not found")
|
||||
assertUnstructuredDoesNotExist(ctx, c, pod1Obj)
|
||||
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, pod1Obj)
|
||||
|
||||
By("verify deployment1 not found")
|
||||
assertUnstructuredDoesNotExist(ctx, c, deployment1Obj)
|
||||
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, deployment1Obj)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
// Copyright 2021 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package invconfig
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/onsi/gomega"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/client-go/rest"
|
||||
"sigs.k8s.io/cli-utils/pkg/apply"
|
||||
"sigs.k8s.io/cli-utils/pkg/common"
|
||||
"sigs.k8s.io/cli-utils/pkg/inventory"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
func NewConfigMapTypeInvConfig(cfg *rest.Config) InventoryConfig {
|
||||
return InventoryConfig{
|
||||
ClientConfig: cfg,
|
||||
Strategy: inventory.LabelStrategy,
|
||||
FactoryFunc: cmInventoryManifest,
|
||||
InvWrapperFunc: inventory.WrapInventoryInfoObj,
|
||||
ApplierFactoryFunc: newDefaultInvApplierFactory(cfg),
|
||||
DestroyerFactoryFunc: newDefaultInvDestroyerFactory(cfg),
|
||||
InvSizeVerifyFunc: defaultInvSizeVerifyFunc,
|
||||
InvCountVerifyFunc: defaultInvCountVerifyFunc,
|
||||
InvNotExistsFunc: defaultInvNotExistsFunc,
|
||||
}
|
||||
}
|
||||
|
||||
func newDefaultInvApplierFactory(cfg *rest.Config) applierFactoryFunc {
|
||||
cfgPtrCopy := cfg
|
||||
return func() *apply.Applier {
|
||||
return newApplier(inventory.ClusterClientFactory{
|
||||
StatusPolicy: inventory.StatusPolicyAll,
|
||||
}, cfgPtrCopy)
|
||||
}
|
||||
}
|
||||
|
||||
func newDefaultInvDestroyerFactory(cfg *rest.Config) destroyerFactoryFunc {
|
||||
cfgPtrCopy := cfg
|
||||
return func() *apply.Destroyer {
|
||||
return newDestroyer(inventory.ClusterClientFactory{
|
||||
StatusPolicy: inventory.StatusPolicyAll,
|
||||
}, cfgPtrCopy)
|
||||
}
|
||||
}
|
||||
|
||||
func defaultInvNotExistsFunc(ctx context.Context, c client.Client, name, namespace, id string) {
|
||||
var cmList v1.ConfigMapList
|
||||
err := c.List(ctx, &cmList,
|
||||
client.MatchingLabels(map[string]string{common.InventoryLabel: id}),
|
||||
client.InNamespace(namespace))
|
||||
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
||||
gomega.Expect(cmList.Items).To(gomega.HaveLen(0), "expected inventory list to be empty")
|
||||
}
|
||||
|
||||
func defaultInvSizeVerifyFunc(ctx context.Context, c client.Client, name, namespace, id string, specCount, _ int) {
|
||||
var cmList v1.ConfigMapList
|
||||
err := c.List(ctx, &cmList,
|
||||
client.MatchingLabels(map[string]string{common.InventoryLabel: id}),
|
||||
client.InNamespace(namespace))
|
||||
gomega.Expect(err).WithOffset(1).ToNot(gomega.HaveOccurred(), "listing ConfigMap inventory from cluster")
|
||||
|
||||
gomega.Expect(len(cmList.Items)).WithOffset(1).To(gomega.Equal(1), "number of inventory objects by label")
|
||||
|
||||
data := cmList.Items[0].Data
|
||||
gomega.Expect(len(data)).WithOffset(1).To(gomega.Equal(specCount), "inventory spec.data length")
|
||||
|
||||
// Don't validate status size.
|
||||
// ConfigMap provider uses inventory.StatusPolicyNone.
|
||||
}
|
||||
|
||||
func defaultInvCountVerifyFunc(ctx context.Context, c client.Client, namespace string, count int) {
|
||||
var cmList v1.ConfigMapList
|
||||
err := c.List(ctx, &cmList, client.InNamespace(namespace), client.HasLabels{common.InventoryLabel})
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
gomega.Expect(len(cmList.Items)).To(gomega.Equal(count))
|
||||
}
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
// Copyright 2021 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package invconfig
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/onsi/gomega"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/rest"
|
||||
"sigs.k8s.io/cli-utils/pkg/apply"
|
||||
"sigs.k8s.io/cli-utils/pkg/common"
|
||||
"sigs.k8s.io/cli-utils/pkg/inventory"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/customprovider"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/e2eutil"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
func NewCustomTypeInvConfig(cfg *rest.Config) InventoryConfig {
|
||||
return InventoryConfig{
|
||||
ClientConfig: cfg,
|
||||
Strategy: inventory.NameStrategy,
|
||||
FactoryFunc: customInventoryManifest,
|
||||
InvWrapperFunc: customprovider.WrapInventoryInfoObj,
|
||||
ApplierFactoryFunc: newCustomInvApplierFactory(cfg),
|
||||
DestroyerFactoryFunc: newCustomInvDestroyerFactory(cfg),
|
||||
InvSizeVerifyFunc: customInvSizeVerifyFunc,
|
||||
InvCountVerifyFunc: customInvCountVerifyFunc,
|
||||
InvNotExistsFunc: customInvNotExistsFunc,
|
||||
}
|
||||
}
|
||||
|
||||
func newCustomInvApplierFactory(cfg *rest.Config) applierFactoryFunc {
|
||||
cfgPtrCopy := cfg
|
||||
return func() *apply.Applier {
|
||||
return newApplier(customprovider.CustomClientFactory{}, cfgPtrCopy)
|
||||
}
|
||||
}
|
||||
|
||||
func newCustomInvDestroyerFactory(cfg *rest.Config) destroyerFactoryFunc {
|
||||
cfgPtrCopy := cfg
|
||||
return func() *apply.Destroyer {
|
||||
return newDestroyer(customprovider.CustomClientFactory{}, cfgPtrCopy)
|
||||
}
|
||||
}
|
||||
|
||||
func customInvNotExistsFunc(ctx context.Context, c client.Client, name, namespace, id string) {
|
||||
var u unstructured.Unstructured
|
||||
u.SetGroupVersionKind(customprovider.InventoryGVK)
|
||||
u.SetName(name)
|
||||
u.SetNamespace(namespace)
|
||||
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, &u)
|
||||
}
|
||||
|
||||
func customInvSizeVerifyFunc(ctx context.Context, c client.Client, name, namespace, _ string, specCount, statusCount int) {
|
||||
var u unstructured.Unstructured
|
||||
u.SetGroupVersionKind(customprovider.InventoryGVK)
|
||||
err := c.Get(ctx, types.NamespacedName{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
}, &u)
|
||||
gomega.Expect(err).WithOffset(1).ToNot(gomega.HaveOccurred(), "getting custom inventory from cluster")
|
||||
|
||||
s, found, err := unstructured.NestedSlice(u.Object, "spec", "objects")
|
||||
gomega.Expect(err).WithOffset(1).ToNot(gomega.HaveOccurred(), "reading inventory spec.objects")
|
||||
if found {
|
||||
gomega.Expect(len(s)).WithOffset(1).To(gomega.Equal(specCount), "inventory status.objects length")
|
||||
} else {
|
||||
gomega.Expect(specCount).WithOffset(1).To(gomega.Equal(0), "inventory spec.objects not found")
|
||||
}
|
||||
|
||||
s, found, err = unstructured.NestedSlice(u.Object, "status", "objects")
|
||||
gomega.Expect(err).WithOffset(1).ToNot(gomega.HaveOccurred(), "reading inventory status.objects")
|
||||
if found {
|
||||
gomega.Expect(len(s)).WithOffset(1).To(gomega.Equal(statusCount), "inventory status.objects length")
|
||||
} else {
|
||||
gomega.Expect(statusCount).WithOffset(1).To(gomega.Equal(0), "inventory status.objects not found")
|
||||
}
|
||||
}
|
||||
|
||||
func customInvCountVerifyFunc(ctx context.Context, c client.Client, namespace string, count int) {
|
||||
var u unstructured.UnstructuredList
|
||||
u.SetGroupVersionKind(customprovider.InventoryGVK)
|
||||
err := c.List(ctx, &u, client.InNamespace(namespace))
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
gomega.Expect(len(u.Items)).To(gomega.Equal(count))
|
||||
}
|
||||
|
||||
func cmInventoryManifest(name, namespace, id string) *unstructured.Unstructured {
|
||||
cm := &v1.ConfigMap{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: v1.SchemeGroupVersion.String(),
|
||||
Kind: "ConfigMap",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
Labels: map[string]string{
|
||||
common.InventoryLabel: id,
|
||||
},
|
||||
},
|
||||
}
|
||||
u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(cm)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return &unstructured.Unstructured{
|
||||
Object: u,
|
||||
}
|
||||
}
|
||||
|
||||
func customInventoryManifest(name, namespace, id string) *unstructured.Unstructured {
|
||||
u := e2eutil.ManifestToUnstructured([]byte(strings.TrimSpace(`
|
||||
apiVersion: cli-utils.example.io/v1alpha1
|
||||
kind: Inventory
|
||||
metadata:
|
||||
name: PLACEHOLDER
|
||||
`)))
|
||||
u.SetName(name)
|
||||
u.SetNamespace(namespace)
|
||||
u.SetLabels(map[string]string{
|
||||
common.InventoryLabel: id,
|
||||
})
|
||||
return u
|
||||
}
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
// Copyright 2021 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package invconfig
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/onsi/gomega"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/kubectl/pkg/cmd/util"
|
||||
"sigs.k8s.io/cli-utils/pkg/apply"
|
||||
"sigs.k8s.io/cli-utils/pkg/inventory"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/e2eutil"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
type inventoryFactoryFunc func(name, namespace, id string) *unstructured.Unstructured
|
||||
type invWrapperFunc func(*unstructured.Unstructured) inventory.Info
|
||||
type applierFactoryFunc func() *apply.Applier
|
||||
type destroyerFactoryFunc func() *apply.Destroyer
|
||||
type invSizeVerifyFunc func(ctx context.Context, c client.Client, name, namespace, id string, specCount, statusCount int)
|
||||
type invCountVerifyFunc func(ctx context.Context, c client.Client, namespace string, count int)
|
||||
type invNotExistsFunc func(ctx context.Context, c client.Client, name, namespace, id string)
|
||||
|
||||
type InventoryConfig struct {
|
||||
ClientConfig *rest.Config
|
||||
Strategy inventory.Strategy
|
||||
FactoryFunc inventoryFactoryFunc
|
||||
InvWrapperFunc invWrapperFunc
|
||||
ApplierFactoryFunc applierFactoryFunc
|
||||
DestroyerFactoryFunc destroyerFactoryFunc
|
||||
InvSizeVerifyFunc invSizeVerifyFunc
|
||||
InvCountVerifyFunc invCountVerifyFunc
|
||||
InvNotExistsFunc invNotExistsFunc
|
||||
}
|
||||
|
||||
func CreateInventoryInfo(invConfig InventoryConfig, inventoryName, namespaceName, inventoryID string) inventory.Info {
|
||||
switch invConfig.Strategy {
|
||||
case inventory.NameStrategy:
|
||||
return invConfig.InvWrapperFunc(invConfig.FactoryFunc(inventoryName, namespaceName, e2eutil.RandomString("inventory-")))
|
||||
case inventory.LabelStrategy:
|
||||
return invConfig.InvWrapperFunc(invConfig.FactoryFunc(e2eutil.RandomString("inventory-"), namespaceName, inventoryID))
|
||||
default:
|
||||
panic(fmt.Errorf("unknown inventory strategy %q", invConfig.Strategy))
|
||||
}
|
||||
}
|
||||
|
||||
func newFactory(cfg *rest.Config) util.Factory {
|
||||
kubeConfigFlags := genericclioptions.NewConfigFlags(true).WithDeprecatedPasswordFlag()
|
||||
cfgPtrCopy := cfg
|
||||
kubeConfigFlags.WrapConfigFn = func(c *rest.Config) *rest.Config {
|
||||
// update rest.Config to pick up QPS & timeout changes
|
||||
deepCopyRESTConfig(cfgPtrCopy, c)
|
||||
return c
|
||||
}
|
||||
matchVersionKubeConfigFlags := util.NewMatchVersionFlags(kubeConfigFlags)
|
||||
return util.NewFactory(matchVersionKubeConfigFlags)
|
||||
}
|
||||
|
||||
func newApplier(invFactory inventory.ClientFactory, cfg *rest.Config) *apply.Applier {
|
||||
f := newFactory(cfg)
|
||||
invClient, err := invFactory.NewClient(f)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
|
||||
a, err := apply.NewApplierBuilder().
|
||||
WithFactory(f).
|
||||
WithInventoryClient(invClient).
|
||||
Build()
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
return a
|
||||
}
|
||||
|
||||
func newDestroyer(invFactory inventory.ClientFactory, cfg *rest.Config) *apply.Destroyer {
|
||||
f := newFactory(cfg)
|
||||
invClient, err := invFactory.NewClient(f)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
|
||||
d, err := apply.NewDestroyer(f, invClient)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
return d
|
||||
}
|
||||
|
||||
func deepCopyRESTConfig(from, to *rest.Config) {
|
||||
to.Host = from.Host
|
||||
to.APIPath = from.APIPath
|
||||
to.ContentConfig = from.ContentConfig
|
||||
to.Username = from.Username
|
||||
to.Password = from.Password
|
||||
to.BearerToken = from.BearerToken
|
||||
to.BearerTokenFile = from.BearerTokenFile
|
||||
to.Impersonate = rest.ImpersonationConfig{
|
||||
UserName: from.Impersonate.UserName,
|
||||
UID: from.Impersonate.UID,
|
||||
Groups: from.Impersonate.Groups,
|
||||
Extra: from.Impersonate.Extra,
|
||||
}
|
||||
to.AuthProvider = from.AuthProvider
|
||||
to.AuthConfigPersister = from.AuthConfigPersister
|
||||
to.ExecProvider = from.ExecProvider
|
||||
if from.ExecProvider != nil && from.ExecProvider.Config != nil {
|
||||
to.ExecProvider.Config = from.ExecProvider.Config.DeepCopyObject()
|
||||
}
|
||||
to.TLSClientConfig = rest.TLSClientConfig{
|
||||
Insecure: from.TLSClientConfig.Insecure,
|
||||
ServerName: from.TLSClientConfig.ServerName,
|
||||
CertFile: from.TLSClientConfig.CertFile,
|
||||
KeyFile: from.TLSClientConfig.KeyFile,
|
||||
CAFile: from.TLSClientConfig.CAFile,
|
||||
CertData: from.TLSClientConfig.CertData,
|
||||
KeyData: from.TLSClientConfig.KeyData,
|
||||
CAData: from.TLSClientConfig.CAData,
|
||||
NextProtos: from.TLSClientConfig.NextProtos,
|
||||
}
|
||||
to.UserAgent = from.UserAgent
|
||||
to.DisableCompression = from.DisableCompression
|
||||
to.Transport = from.Transport
|
||||
to.WrapTransport = from.WrapTransport
|
||||
to.QPS = from.QPS
|
||||
to.Burst = from.Burst
|
||||
to.RateLimiter = from.RateLimiter
|
||||
to.WarningHandler = from.WarningHandler
|
||||
to.Timeout = from.Timeout
|
||||
to.Dial = from.Dial
|
||||
to.Proxy = from.Proxy
|
||||
}
|
||||
|
|
@ -17,34 +17,36 @@ import (
|
|||
"sigs.k8s.io/cli-utils/pkg/kstatus/status"
|
||||
"sigs.k8s.io/cli-utils/pkg/object"
|
||||
"sigs.k8s.io/cli-utils/pkg/testutil"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/e2eutil"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/invconfig"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
func inventoryPolicyMustMatchTest(ctx context.Context, c client.Client, invConfig InventoryConfig, namespaceName string) {
|
||||
func inventoryPolicyMustMatchTest(ctx context.Context, c client.Client, invConfig invconfig.InventoryConfig, namespaceName string) {
|
||||
By("Apply first set of resources")
|
||||
applier := invConfig.ApplierFactoryFunc()
|
||||
|
||||
firstInvName := randomString("first-inv-")
|
||||
firstInvName := e2eutil.RandomString("first-inv-")
|
||||
firstInv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(firstInvName, namespaceName, firstInvName))
|
||||
deployment1Obj := withNamespace(manifestToUnstructured(deployment1), namespaceName)
|
||||
deployment1Obj := e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(deployment1), namespaceName)
|
||||
firstResources := []*unstructured.Unstructured{
|
||||
deployment1Obj,
|
||||
}
|
||||
|
||||
runWithNoErr(applier.Run(ctx, firstInv, firstResources, apply.ApplierOptions{
|
||||
e2eutil.RunWithNoErr(applier.Run(ctx, firstInv, firstResources, apply.ApplierOptions{
|
||||
ReconcileTimeout: 2 * time.Minute,
|
||||
EmitStatusEvents: true,
|
||||
}))
|
||||
|
||||
By("Apply second set of resources")
|
||||
secondInvName := randomString("second-inv-")
|
||||
secondInvName := e2eutil.RandomString("second-inv-")
|
||||
secondInv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(secondInvName, namespaceName, secondInvName))
|
||||
deployment1Obj = withNamespace(manifestToUnstructured(deployment1), namespaceName)
|
||||
deployment1Obj = e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(deployment1), namespaceName)
|
||||
secondResources := []*unstructured.Unstructured{
|
||||
withReplicas(deployment1Obj, 6),
|
||||
e2eutil.WithReplicas(deployment1Obj, 6),
|
||||
}
|
||||
|
||||
applierEvents := runCollect(applier.Run(ctx, secondInv, secondResources, apply.ApplierOptions{
|
||||
applierEvents := e2eutil.RunCollect(applier.Run(ctx, secondInv, secondResources, apply.ApplierOptions{
|
||||
ReconcileTimeout: 2 * time.Minute,
|
||||
EmitStatusEvents: true,
|
||||
InventoryPolicy: inventory.PolicyMustMatch,
|
||||
|
|
@ -178,7 +180,7 @@ func inventoryPolicyMustMatchTest(ctx context.Context, c client.Client, invConfi
|
|||
Expect(received).To(testutil.Equal(expEvents))
|
||||
|
||||
By("Verify resource wasn't updated")
|
||||
result := assertUnstructuredExists(ctx, c, deployment1Obj)
|
||||
result := e2eutil.AssertUnstructuredExists(ctx, c, deployment1Obj)
|
||||
replicas, found, err := object.NestedField(result.Object, "spec", "replicas")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(found).To(BeTrue())
|
||||
|
|
@ -187,22 +189,22 @@ func inventoryPolicyMustMatchTest(ctx context.Context, c client.Client, invConfi
|
|||
invConfig.InvCountVerifyFunc(ctx, c, namespaceName, 2)
|
||||
}
|
||||
|
||||
func inventoryPolicyAdoptIfNoInventoryTest(ctx context.Context, c client.Client, invConfig InventoryConfig, namespaceName string) {
|
||||
func inventoryPolicyAdoptIfNoInventoryTest(ctx context.Context, c client.Client, invConfig invconfig.InventoryConfig, namespaceName string) {
|
||||
By("Create unmanaged resource")
|
||||
deployment1Obj := withNamespace(manifestToUnstructured(deployment1), namespaceName)
|
||||
createUnstructuredAndWait(ctx, c, deployment1Obj)
|
||||
deployment1Obj := e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(deployment1), namespaceName)
|
||||
e2eutil.CreateUnstructuredAndWait(ctx, c, deployment1Obj)
|
||||
|
||||
By("Apply resources")
|
||||
applier := invConfig.ApplierFactoryFunc()
|
||||
|
||||
invName := randomString("test-inv-")
|
||||
invName := e2eutil.RandomString("test-inv-")
|
||||
inv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(invName, namespaceName, invName))
|
||||
deployment1Obj = withNamespace(manifestToUnstructured(deployment1), namespaceName)
|
||||
deployment1Obj = e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(deployment1), namespaceName)
|
||||
resources := []*unstructured.Unstructured{
|
||||
withReplicas(deployment1Obj, 6),
|
||||
e2eutil.WithReplicas(deployment1Obj, 6),
|
||||
}
|
||||
|
||||
applierEvents := runCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
||||
applierEvents := e2eutil.RunCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
||||
ReconcileTimeout: 2 * time.Minute,
|
||||
EmitStatusEvents: true,
|
||||
InventoryPolicy: inventory.PolicyAdoptIfNoInventory,
|
||||
|
|
@ -344,7 +346,7 @@ func inventoryPolicyAdoptIfNoInventoryTest(ctx context.Context, c client.Client,
|
|||
Expect(received).To(testutil.Equal(expEvents))
|
||||
|
||||
By("Verify resource was updated and added to inventory")
|
||||
result := assertUnstructuredExists(ctx, c, deployment1Obj)
|
||||
result := e2eutil.AssertUnstructuredExists(ctx, c, deployment1Obj)
|
||||
|
||||
replicas, found, err := object.NestedField(result.Object, "spec", "replicas")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
|
@ -360,31 +362,31 @@ func inventoryPolicyAdoptIfNoInventoryTest(ctx context.Context, c client.Client,
|
|||
invConfig.InvSizeVerifyFunc(ctx, c, invName, namespaceName, invName, 1, 1)
|
||||
}
|
||||
|
||||
func inventoryPolicyAdoptAllTest(ctx context.Context, c client.Client, invConfig InventoryConfig, namespaceName string) {
|
||||
func inventoryPolicyAdoptAllTest(ctx context.Context, c client.Client, invConfig invconfig.InventoryConfig, namespaceName string) {
|
||||
By("Apply an initial set of resources")
|
||||
applier := invConfig.ApplierFactoryFunc()
|
||||
|
||||
firstInvName := randomString("first-inv-")
|
||||
firstInvName := e2eutil.RandomString("first-inv-")
|
||||
firstInv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(firstInvName, namespaceName, firstInvName))
|
||||
deployment1Obj := withNamespace(manifestToUnstructured(deployment1), namespaceName)
|
||||
deployment1Obj := e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(deployment1), namespaceName)
|
||||
firstResources := []*unstructured.Unstructured{
|
||||
deployment1Obj,
|
||||
}
|
||||
|
||||
runWithNoErr(applier.Run(ctx, firstInv, firstResources, apply.ApplierOptions{
|
||||
e2eutil.RunWithNoErr(applier.Run(ctx, firstInv, firstResources, apply.ApplierOptions{
|
||||
ReconcileTimeout: 2 * time.Minute,
|
||||
EmitStatusEvents: true,
|
||||
}))
|
||||
|
||||
By("Apply resources")
|
||||
secondInvName := randomString("test-inv-")
|
||||
secondInvName := e2eutil.RandomString("test-inv-")
|
||||
secondInv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(secondInvName, namespaceName, secondInvName))
|
||||
deployment1Obj = withNamespace(manifestToUnstructured(deployment1), namespaceName)
|
||||
deployment1Obj = e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(deployment1), namespaceName)
|
||||
secondResources := []*unstructured.Unstructured{
|
||||
withReplicas(deployment1Obj, 6),
|
||||
e2eutil.WithReplicas(deployment1Obj, 6),
|
||||
}
|
||||
|
||||
applierEvents := runCollect(applier.Run(ctx, secondInv, secondResources, apply.ApplierOptions{
|
||||
applierEvents := e2eutil.RunCollect(applier.Run(ctx, secondInv, secondResources, apply.ApplierOptions{
|
||||
ReconcileTimeout: 2 * time.Minute,
|
||||
EmitStatusEvents: true,
|
||||
InventoryPolicy: inventory.PolicyAdoptAll,
|
||||
|
|
@ -526,7 +528,7 @@ func inventoryPolicyAdoptAllTest(ctx context.Context, c client.Client, invConfig
|
|||
Expect(received).To(testutil.Equal(expEvents))
|
||||
|
||||
By("Verify resource was updated and added to inventory")
|
||||
result := assertUnstructuredExists(ctx, c, deployment1Obj)
|
||||
result := e2eutil.AssertUnstructuredExists(ctx, c, deployment1Obj)
|
||||
|
||||
replicas, found, err := object.NestedField(result.Object, "spec", "replicas")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ import (
|
|||
"sigs.k8s.io/cli-utils/pkg/inventory"
|
||||
"sigs.k8s.io/cli-utils/pkg/object"
|
||||
"sigs.k8s.io/cli-utils/pkg/testutil"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/e2eutil"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/invconfig"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
|
|
@ -32,15 +34,15 @@ import (
|
|||
// port from pod-b into an environment variable of pod-a.
|
||||
|
||||
//nolint:dupl // expEvents similar to CRD tests
|
||||
func mutationTest(ctx context.Context, c client.Client, invConfig InventoryConfig, inventoryName, namespaceName string) {
|
||||
func mutationTest(ctx context.Context, c client.Client, invConfig invconfig.InventoryConfig, inventoryName, namespaceName string) {
|
||||
By("apply resources in order with substitutions based on apply-time-mutation annotation")
|
||||
applier := invConfig.ApplierFactoryFunc()
|
||||
|
||||
inv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(inventoryName, namespaceName, "test"))
|
||||
|
||||
fields := struct{ Namespace string }{Namespace: namespaceName}
|
||||
podAObj := templateToUnstructured(podATemplate, fields)
|
||||
podBObj := templateToUnstructured(podBTemplate, fields)
|
||||
podAObj := e2eutil.TemplateToUnstructured(podATemplate, fields)
|
||||
podBObj := e2eutil.TemplateToUnstructured(podBTemplate, fields)
|
||||
|
||||
// Dependency order: podA -> podB
|
||||
// Apply order: podB, podA
|
||||
|
|
@ -49,7 +51,7 @@ func mutationTest(ctx context.Context, c client.Client, invConfig InventoryConfi
|
|||
podBObj,
|
||||
}
|
||||
|
||||
applierEvents := runCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
||||
applierEvents := e2eutil.RunCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
||||
EmitStatusEvents: false,
|
||||
}))
|
||||
|
||||
|
|
@ -227,7 +229,7 @@ func mutationTest(ctx context.Context, c client.Client, invConfig InventoryConfi
|
|||
Expect(testutil.EventsToExpEvents(applierEvents)).To(testutil.Equal(expEvents))
|
||||
|
||||
By("verify podB is created and ready")
|
||||
result := assertUnstructuredExists(ctx, c, podBObj)
|
||||
result := e2eutil.AssertUnstructuredExists(ctx, c, podBObj)
|
||||
|
||||
podIP, found, err := object.NestedField(result.Object, "status", "podIP")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
|
@ -242,7 +244,7 @@ func mutationTest(ctx context.Context, c client.Client, invConfig InventoryConfi
|
|||
host := fmt.Sprintf("%s:%d", podIP, containerPort)
|
||||
|
||||
By("verify podA is mutated, created, and ready")
|
||||
result = assertUnstructuredExists(ctx, c, podAObj)
|
||||
result = e2eutil.AssertUnstructuredExists(ctx, c, podAObj)
|
||||
|
||||
podIP, found, err = object.NestedField(result.Object, "status", "podIP")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
|
@ -257,7 +259,7 @@ func mutationTest(ctx context.Context, c client.Client, invConfig InventoryConfi
|
|||
By("destroy resources in opposite order")
|
||||
destroyer := invConfig.DestroyerFactoryFunc()
|
||||
options := apply.DestroyerOptions{InventoryPolicy: inventory.PolicyAdoptIfNoInventory}
|
||||
destroyerEvents := runCollect(destroyer.Run(ctx, inv, options))
|
||||
destroyerEvents := e2eutil.RunCollect(destroyer.Run(ctx, inv, options))
|
||||
|
||||
expEvents = []testutil.ExpEvent{
|
||||
{
|
||||
|
|
@ -416,8 +418,8 @@ func mutationTest(ctx context.Context, c client.Client, invConfig InventoryConfi
|
|||
Expect(testutil.EventsToExpEvents(destroyerEvents)).To(testutil.Equal(expEvents))
|
||||
|
||||
By("verify podB deleted")
|
||||
assertUnstructuredDoesNotExist(ctx, c, podBObj)
|
||||
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, podBObj)
|
||||
|
||||
By("verify podA deleted")
|
||||
assertUnstructuredDoesNotExist(ctx, c, podAObj)
|
||||
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, podAObj)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,10 +12,12 @@ import (
|
|||
. "github.com/onsi/gomega"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"sigs.k8s.io/cli-utils/pkg/apply"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/e2eutil"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/invconfig"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
func applyWithExistingInvTest(ctx context.Context, c client.Client, invConfig InventoryConfig, inventoryName, namespaceName string) {
|
||||
func applyWithExistingInvTest(ctx context.Context, c client.Client, invConfig invconfig.InventoryConfig, inventoryName, namespaceName string) {
|
||||
By("Apply first set of resources")
|
||||
applier := invConfig.ApplierFactoryFunc()
|
||||
orgInventoryID := fmt.Sprintf("%s-%s", inventoryName, namespaceName)
|
||||
|
|
@ -23,10 +25,10 @@ func applyWithExistingInvTest(ctx context.Context, c client.Client, invConfig In
|
|||
orgApplyInv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(inventoryName, namespaceName, orgInventoryID))
|
||||
|
||||
resources := []*unstructured.Unstructured{
|
||||
withNamespace(manifestToUnstructured(deployment1), namespaceName),
|
||||
e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(deployment1), namespaceName),
|
||||
}
|
||||
|
||||
runWithNoErr(applier.Run(ctx, orgApplyInv, resources, apply.ApplierOptions{
|
||||
e2eutil.RunWithNoErr(applier.Run(ctx, orgApplyInv, resources, apply.ApplierOptions{
|
||||
ReconcileTimeout: 2 * time.Minute,
|
||||
EmitStatusEvents: true,
|
||||
}))
|
||||
|
|
@ -38,7 +40,7 @@ func applyWithExistingInvTest(ctx context.Context, c client.Client, invConfig In
|
|||
secondInventoryID := fmt.Sprintf("%s-%s-2", inventoryName, namespaceName)
|
||||
secondApplyInv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(inventoryName, namespaceName, secondInventoryID))
|
||||
|
||||
err := run(applier.Run(ctx, secondApplyInv, resources, apply.ApplierOptions{
|
||||
err := e2eutil.Run(applier.Run(ctx, secondApplyInv, resources, apply.ApplierOptions{
|
||||
ReconcileTimeout: 2 * time.Minute,
|
||||
EmitStatusEvents: true,
|
||||
}))
|
||||
|
|
|
|||
|
|
@ -14,11 +14,13 @@ import (
|
|||
"sigs.k8s.io/cli-utils/pkg/apply/event"
|
||||
"sigs.k8s.io/cli-utils/pkg/object"
|
||||
"sigs.k8s.io/cli-utils/pkg/testutil"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/e2eutil"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/invconfig"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
//nolint:dupl // expEvents similar to other tests
|
||||
func namespaceFilterTest(ctx context.Context, c client.Client, invConfig InventoryConfig, inventoryName, namespaceName string) {
|
||||
func namespaceFilterTest(ctx context.Context, c client.Client, invConfig invconfig.InventoryConfig, inventoryName, namespaceName string) {
|
||||
By("apply resources in order based on depends-on annotation")
|
||||
applier := invConfig.ApplierFactoryFunc()
|
||||
|
||||
|
|
@ -27,8 +29,8 @@ func namespaceFilterTest(ctx context.Context, c client.Client, invConfig Invento
|
|||
namespace1Name := fmt.Sprintf("%s-ns1", namespaceName)
|
||||
|
||||
fields := struct{ Namespace string }{Namespace: namespace1Name}
|
||||
namespace1Obj := templateToUnstructured(namespaceTemplate, fields)
|
||||
podBObj := templateToUnstructured(podBTemplate, fields)
|
||||
namespace1Obj := e2eutil.TemplateToUnstructured(namespaceTemplate, fields)
|
||||
podBObj := e2eutil.TemplateToUnstructured(podBTemplate, fields)
|
||||
|
||||
// Dependency order: podB -> namespace1
|
||||
// Apply order: namespace1, podB
|
||||
|
|
@ -39,11 +41,11 @@ func namespaceFilterTest(ctx context.Context, c client.Client, invConfig Invento
|
|||
|
||||
// Cleanup
|
||||
defer func(ctx context.Context, c client.Client) {
|
||||
deleteUnstructuredIfExists(ctx, c, podBObj)
|
||||
deleteUnstructuredIfExists(ctx, c, namespace1Obj)
|
||||
e2eutil.DeleteUnstructuredIfExists(ctx, c, podBObj)
|
||||
e2eutil.DeleteUnstructuredIfExists(ctx, c, namespace1Obj)
|
||||
}(ctx, c)
|
||||
|
||||
applierEvents := runCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
||||
applierEvents := e2eutil.RunCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
||||
EmitStatusEvents: false,
|
||||
}))
|
||||
|
||||
|
|
@ -221,10 +223,10 @@ func namespaceFilterTest(ctx context.Context, c client.Client, invConfig Invento
|
|||
Expect(testutil.EventsToExpEvents(applierEvents)).To(testutil.Equal(expEvents))
|
||||
|
||||
By("verify namespace1 created")
|
||||
assertUnstructuredExists(ctx, c, namespace1Obj)
|
||||
e2eutil.AssertUnstructuredExists(ctx, c, namespace1Obj)
|
||||
|
||||
By("verify podB created and ready")
|
||||
result := assertUnstructuredExists(ctx, c, podBObj)
|
||||
result := e2eutil.AssertUnstructuredExists(ctx, c, podBObj)
|
||||
podIP, found, err := object.NestedField(result.Object, "status", "podIP")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(found).To(BeTrue())
|
||||
|
|
@ -235,7 +237,7 @@ func namespaceFilterTest(ctx context.Context, c client.Client, invConfig Invento
|
|||
podBObj,
|
||||
}
|
||||
|
||||
applierEvents = runCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
||||
applierEvents = e2eutil.RunCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
||||
EmitStatusEvents: false,
|
||||
}))
|
||||
|
||||
|
|
@ -395,13 +397,13 @@ func namespaceFilterTest(ctx context.Context, c client.Client, invConfig Invento
|
|||
Expect(testutil.EventsToExpEvents(applierEvents)).To(testutil.Equal(expEvents))
|
||||
|
||||
By("verify namespace1 not deleted")
|
||||
result = assertUnstructuredExists(ctx, c, namespace1Obj)
|
||||
result = e2eutil.AssertUnstructuredExists(ctx, c, namespace1Obj)
|
||||
ts, found, err := object.NestedField(result.Object, "metadata", "deletionTimestamp")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(found).To(BeFalse(), "deletionTimestamp found: ", ts)
|
||||
|
||||
By("verify podB not deleted")
|
||||
result = assertUnstructuredExists(ctx, c, podBObj)
|
||||
result = e2eutil.AssertUnstructuredExists(ctx, c, podBObj)
|
||||
ts, found, err = object.NestedField(result.Object, "metadata", "deletionTimestamp")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(found).To(BeFalse(), "deletionTimestamp found: ", ts)
|
||||
|
|
|
|||
|
|
@ -15,23 +15,25 @@ import (
|
|||
"sigs.k8s.io/cli-utils/pkg/inventory"
|
||||
"sigs.k8s.io/cli-utils/pkg/object"
|
||||
"sigs.k8s.io/cli-utils/pkg/testutil"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/e2eutil"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/invconfig"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
func pruneRetrieveErrorTest(ctx context.Context, c client.Client, invConfig InventoryConfig, inventoryName, namespaceName string) {
|
||||
func pruneRetrieveErrorTest(ctx context.Context, c client.Client, invConfig invconfig.InventoryConfig, inventoryName, namespaceName string) {
|
||||
By("apply a single resource, which is referenced in the inventory")
|
||||
applier := invConfig.ApplierFactoryFunc()
|
||||
|
||||
inventoryID := fmt.Sprintf("%s-%s", inventoryName, namespaceName)
|
||||
|
||||
inv := createInventoryInfo(invConfig, inventoryName, namespaceName, inventoryID)
|
||||
inv := invconfig.CreateInventoryInfo(invConfig, inventoryName, namespaceName, inventoryID)
|
||||
|
||||
pod1Obj := withNamespace(manifestToUnstructured(pod1), namespaceName)
|
||||
pod1Obj := e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod1), namespaceName)
|
||||
resource1 := []*unstructured.Unstructured{
|
||||
pod1Obj,
|
||||
}
|
||||
|
||||
applierEvents := runCollect(applier.Run(ctx, inv, resource1, apply.ApplierOptions{
|
||||
applierEvents := e2eutil.RunCollect(applier.Run(ctx, inv, resource1, apply.ApplierOptions{
|
||||
EmitStatusEvents: false,
|
||||
}))
|
||||
|
||||
|
|
@ -145,7 +147,7 @@ func pruneRetrieveErrorTest(ctx context.Context, c client.Client, invConfig Inve
|
|||
Expect(testutil.EventsToExpEvents(applierEvents)).To(testutil.Equal(expEvents))
|
||||
|
||||
By("Verify pod1 created and ready")
|
||||
result := assertUnstructuredExists(ctx, c, pod1Obj)
|
||||
result := e2eutil.AssertUnstructuredExists(ctx, c, pod1Obj)
|
||||
podIP, found, err := object.NestedField(result.Object, "status", "podIP")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(found).To(BeTrue())
|
||||
|
|
@ -153,19 +155,19 @@ func pruneRetrieveErrorTest(ctx context.Context, c client.Client, invConfig Inve
|
|||
|
||||
// Delete the previously applied resource, which is referenced in the inventory.
|
||||
By("delete resource, which is referenced in the inventory")
|
||||
deleteUnstructuredAndWait(ctx, c, pod1Obj)
|
||||
e2eutil.DeleteUnstructuredAndWait(ctx, c, pod1Obj)
|
||||
|
||||
By("Verify inventory")
|
||||
// The inventory should still have the previously deleted item.
|
||||
invConfig.InvSizeVerifyFunc(ctx, c, inventoryName, namespaceName, inventoryID, 1, 1)
|
||||
|
||||
By("apply a different resource, and validate the inventory accurately reflects only this object")
|
||||
pod2Obj := withNamespace(manifestToUnstructured(pod2), namespaceName)
|
||||
pod2Obj := e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod2), namespaceName)
|
||||
resource2 := []*unstructured.Unstructured{
|
||||
pod2Obj,
|
||||
}
|
||||
|
||||
applierEvents2 := runCollect(applier.Run(ctx, inv, resource2, apply.ApplierOptions{
|
||||
applierEvents2 := e2eutil.RunCollect(applier.Run(ctx, inv, resource2, apply.ApplierOptions{
|
||||
EmitStatusEvents: false,
|
||||
}))
|
||||
|
||||
|
|
@ -280,14 +282,14 @@ func pruneRetrieveErrorTest(ctx context.Context, c client.Client, invConfig Inve
|
|||
Expect(testutil.EventsToExpEvents(applierEvents2)).To(testutil.Equal(expEvents2))
|
||||
|
||||
By("Verify pod2 created and ready")
|
||||
result = assertUnstructuredExists(ctx, c, pod2Obj)
|
||||
result = e2eutil.AssertUnstructuredExists(ctx, c, pod2Obj)
|
||||
podIP, found, err = object.NestedField(result.Object, "status", "podIP")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(found).To(BeTrue())
|
||||
Expect(podIP).NotTo(BeEmpty()) // use podIP as proxy for readiness
|
||||
|
||||
By("Verify pod1 still deleted")
|
||||
assertUnstructuredDoesNotExist(ctx, c, pod1Obj)
|
||||
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, pod1Obj)
|
||||
|
||||
By("Verify inventory")
|
||||
// The inventory should only have the currently applied item.
|
||||
|
|
@ -297,7 +299,7 @@ func pruneRetrieveErrorTest(ctx context.Context, c client.Client, invConfig Inve
|
|||
destroyer := invConfig.DestroyerFactoryFunc()
|
||||
|
||||
options := apply.DestroyerOptions{InventoryPolicy: inventory.PolicyAdoptIfNoInventory}
|
||||
destroyerEvents := runCollect(destroyer.Run(ctx, inv, options))
|
||||
destroyerEvents := e2eutil.RunCollect(destroyer.Run(ctx, inv, options))
|
||||
|
||||
expEvents3 := []testutil.ExpEvent{
|
||||
{
|
||||
|
|
@ -391,8 +393,8 @@ func pruneRetrieveErrorTest(ctx context.Context, c client.Client, invConfig Inve
|
|||
Expect(testutil.EventsToExpEvents(destroyerEvents)).To(testutil.Equal(expEvents3))
|
||||
|
||||
By("Verify pod1 is deleted")
|
||||
assertUnstructuredDoesNotExist(ctx, c, pod1Obj)
|
||||
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, pod1Obj)
|
||||
|
||||
By("Verify pod2 is deleted")
|
||||
assertUnstructuredDoesNotExist(ctx, c, pod2Obj)
|
||||
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, pod2Obj)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,21 +15,23 @@ import (
|
|||
"sigs.k8s.io/cli-utils/pkg/apply/event"
|
||||
"sigs.k8s.io/cli-utils/pkg/object"
|
||||
"sigs.k8s.io/cli-utils/pkg/testutil"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/e2eutil"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/invconfig"
|
||||
)
|
||||
|
||||
func reconciliationFailed(ctx context.Context, invConfig InventoryConfig, inventoryName, namespaceName string) {
|
||||
func reconciliationFailed(ctx context.Context, invConfig invconfig.InventoryConfig, inventoryName, namespaceName string) {
|
||||
By("Apply resources")
|
||||
applier := invConfig.ApplierFactoryFunc()
|
||||
inventoryID := fmt.Sprintf("%s-%s", inventoryName, namespaceName)
|
||||
|
||||
inventoryInfo := createInventoryInfo(invConfig, inventoryName, namespaceName, inventoryID)
|
||||
inventoryInfo := invconfig.CreateInventoryInfo(invConfig, inventoryName, namespaceName, inventoryID)
|
||||
|
||||
podObj := withNodeSelector(withNamespace(manifestToUnstructured(pod1), namespaceName), "foo", "bar")
|
||||
podObj := e2eutil.WithNodeSelector(e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod1), namespaceName), "foo", "bar")
|
||||
resources := []*unstructured.Unstructured{
|
||||
podObj,
|
||||
}
|
||||
|
||||
applierEvents := runCollect(applier.Run(ctx, inventoryInfo, resources, apply.ApplierOptions{
|
||||
applierEvents := e2eutil.RunCollect(applier.Run(ctx, inventoryInfo, resources, apply.ApplierOptions{
|
||||
ReconcileTimeout: 2 * time.Minute,
|
||||
EmitStatusEvents: false,
|
||||
}))
|
||||
|
|
@ -40,19 +42,19 @@ func reconciliationFailed(ctx context.Context, invConfig InventoryConfig, invent
|
|||
Expect(received).To(testutil.Equal(expEvents))
|
||||
}
|
||||
|
||||
func reconciliationTimeout(ctx context.Context, invConfig InventoryConfig, inventoryName, namespaceName string) {
|
||||
func reconciliationTimeout(ctx context.Context, invConfig invconfig.InventoryConfig, inventoryName, namespaceName string) {
|
||||
By("Apply resources")
|
||||
applier := invConfig.ApplierFactoryFunc()
|
||||
inventoryID := fmt.Sprintf("%s-%s", inventoryName, namespaceName)
|
||||
|
||||
inventoryInfo := createInventoryInfo(invConfig, inventoryName, namespaceName, inventoryID)
|
||||
inventoryInfo := invconfig.CreateInventoryInfo(invConfig, inventoryName, namespaceName, inventoryID)
|
||||
|
||||
podObj := podWithImage(withNamespace(manifestToUnstructured(pod1), namespaceName), "kubernetes-pause", "does-not-exist")
|
||||
podObj := e2eutil.PodWithImage(e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod1), namespaceName), "kubernetes-pause", "does-not-exist")
|
||||
resources := []*unstructured.Unstructured{
|
||||
podObj,
|
||||
}
|
||||
|
||||
applierEvents := runCollect(applier.Run(ctx, inventoryInfo, resources, apply.ApplierOptions{
|
||||
applierEvents := e2eutil.RunCollect(applier.Run(ctx, inventoryInfo, resources, apply.ApplierOptions{
|
||||
ReconcileTimeout: 30 * time.Second,
|
||||
EmitStatusEvents: false,
|
||||
}))
|
||||
|
|
|
|||
|
|
@ -14,20 +14,22 @@ import (
|
|||
"sigs.k8s.io/cli-utils/pkg/apply"
|
||||
"sigs.k8s.io/cli-utils/pkg/common"
|
||||
"sigs.k8s.io/cli-utils/pkg/object"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/e2eutil"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/invconfig"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
func serversideApplyTest(ctx context.Context, c client.Client, invConfig InventoryConfig, inventoryName, namespaceName string) {
|
||||
func serversideApplyTest(ctx context.Context, c client.Client, invConfig invconfig.InventoryConfig, inventoryName, namespaceName string) {
|
||||
By("Apply a Deployment and an APIService by server-side apply")
|
||||
applier := invConfig.ApplierFactoryFunc()
|
||||
|
||||
inv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(inventoryName, namespaceName, "test"))
|
||||
firstResources := []*unstructured.Unstructured{
|
||||
withNamespace(manifestToUnstructured(deployment1), namespaceName),
|
||||
manifestToUnstructured(apiservice1),
|
||||
e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(deployment1), namespaceName),
|
||||
e2eutil.ManifestToUnstructured(apiservice1),
|
||||
}
|
||||
|
||||
runWithNoErr(applier.Run(ctx, inv, firstResources, apply.ApplierOptions{
|
||||
e2eutil.RunWithNoErr(applier.Run(ctx, inv, firstResources, apply.ApplierOptions{
|
||||
ReconcileTimeout: 2 * time.Minute,
|
||||
EmitStatusEvents: true,
|
||||
ServerSideOptions: common.ServerSideOptions{
|
||||
|
|
@ -38,7 +40,7 @@ func serversideApplyTest(ctx context.Context, c client.Client, invConfig Invento
|
|||
}))
|
||||
|
||||
By("Verify deployment is server-side applied")
|
||||
result := assertUnstructuredExists(ctx, c, withNamespace(manifestToUnstructured(deployment1), namespaceName))
|
||||
result := e2eutil.AssertUnstructuredExists(ctx, c, e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(deployment1), namespaceName))
|
||||
|
||||
// LastAppliedConfigAnnotation annotation is only set for client-side apply and we've server-side applied here.
|
||||
_, found, err := object.NestedField(result.Object, "metadata", "annotations", v1.LastAppliedConfigAnnotation)
|
||||
|
|
@ -51,7 +53,7 @@ func serversideApplyTest(ctx context.Context, c client.Client, invConfig Invento
|
|||
Expect(manager).To(Equal("test"))
|
||||
|
||||
By("Verify APIService is server-side applied")
|
||||
result = assertUnstructuredExists(ctx, c, manifestToUnstructured(apiservice1))
|
||||
result = e2eutil.AssertUnstructuredExists(ctx, c, e2eutil.ManifestToUnstructured(apiservice1))
|
||||
|
||||
// LastAppliedConfigAnnotation annotation is only set for client-side apply and we've server-side applied here.
|
||||
_, found, err = object.NestedField(result.Object, "metadata", "annotations", v1.LastAppliedConfigAnnotation)
|
||||
|
|
|
|||
|
|
@ -21,10 +21,12 @@ import (
|
|||
"sigs.k8s.io/cli-utils/pkg/object/mutation"
|
||||
"sigs.k8s.io/cli-utils/pkg/object/validation"
|
||||
"sigs.k8s.io/cli-utils/pkg/testutil"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/e2eutil"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/invconfig"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
func skipInvalidTest(ctx context.Context, c client.Client, invConfig InventoryConfig, inventoryName, namespaceName string) {
|
||||
func skipInvalidTest(ctx context.Context, c client.Client, invConfig invconfig.InventoryConfig, inventoryName, namespaceName string) {
|
||||
By("apply valid objects and skip invalid objects")
|
||||
applier := invConfig.ApplierFactoryFunc()
|
||||
|
||||
|
|
@ -32,19 +34,19 @@ func skipInvalidTest(ctx context.Context, c client.Client, invConfig InventoryCo
|
|||
|
||||
fields := struct{ Namespace string }{Namespace: namespaceName}
|
||||
// valid pod
|
||||
pod1Obj := withNamespace(manifestToUnstructured(pod1), namespaceName)
|
||||
pod1Obj := e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod1), namespaceName)
|
||||
// valid deployment with dependency
|
||||
deployment1Obj := withDependsOn(withNamespace(manifestToUnstructured(deployment1), namespaceName),
|
||||
deployment1Obj := e2eutil.WithDependsOn(e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(deployment1), namespaceName),
|
||||
fmt.Sprintf("/namespaces/%s/Pod/%s", namespaceName, pod1Obj.GetName()))
|
||||
// external/missing dependency
|
||||
pod3Obj := withDependsOn(withNamespace(manifestToUnstructured(pod3), namespaceName),
|
||||
pod3Obj := e2eutil.WithDependsOn(e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod3), namespaceName),
|
||||
fmt.Sprintf("/namespaces/%s/Pod/pod0", namespaceName))
|
||||
// cyclic dependency (podB)
|
||||
podAObj := templateToUnstructured(podATemplate, fields)
|
||||
podAObj := e2eutil.TemplateToUnstructured(podATemplate, fields)
|
||||
// cyclic dependency (podA) & invalid source reference (dependency not in object set)
|
||||
podBObj := templateToUnstructured(invalidMutationPodBTemplate, fields)
|
||||
podBObj := e2eutil.TemplateToUnstructured(invalidMutationPodBTemplate, fields)
|
||||
// missing name
|
||||
invalidPodObj := templateToUnstructured(invalidPodTemplate, fields)
|
||||
invalidPodObj := e2eutil.TemplateToUnstructured(invalidPodTemplate, fields)
|
||||
|
||||
resources := []*unstructured.Unstructured{
|
||||
pod1Obj,
|
||||
|
|
@ -55,7 +57,7 @@ func skipInvalidTest(ctx context.Context, c client.Client, invConfig InventoryCo
|
|||
invalidPodObj,
|
||||
}
|
||||
|
||||
applierEvents := runCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
||||
applierEvents := e2eutil.RunCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
||||
EmitStatusEvents: false,
|
||||
ValidationPolicy: validation.SkipInvalid,
|
||||
}))
|
||||
|
|
@ -320,31 +322,31 @@ func skipInvalidTest(ctx context.Context, c client.Client, invConfig InventoryCo
|
|||
Expect(testutil.EventsToExpEvents(applierEvents)).To(testutil.Equal(expEvents))
|
||||
|
||||
By("verify pod1 created and ready")
|
||||
result := assertUnstructuredExists(ctx, c, pod1Obj)
|
||||
result := e2eutil.AssertUnstructuredExists(ctx, c, pod1Obj)
|
||||
podIP, found, err := object.NestedField(result.Object, "status", "podIP")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(found).To(BeTrue())
|
||||
Expect(podIP).NotTo(BeEmpty()) // use podIP as proxy for readiness
|
||||
|
||||
By("verify deployment1 created and ready")
|
||||
result = assertUnstructuredExists(ctx, c, deployment1Obj)
|
||||
assertUnstructuredAvailable(result)
|
||||
result = e2eutil.AssertUnstructuredExists(ctx, c, deployment1Obj)
|
||||
e2eutil.AssertUnstructuredAvailable(result)
|
||||
|
||||
By("verify pod3 not found")
|
||||
assertUnstructuredDoesNotExist(ctx, c, pod3Obj)
|
||||
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, pod3Obj)
|
||||
|
||||
By("verify podA not found")
|
||||
assertUnstructuredDoesNotExist(ctx, c, podAObj)
|
||||
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, podAObj)
|
||||
|
||||
By("verify podB not found")
|
||||
assertUnstructuredDoesNotExist(ctx, c, podBObj)
|
||||
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, podBObj)
|
||||
|
||||
By("modify deployment1 depends-on annotation to be invalid")
|
||||
applyUnstructured(ctx, c, withDependsOn(deployment1Obj, "invalid"))
|
||||
e2eutil.ApplyUnstructured(ctx, c, e2eutil.WithDependsOn(deployment1Obj, "invalid"))
|
||||
|
||||
By("destroy valid objects and skip invalid objects")
|
||||
destroyer := invConfig.DestroyerFactoryFunc()
|
||||
destroyerEvents := runCollect(destroyer.Run(ctx, inv, apply.DestroyerOptions{
|
||||
destroyerEvents := e2eutil.RunCollect(destroyer.Run(ctx, inv, apply.DestroyerOptions{
|
||||
InventoryPolicy: inventory.PolicyAdoptIfNoInventory,
|
||||
ValidationPolicy: validation.SkipInvalid,
|
||||
}))
|
||||
|
|
@ -453,18 +455,18 @@ func skipInvalidTest(ctx context.Context, c client.Client, invConfig InventoryCo
|
|||
Expect(testutil.EventsToExpEvents(destroyerEvents)).To(testutil.Equal(expEvents))
|
||||
|
||||
By("verify pod1 deleted")
|
||||
assertUnstructuredDoesNotExist(ctx, c, pod1Obj)
|
||||
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, pod1Obj)
|
||||
|
||||
By("verify deployment1 not deleted")
|
||||
assertUnstructuredExists(ctx, c, deployment1Obj)
|
||||
deleteUnstructuredIfExists(ctx, c, deployment1Obj)
|
||||
e2eutil.AssertUnstructuredExists(ctx, c, deployment1Obj)
|
||||
e2eutil.DeleteUnstructuredIfExists(ctx, c, deployment1Obj)
|
||||
|
||||
By("verify pod3 not found")
|
||||
assertUnstructuredDoesNotExist(ctx, c, pod3Obj)
|
||||
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, pod3Obj)
|
||||
|
||||
By("verify podA not found")
|
||||
assertUnstructuredDoesNotExist(ctx, c, podAObj)
|
||||
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, podAObj)
|
||||
|
||||
By("verify podB not found")
|
||||
assertUnstructuredDoesNotExist(ctx, c, podBObj)
|
||||
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, podBObj)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,67 @@
|
|||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package stress
|
||||
|
||||
var namespaceYaml = `
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: ""
|
||||
`
|
||||
|
||||
var configMapYaml = `
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: ""
|
||||
namespace: ""
|
||||
data: {}
|
||||
`
|
||||
|
||||
var cronTabCRDYaml = `
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: crontabs.stable.example.com
|
||||
spec:
|
||||
group: stable.example.com
|
||||
versions:
|
||||
- name: v1
|
||||
served: true
|
||||
storage: true
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
type: object
|
||||
properties:
|
||||
apiVersion:
|
||||
type: string
|
||||
kind:
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
type: object
|
||||
properties:
|
||||
cronSpec:
|
||||
type: string
|
||||
image:
|
||||
type: string
|
||||
scope: Namespaced
|
||||
names:
|
||||
plural: crontabs
|
||||
singular: crontab
|
||||
kind: CronTab
|
||||
shortNames:
|
||||
- ct
|
||||
`
|
||||
|
||||
var cronTabYaml = `
|
||||
apiVersion: stable.example.com/v1
|
||||
kind: CronTab
|
||||
metadata:
|
||||
name: ""
|
||||
namespace: ""
|
||||
spec:
|
||||
cronSpec: "* * * * */5"
|
||||
`
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package stress
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func TestE2e(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "Stress Test Suite")
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package stress
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/onsi/gomega/format"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/klog/v2"
|
||||
"k8s.io/kubectl/pkg/scheme"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/e2eutil"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/invconfig"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
|
||||
)
|
||||
|
||||
// Parse optional logging flags
|
||||
// Ex: ginkgo ./test/e2e/... -- -v=5
|
||||
// Allow init for e2e test (not imported by external code)
|
||||
// nolint:gochecknoinits
|
||||
func init() {
|
||||
klog.InitFlags(nil)
|
||||
klog.SetOutput(GinkgoWriter)
|
||||
}
|
||||
|
||||
var defaultTestTimeout = 1 * time.Hour
|
||||
var defaultBeforeTestTimeout = 30 * time.Second
|
||||
var defaultAfterTestTimeout = 30 * time.Second
|
||||
|
||||
var _ = Describe("Applier", func() {
|
||||
|
||||
var c client.Client
|
||||
var invConfig invconfig.InventoryConfig
|
||||
|
||||
BeforeSuite(func() {
|
||||
// increase from 4000 to handle long event lists
|
||||
format.MaxLength = 10000
|
||||
|
||||
cfg, err := ctrl.GetConfig()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
// increase QPS from 5 to 20
|
||||
cfg.QPS = 20
|
||||
// increase Burst QPS from 10 to 40
|
||||
cfg.Burst = 40
|
||||
|
||||
invConfig = invconfig.NewCustomTypeInvConfig(cfg)
|
||||
|
||||
mapper, err := apiutil.NewDynamicRESTMapper(cfg)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
c, err = client.New(cfg, client.Options{
|
||||
Scheme: scheme.Scheme,
|
||||
Mapper: mapper,
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultBeforeTestTimeout)
|
||||
defer cancel()
|
||||
e2eutil.CreateInventoryCRD(ctx, c)
|
||||
Expect(ctx.Err()).To(BeNil(), "BeforeSuite context cancelled or timed out")
|
||||
})
|
||||
|
||||
AfterSuite(func() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultAfterTestTimeout)
|
||||
defer cancel()
|
||||
e2eutil.DeleteInventoryCRD(ctx, c)
|
||||
Expect(ctx.Err()).To(BeNil(), "AfterSuite context cancelled or timed out")
|
||||
})
|
||||
|
||||
Context("StressTest", func() {
|
||||
var namespace *v1.Namespace
|
||||
var inventoryName string
|
||||
var ctx context.Context
|
||||
var cancel context.CancelFunc
|
||||
|
||||
BeforeEach(func() {
|
||||
ctx, cancel = context.WithTimeout(context.Background(), defaultTestTimeout)
|
||||
inventoryName = e2eutil.RandomString("test-inv-")
|
||||
namespace = e2eutil.CreateRandomNamespace(ctx, c)
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
Expect(ctx.Err()).To(BeNil(), "test context cancelled or timed out")
|
||||
cancel()
|
||||
ctx, cancel = context.WithTimeout(context.Background(), defaultAfterTestTimeout)
|
||||
defer cancel()
|
||||
// clean up resources created by the tests
|
||||
e2eutil.DeleteNamespace(ctx, c, namespace)
|
||||
})
|
||||
|
||||
It("Thousand Namespaces", func() {
|
||||
thousandNamespacesTest(ctx, c, invConfig, inventoryName, namespace.GetName())
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
// Copyright 2020 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package stress
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/klog/v2"
|
||||
"sigs.k8s.io/cli-utils/pkg/apply"
|
||||
"sigs.k8s.io/cli-utils/pkg/apply/event"
|
||||
"sigs.k8s.io/cli-utils/pkg/common"
|
||||
"sigs.k8s.io/cli-utils/pkg/inventory"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/e2eutil"
|
||||
"sigs.k8s.io/cli-utils/test/e2e/invconfig"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
func thousandNamespacesTest(ctx context.Context, c client.Client, invConfig invconfig.InventoryConfig, inventoryName, namespaceName string) {
|
||||
By("Apply LOTS of resources")
|
||||
applier := invConfig.ApplierFactoryFunc()
|
||||
inventoryID := fmt.Sprintf("%s-%s", inventoryName, namespaceName)
|
||||
|
||||
inventoryInfo := invconfig.CreateInventoryInfo(invConfig, inventoryName, namespaceName, inventoryID)
|
||||
|
||||
crdObj := e2eutil.ManifestToUnstructured([]byte(cronTabCRDYaml))
|
||||
|
||||
resources := []*unstructured.Unstructured{crdObj}
|
||||
|
||||
labelKey := "created-for"
|
||||
labelValue := "stress-test"
|
||||
|
||||
namespaceObjTemplate := e2eutil.ManifestToUnstructured([]byte(namespaceYaml))
|
||||
namespaceObjTemplate.SetLabels(map[string]string{labelKey: labelValue})
|
||||
|
||||
configMapObjTemplate := e2eutil.ManifestToUnstructured([]byte(configMapYaml))
|
||||
configMapObjTemplate.SetLabels(map[string]string{labelKey: labelValue})
|
||||
|
||||
cronTabObjTemplate := e2eutil.ManifestToUnstructured([]byte(cronTabYaml))
|
||||
cronTabObjTemplate.SetLabels(map[string]string{labelKey: labelValue})
|
||||
|
||||
for i := 1; i <= 1000; i++ {
|
||||
ns := fmt.Sprintf("%s-%d", namespaceName, i)
|
||||
namespaceObj := namespaceObjTemplate.DeepCopy()
|
||||
namespaceObj.SetName(ns)
|
||||
resources = append(resources, namespaceObj)
|
||||
|
||||
configMapObj := configMapObjTemplate.DeepCopy()
|
||||
configMapObj.SetName(fmt.Sprintf("configmap-%d", i))
|
||||
configMapObj.SetNamespace(ns)
|
||||
resources = append(resources, configMapObj)
|
||||
|
||||
cronTabObj := cronTabObjTemplate.DeepCopy()
|
||||
cronTabObj.SetName(fmt.Sprintf("crontab-%d", i))
|
||||
cronTabObj.SetNamespace(ns)
|
||||
resources = append(resources, cronTabObj)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
// Can't delete custom resources if the CRD is still terminating
|
||||
if e2eutil.UnstructuredExistsAndIsNotTerminating(ctx, c, crdObj) {
|
||||
By("Cleanup CronTabs")
|
||||
e2eutil.DeleteAllUnstructuredIfExists(ctx, c, cronTabObjTemplate)
|
||||
By("Cleanup CRD")
|
||||
e2eutil.DeleteUnstructuredIfExists(ctx, c, crdObj)
|
||||
}
|
||||
|
||||
By("Cleanup ConfigMaps")
|
||||
e2eutil.DeleteAllUnstructuredIfExists(ctx, c, configMapObjTemplate)
|
||||
By("Cleanup Namespaces")
|
||||
e2eutil.DeleteAllUnstructuredIfExists(ctx, c, namespaceObjTemplate)
|
||||
}()
|
||||
|
||||
start := time.Now()
|
||||
|
||||
applierEvents := e2eutil.RunCollect(applier.Run(ctx, inventoryInfo, resources, apply.ApplierOptions{
|
||||
// SSA reduces GET+PATCH to just PATCH, which is faster
|
||||
ServerSideOptions: common.ServerSideOptions{
|
||||
ServerSideApply: true,
|
||||
ForceConflicts: true,
|
||||
FieldManager: "cli-utils.kubernetes.io",
|
||||
},
|
||||
ReconcileTimeout: 30 * time.Minute,
|
||||
EmitStatusEvents: false,
|
||||
}))
|
||||
|
||||
duration := time.Since(start)
|
||||
klog.Infof("Applier.Run execution time: %v", duration)
|
||||
|
||||
for _, e := range applierEvents {
|
||||
Expect(e.ErrorEvent.Err).To(BeNil())
|
||||
}
|
||||
for _, e := range applierEvents {
|
||||
Expect(e.ApplyEvent.Error).To(BeNil(), "ApplyEvent: %v", e.ApplyEvent)
|
||||
}
|
||||
for _, e := range applierEvents {
|
||||
if e.Type == event.WaitType {
|
||||
Expect(e.WaitEvent.Operation).To(BeElementOf(event.ReconcilePending, event.Reconciled), "WaitEvent: %v", e.WaitEvent)
|
||||
}
|
||||
}
|
||||
|
||||
By("Verify inventory created")
|
||||
invConfig.InvSizeVerifyFunc(ctx, c, inventoryName, namespaceName, inventoryID, len(resources), len(resources))
|
||||
|
||||
By("Verify CRD created")
|
||||
e2eutil.AssertUnstructuredExists(ctx, c, crdObj)
|
||||
|
||||
By("Verify 1000 Namespaces created")
|
||||
e2eutil.AssertUnstructuredCount(ctx, c, namespaceObjTemplate, 1000)
|
||||
|
||||
By("Verify 1000 ConfigMaps created")
|
||||
e2eutil.AssertUnstructuredCount(ctx, c, configMapObjTemplate, 1000)
|
||||
|
||||
By("Verify 1000 CronTabs created")
|
||||
e2eutil.AssertUnstructuredCount(ctx, c, cronTabObjTemplate, 1000)
|
||||
|
||||
By("Destroy LOTS of resources")
|
||||
destroyer := invConfig.DestroyerFactoryFunc()
|
||||
|
||||
start = time.Now()
|
||||
|
||||
destroyerEvents := e2eutil.RunCollect(destroyer.Run(ctx, inventoryInfo, apply.DestroyerOptions{
|
||||
InventoryPolicy: inventory.PolicyAdoptIfNoInventory,
|
||||
DeleteTimeout: 30 * time.Minute,
|
||||
}))
|
||||
|
||||
duration = time.Since(start)
|
||||
klog.Infof("Destroyer.Run execution time: %v", duration)
|
||||
|
||||
for _, e := range destroyerEvents {
|
||||
Expect(e.ErrorEvent.Err).To(BeNil())
|
||||
}
|
||||
for _, e := range destroyerEvents {
|
||||
Expect(e.PruneEvent.Error).To(BeNil(), "PruneEvent: %v", e.PruneEvent)
|
||||
}
|
||||
for _, e := range destroyerEvents {
|
||||
if e.Type == event.WaitType {
|
||||
Expect(e.WaitEvent.Operation).To(BeElementOf(event.ReconcilePending, event.Reconciled), "WaitEvent: %v", e.WaitEvent)
|
||||
}
|
||||
}
|
||||
|
||||
By("Verify inventory deleted")
|
||||
invConfig.InvNotExistsFunc(ctx, c, inventoryName, namespaceName, inventoryID)
|
||||
|
||||
By("Verify 1000 CronTabs deleted")
|
||||
e2eutil.AssertUnstructuredCount(ctx, c, cronTabObjTemplate, 0)
|
||||
|
||||
By("Verify 1000 ConfigMaps deleted")
|
||||
e2eutil.AssertUnstructuredCount(ctx, c, configMapObjTemplate, 0)
|
||||
|
||||
By("Verify 1000 Namespaces deleted")
|
||||
e2eutil.AssertUnstructuredCount(ctx, c, namespaceObjTemplate, 0)
|
||||
|
||||
By("Verify CRD deleted")
|
||||
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, crdObj)
|
||||
}
|
||||
Loading…
Reference in New Issue