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
|
kind delete cluster --name=cli-utils-e2e && kind create cluster --name=cli-utils-e2e
|
||||||
$(GOPATH)/bin/ginkgo ./test/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:
|
vet:
|
||||||
go vet ./...
|
go vet ./...
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,22 +17,24 @@ import (
|
||||||
"sigs.k8s.io/cli-utils/pkg/kstatus/status"
|
"sigs.k8s.io/cli-utils/pkg/kstatus/status"
|
||||||
"sigs.k8s.io/cli-utils/pkg/object"
|
"sigs.k8s.io/cli-utils/pkg/object"
|
||||||
"sigs.k8s.io/cli-utils/pkg/testutil"
|
"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"
|
"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")
|
By("Apply resources")
|
||||||
applier := invConfig.ApplierFactoryFunc()
|
applier := invConfig.ApplierFactoryFunc()
|
||||||
inventoryID := fmt.Sprintf("%s-%s", inventoryName, namespaceName)
|
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{
|
resources := []*unstructured.Unstructured{
|
||||||
deployment1Obj,
|
deployment1Obj,
|
||||||
}
|
}
|
||||||
|
|
||||||
applierEvents := runCollect(applier.Run(ctx, inventoryInfo, resources, apply.ApplierOptions{
|
applierEvents := e2eutil.RunCollect(applier.Run(ctx, inventoryInfo, resources, apply.ApplierOptions{
|
||||||
ReconcileTimeout: 2 * time.Minute,
|
ReconcileTimeout: 2 * time.Minute,
|
||||||
EmitStatusEvents: true,
|
EmitStatusEvents: true,
|
||||||
}))
|
}))
|
||||||
|
|
@ -184,7 +186,7 @@ func applyAndDestroyTest(ctx context.Context, c client.Client, invConfig Invento
|
||||||
Expect(received).To(testutil.Equal(expEvents))
|
Expect(received).To(testutil.Equal(expEvents))
|
||||||
|
|
||||||
By("Verify deployment created")
|
By("Verify deployment created")
|
||||||
assertUnstructuredExists(ctx, c, deployment1Obj)
|
e2eutil.AssertUnstructuredExists(ctx, c, deployment1Obj)
|
||||||
|
|
||||||
By("Verify inventory")
|
By("Verify inventory")
|
||||||
invConfig.InvSizeVerifyFunc(ctx, c, inventoryName, namespaceName, inventoryID, 1, 1)
|
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()
|
destroyer := invConfig.DestroyerFactoryFunc()
|
||||||
|
|
||||||
options := apply.DestroyerOptions{InventoryPolicy: inventory.PolicyAdoptIfNoInventory}
|
options := apply.DestroyerOptions{InventoryPolicy: inventory.PolicyAdoptIfNoInventory}
|
||||||
destroyerEvents := runCollect(destroyer.Run(ctx, inventoryInfo, options))
|
destroyerEvents := e2eutil.RunCollect(destroyer.Run(ctx, inventoryInfo, options))
|
||||||
|
|
||||||
expEvents = []testutil.ExpEvent{
|
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))
|
Expect(testutil.EventsToExpEvents(destroyerEvents)).To(testutil.Equal(expEvents))
|
||||||
|
|
||||||
By("Verify deployment deleted")
|
By("Verify deployment deleted")
|
||||||
assertUnstructuredDoesNotExist(ctx, c, deployment1Obj)
|
e2eutil.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))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,23 +16,25 @@ import (
|
||||||
"sigs.k8s.io/cli-utils/pkg/apply/event"
|
"sigs.k8s.io/cli-utils/pkg/apply/event"
|
||||||
"sigs.k8s.io/cli-utils/pkg/object"
|
"sigs.k8s.io/cli-utils/pkg/object"
|
||||||
"sigs.k8s.io/cli-utils/pkg/testutil"
|
"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"
|
"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")
|
By("apply an invalid CRD")
|
||||||
applier := invConfig.ApplierFactoryFunc()
|
applier := invConfig.ApplierFactoryFunc()
|
||||||
|
|
||||||
inv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(inventoryName, namespaceName, "test"))
|
inv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(inventoryName, namespaceName, "test"))
|
||||||
|
|
||||||
invalidCrdObj := manifestToUnstructured(invalidCrd)
|
invalidCrdObj := e2eutil.ManifestToUnstructured(invalidCrd)
|
||||||
pod1Obj := withNamespace(manifestToUnstructured(pod1), namespaceName)
|
pod1Obj := e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod1), namespaceName)
|
||||||
resources := []*unstructured.Unstructured{
|
resources := []*unstructured.Unstructured{
|
||||||
invalidCrdObj,
|
invalidCrdObj,
|
||||||
pod1Obj,
|
pod1Obj,
|
||||||
}
|
}
|
||||||
|
|
||||||
applierEvents := runCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{}))
|
applierEvents := e2eutil.RunCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{}))
|
||||||
|
|
||||||
expEvents := []testutil.ExpEvent{
|
expEvents := []testutil.ExpEvent{
|
||||||
{
|
{
|
||||||
|
|
@ -167,8 +169,8 @@ func continueOnErrorTest(ctx context.Context, c client.Client, invConfig Invento
|
||||||
Expect(receivedEvents).To(testutil.Equal(expEvents))
|
Expect(receivedEvents).To(testutil.Equal(expEvents))
|
||||||
|
|
||||||
By("Verify pod1 created")
|
By("Verify pod1 created")
|
||||||
assertUnstructuredExists(ctx, c, pod1Obj)
|
e2eutil.AssertUnstructuredExists(ctx, c, pod1Obj)
|
||||||
|
|
||||||
By("Verify CRD not created")
|
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/inventory"
|
||||||
"sigs.k8s.io/cli-utils/pkg/object"
|
"sigs.k8s.io/cli-utils/pkg/object"
|
||||||
"sigs.k8s.io/cli-utils/pkg/testutil"
|
"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"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
//nolint:dupl // expEvents similar to mutation tests
|
//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")
|
By("apply a set of resources that includes both a crd and a cr")
|
||||||
applier := invConfig.ApplierFactoryFunc()
|
applier := invConfig.ApplierFactoryFunc()
|
||||||
|
|
||||||
inv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(inventoryName, namespaceName, "test"))
|
inv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(inventoryName, namespaceName, "test"))
|
||||||
|
|
||||||
crdObj := manifestToUnstructured(crd)
|
crdObj := e2eutil.ManifestToUnstructured(crd)
|
||||||
crObj := manifestToUnstructured(cr)
|
crObj := e2eutil.ManifestToUnstructured(cr)
|
||||||
|
|
||||||
resources := []*unstructured.Unstructured{
|
resources := []*unstructured.Unstructured{
|
||||||
crObj,
|
crObj,
|
||||||
crdObj,
|
crdObj,
|
||||||
}
|
}
|
||||||
|
|
||||||
applierEvents := runCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
applierEvents := e2eutil.RunCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
||||||
ReconcileTimeout: 2 * time.Minute,
|
ReconcileTimeout: 2 * time.Minute,
|
||||||
EmitStatusEvents: false,
|
EmitStatusEvents: false,
|
||||||
}))
|
}))
|
||||||
|
|
@ -215,7 +217,7 @@ func crdTest(ctx context.Context, _ client.Client, invConfig InventoryConfig, in
|
||||||
By("destroy the resources, including the crd")
|
By("destroy the resources, including the crd")
|
||||||
destroyer := invConfig.DestroyerFactoryFunc()
|
destroyer := invConfig.DestroyerFactoryFunc()
|
||||||
options := apply.DestroyerOptions{InventoryPolicy: inventory.PolicyAdoptIfNoInventory}
|
options := apply.DestroyerOptions{InventoryPolicy: inventory.PolicyAdoptIfNoInventory}
|
||||||
destroyerEvents := runCollect(destroyer.Run(ctx, inv, options))
|
destroyerEvents := e2eutil.RunCollect(destroyer.Run(ctx, inv, options))
|
||||||
|
|
||||||
expEvents = []testutil.ExpEvent{
|
expEvents = []testutil.ExpEvent{
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -36,12 +36,6 @@ spec:
|
||||||
openAPIV3Schema:
|
openAPIV3Schema:
|
||||||
description: Example for cli-utils e2e tests
|
description: Example for cli-utils e2e tests
|
||||||
properties:
|
properties:
|
||||||
apiVersion:
|
|
||||||
type: string
|
|
||||||
kind:
|
|
||||||
type: string
|
|
||||||
metadata:
|
|
||||||
type: object
|
|
||||||
spec:
|
spec:
|
||||||
properties:
|
properties:
|
||||||
objects:
|
objects:
|
||||||
|
|
|
||||||
|
|
@ -14,36 +14,38 @@ import (
|
||||||
"sigs.k8s.io/cli-utils/pkg/apply"
|
"sigs.k8s.io/cli-utils/pkg/apply"
|
||||||
"sigs.k8s.io/cli-utils/pkg/common"
|
"sigs.k8s.io/cli-utils/pkg/common"
|
||||||
"sigs.k8s.io/cli-utils/pkg/inventory"
|
"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"
|
"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")
|
By("Apply resources")
|
||||||
applier := invConfig.ApplierFactoryFunc()
|
applier := invConfig.ApplierFactoryFunc()
|
||||||
inventoryID := fmt.Sprintf("%s-%s", inventoryName, namespaceName)
|
inventoryID := fmt.Sprintf("%s-%s", inventoryName, namespaceName)
|
||||||
|
|
||||||
inventoryInfo := createInventoryInfo(invConfig, inventoryName, namespaceName, inventoryID)
|
inventoryInfo := invconfig.CreateInventoryInfo(invConfig, inventoryName, namespaceName, inventoryID)
|
||||||
|
|
||||||
resources := []*unstructured.Unstructured{
|
resources := []*unstructured.Unstructured{
|
||||||
withNamespace(manifestToUnstructured(deployment1), namespaceName),
|
e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(deployment1), namespaceName),
|
||||||
withAnnotation(withNamespace(manifestToUnstructured(pod1), namespaceName), common.OnRemoveAnnotation, common.OnRemoveKeep),
|
e2eutil.WithAnnotation(e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod1), namespaceName), common.OnRemoveAnnotation, common.OnRemoveKeep),
|
||||||
withAnnotation(withNamespace(manifestToUnstructured(pod2), namespaceName), common.LifecycleDeleteAnnotation, common.PreventDeletion),
|
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,
|
ReconcileTimeout: 2 * time.Minute,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
By("Verify deployment created")
|
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()))
|
Expect(obj.GetAnnotations()[inventory.OwningInventoryKey]).To(Equal(inventoryInfo.ID()))
|
||||||
|
|
||||||
By("Verify pod1 created")
|
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()))
|
Expect(obj.GetAnnotations()[inventory.OwningInventoryKey]).To(Equal(inventoryInfo.ID()))
|
||||||
|
|
||||||
By("Verify pod2 created")
|
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()))
|
Expect(obj.GetAnnotations()[inventory.OwningInventoryKey]).To(Equal(inventoryInfo.ID()))
|
||||||
|
|
||||||
By("Verify the inventory size is 3")
|
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")
|
By("Dry-run apply resources")
|
||||||
resources = []*unstructured.Unstructured{
|
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,
|
ReconcileTimeout: 2 * time.Minute,
|
||||||
DryRunStrategy: common.DryRunClient,
|
DryRunStrategy: common.DryRunClient,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
By("Verify deployment still exists and has the config.k8s.io/owning-inventory annotation")
|
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()))
|
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")
|
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()))
|
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")
|
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()))
|
Expect(obj.GetAnnotations()[inventory.OwningInventoryKey]).To(Equal(inventoryInfo.ID()))
|
||||||
|
|
||||||
By("Verify the inventory size is still 3")
|
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")
|
By("Apply resources")
|
||||||
resources = []*unstructured.Unstructured{
|
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,
|
ReconcileTimeout: 2 * time.Minute,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
By("Verify deployment still exists and has the config.k8s.io/owning-inventory annotation")
|
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()))
|
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")
|
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(""))
|
Expect(obj.GetAnnotations()[inventory.OwningInventoryKey]).To(Equal(""))
|
||||||
|
|
||||||
By("Verify pod2 still exits and does not have the config.k8s.io/owning-inventory annotation")
|
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(""))
|
Expect(obj.GetAnnotations()[inventory.OwningInventoryKey]).To(Equal(""))
|
||||||
|
|
||||||
By("Verify the inventory size is 1")
|
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"
|
||||||
"sigs.k8s.io/cli-utils/pkg/object/validation"
|
"sigs.k8s.io/cli-utils/pkg/object/validation"
|
||||||
"sigs.k8s.io/cli-utils/pkg/testutil"
|
"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"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
//nolint:dupl // expEvents similar to other tests
|
//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")
|
By("apply resources in order based on depends-on annotation")
|
||||||
applier := invConfig.ApplierFactoryFunc()
|
applier := invConfig.ApplierFactoryFunc()
|
||||||
|
|
||||||
inv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(inventoryName, namespaceName, "test"))
|
inv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(inventoryName, namespaceName, "test"))
|
||||||
|
|
||||||
pod1Obj := withDependsOn(withNamespace(manifestToUnstructured(pod1), namespaceName), fmt.Sprintf("/namespaces/%s/Pod/pod2", namespaceName))
|
pod1Obj := e2eutil.WithDependsOn(e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod1), namespaceName), fmt.Sprintf("/namespaces/%s/Pod/pod2", namespaceName))
|
||||||
pod2Obj := withNamespace(manifestToUnstructured(pod2), namespaceName)
|
pod2Obj := e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod2), namespaceName)
|
||||||
|
|
||||||
// Dependency order: pod1 -> pod2
|
// Dependency order: pod1 -> pod2
|
||||||
// Apply order: pod2, pod1
|
// Apply order: pod2, pod1
|
||||||
|
|
@ -37,11 +39,11 @@ func dependencyFilterTest(ctx context.Context, c client.Client, invConfig Invent
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
defer func(ctx context.Context, c client.Client) {
|
defer func(ctx context.Context, c client.Client) {
|
||||||
deleteUnstructuredIfExists(ctx, c, pod1Obj)
|
e2eutil.DeleteUnstructuredIfExists(ctx, c, pod1Obj)
|
||||||
deleteUnstructuredIfExists(ctx, c, pod2Obj)
|
e2eutil.DeleteUnstructuredIfExists(ctx, c, pod2Obj)
|
||||||
}(ctx, c)
|
}(ctx, c)
|
||||||
|
|
||||||
applierEvents := runCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
applierEvents := e2eutil.RunCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
||||||
EmitStatusEvents: false,
|
EmitStatusEvents: false,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|
@ -219,14 +221,14 @@ func dependencyFilterTest(ctx context.Context, c client.Client, invConfig Invent
|
||||||
Expect(testutil.EventsToExpEvents(applierEvents)).To(testutil.Equal(expEvents))
|
Expect(testutil.EventsToExpEvents(applierEvents)).To(testutil.Equal(expEvents))
|
||||||
|
|
||||||
By("verify pod1 created and ready")
|
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")
|
podIP, found, err := object.NestedField(result.Object, "status", "podIP")
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(found).To(BeTrue())
|
Expect(found).To(BeTrue())
|
||||||
Expect(podIP).NotTo(BeEmpty()) // use podIP as proxy for readiness
|
Expect(podIP).NotTo(BeEmpty()) // use podIP as proxy for readiness
|
||||||
|
|
||||||
By("verify pod2 created and ready")
|
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")
|
podIP, found, err = object.NestedField(result.Object, "status", "podIP")
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(found).To(BeTrue())
|
Expect(found).To(BeTrue())
|
||||||
|
|
@ -237,7 +239,7 @@ func dependencyFilterTest(ctx context.Context, c client.Client, invConfig Invent
|
||||||
pod1Obj,
|
pod1Obj,
|
||||||
}
|
}
|
||||||
|
|
||||||
applierEvents = runCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
applierEvents = e2eutil.RunCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
||||||
EmitStatusEvents: false,
|
EmitStatusEvents: false,
|
||||||
ValidationPolicy: validation.SkipInvalid,
|
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))
|
Expect(testutil.EventsToExpEvents(applierEvents)).To(testutil.Equal(expEvents))
|
||||||
|
|
||||||
By("verify pod1 not deleted")
|
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")
|
ts, found, err := object.NestedField(result.Object, "metadata", "deletionTimestamp")
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(found).To(BeFalse(), "deletionTimestamp found: ", ts)
|
Expect(found).To(BeFalse(), "deletionTimestamp found: ", ts)
|
||||||
|
|
||||||
By("verify pod2 not deleted")
|
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")
|
ts, found, err = object.NestedField(result.Object, "metadata", "deletionTimestamp")
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(found).To(BeFalse(), "deletionTimestamp found: ", ts)
|
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/inventory"
|
||||||
"sigs.k8s.io/cli-utils/pkg/object"
|
"sigs.k8s.io/cli-utils/pkg/object"
|
||||||
"sigs.k8s.io/cli-utils/pkg/testutil"
|
"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"
|
"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")
|
By("apply resources in order based on depends-on annotation")
|
||||||
applier := invConfig.ApplierFactoryFunc()
|
applier := invConfig.ApplierFactoryFunc()
|
||||||
|
|
||||||
inv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(inventoryName, namespaceName, "test"))
|
inv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(inventoryName, namespaceName, "test"))
|
||||||
|
|
||||||
pod1Obj := withDependsOn(withNamespace(manifestToUnstructured(pod1), namespaceName), fmt.Sprintf("/namespaces/%s/Pod/pod3", namespaceName))
|
pod1Obj := e2eutil.WithDependsOn(e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod1), namespaceName), fmt.Sprintf("/namespaces/%s/Pod/pod3", namespaceName))
|
||||||
pod2Obj := withNamespace(manifestToUnstructured(pod2), namespaceName)
|
pod2Obj := e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod2), namespaceName)
|
||||||
pod3Obj := withDependsOn(withNamespace(manifestToUnstructured(pod3), namespaceName), fmt.Sprintf("/namespaces/%s/Pod/pod2", namespaceName))
|
pod3Obj := e2eutil.WithDependsOn(e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod3), namespaceName), fmt.Sprintf("/namespaces/%s/Pod/pod2", namespaceName))
|
||||||
|
|
||||||
// Dependency order: pod1 -> pod3 -> pod2
|
// Dependency order: pod1 -> pod3 -> pod2
|
||||||
// Apply order: pod2, pod3, pod1
|
// Apply order: pod2, pod3, pod1
|
||||||
|
|
@ -36,7 +38,7 @@ func dependsOnTest(ctx context.Context, c client.Client, invConfig InventoryConf
|
||||||
pod3Obj,
|
pod3Obj,
|
||||||
}
|
}
|
||||||
|
|
||||||
applierEvents := runCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
applierEvents := e2eutil.RunCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
||||||
EmitStatusEvents: false,
|
EmitStatusEvents: false,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|
@ -278,21 +280,21 @@ func dependsOnTest(ctx context.Context, c client.Client, invConfig InventoryConf
|
||||||
Expect(testutil.EventsToExpEvents(applierEvents)).To(testutil.Equal(expEvents))
|
Expect(testutil.EventsToExpEvents(applierEvents)).To(testutil.Equal(expEvents))
|
||||||
|
|
||||||
By("verify pod1 created and ready")
|
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")
|
podIP, found, err := object.NestedField(result.Object, "status", "podIP")
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(found).To(BeTrue())
|
Expect(found).To(BeTrue())
|
||||||
Expect(podIP).NotTo(BeEmpty()) // use podIP as proxy for readiness
|
Expect(podIP).NotTo(BeEmpty()) // use podIP as proxy for readiness
|
||||||
|
|
||||||
By("verify pod2 created and ready")
|
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")
|
podIP, found, err = object.NestedField(result.Object, "status", "podIP")
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(found).To(BeTrue())
|
Expect(found).To(BeTrue())
|
||||||
Expect(podIP).NotTo(BeEmpty()) // use podIP as proxy for readiness
|
Expect(podIP).NotTo(BeEmpty()) // use podIP as proxy for readiness
|
||||||
|
|
||||||
By("verify pod3 created and ready")
|
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")
|
podIP, found, err = object.NestedField(result.Object, "status", "podIP")
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(found).To(BeTrue())
|
Expect(found).To(BeTrue())
|
||||||
|
|
@ -301,7 +303,7 @@ func dependsOnTest(ctx context.Context, c client.Client, invConfig InventoryConf
|
||||||
By("destroy resources in opposite order")
|
By("destroy resources in opposite order")
|
||||||
destroyer := invConfig.DestroyerFactoryFunc()
|
destroyer := invConfig.DestroyerFactoryFunc()
|
||||||
options := apply.DestroyerOptions{InventoryPolicy: inventory.PolicyAdoptIfNoInventory}
|
options := apply.DestroyerOptions{InventoryPolicy: inventory.PolicyAdoptIfNoInventory}
|
||||||
destroyerEvents := runCollect(destroyer.Run(ctx, inv, options))
|
destroyerEvents := e2eutil.RunCollect(destroyer.Run(ctx, inv, options))
|
||||||
|
|
||||||
expEvents = []testutil.ExpEvent{
|
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))
|
Expect(testutil.EventsToExpEvents(destroyerEvents)).To(testutil.Equal(expEvents))
|
||||||
|
|
||||||
By("verify pod1 deleted")
|
By("verify pod1 deleted")
|
||||||
assertUnstructuredDoesNotExist(ctx, c, pod1Obj)
|
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, pod1Obj)
|
||||||
|
|
||||||
By("verify pod2 deleted")
|
By("verify pod2 deleted")
|
||||||
assertUnstructuredDoesNotExist(ctx, c, pod2Obj)
|
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, pod2Obj)
|
||||||
|
|
||||||
By("verify pod3 deleted")
|
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/kstatus/status"
|
||||||
"sigs.k8s.io/cli-utils/pkg/object"
|
"sigs.k8s.io/cli-utils/pkg/object"
|
||||||
"sigs.k8s.io/cli-utils/pkg/testutil"
|
"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"
|
"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")
|
By("Apply with DryRun")
|
||||||
applier := invConfig.ApplierFactoryFunc()
|
applier := invConfig.ApplierFactoryFunc()
|
||||||
inventoryID := fmt.Sprintf("%s-%s", inventoryName, namespaceName)
|
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)
|
namespace1Name := fmt.Sprintf("%s-ns1", namespaceName)
|
||||||
|
|
||||||
fields := struct{ Namespace string }{Namespace: namespace1Name}
|
fields := struct{ Namespace string }{Namespace: namespace1Name}
|
||||||
namespace1Obj := templateToUnstructured(namespaceTemplate, fields)
|
namespace1Obj := e2eutil.TemplateToUnstructured(namespaceTemplate, fields)
|
||||||
podBObj := templateToUnstructured(podBTemplate, fields)
|
podBObj := e2eutil.TemplateToUnstructured(podBTemplate, fields)
|
||||||
|
|
||||||
// Dependency order: podB -> namespace1
|
// Dependency order: podB -> namespace1
|
||||||
// Apply order: namespace1, podB
|
// Apply order: namespace1, podB
|
||||||
|
|
@ -41,7 +43,7 @@ func dryRunTest(ctx context.Context, c client.Client, invConfig InventoryConfig,
|
||||||
podBObj,
|
podBObj,
|
||||||
}
|
}
|
||||||
|
|
||||||
applierEvents := runCollect(applier.Run(ctx, inventoryInfo, resources, apply.ApplierOptions{
|
applierEvents := e2eutil.RunCollect(applier.Run(ctx, inventoryInfo, resources, apply.ApplierOptions{
|
||||||
ReconcileTimeout: 2 * time.Minute,
|
ReconcileTimeout: 2 * time.Minute,
|
||||||
EmitStatusEvents: true,
|
EmitStatusEvents: true,
|
||||||
DryRunStrategy: common.DryRunClient,
|
DryRunStrategy: common.DryRunClient,
|
||||||
|
|
@ -176,18 +178,18 @@ func dryRunTest(ctx context.Context, c client.Client, invConfig InventoryConfig,
|
||||||
Expect(received).To(testutil.Equal(expEvents))
|
Expect(received).To(testutil.Equal(expEvents))
|
||||||
|
|
||||||
By("Verify pod NotFound")
|
By("Verify pod NotFound")
|
||||||
assertUnstructuredDoesNotExist(ctx, c, podBObj)
|
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, podBObj)
|
||||||
|
|
||||||
By("Verify inventory NotFound")
|
By("Verify inventory NotFound")
|
||||||
invConfig.InvNotExistsFunc(ctx, c, inventoryName, namespaceName, inventoryID)
|
invConfig.InvNotExistsFunc(ctx, c, inventoryName, namespaceName, inventoryID)
|
||||||
|
|
||||||
By("Apply")
|
By("Apply")
|
||||||
runWithNoErr(applier.Run(ctx, inventoryInfo, resources, apply.ApplierOptions{
|
e2eutil.RunWithNoErr(applier.Run(ctx, inventoryInfo, resources, apply.ApplierOptions{
|
||||||
ReconcileTimeout: 2 * time.Minute,
|
ReconcileTimeout: 2 * time.Minute,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
By("Verify pod created")
|
By("Verify pod created")
|
||||||
assertUnstructuredExists(ctx, c, podBObj)
|
e2eutil.AssertUnstructuredExists(ctx, c, podBObj)
|
||||||
|
|
||||||
By("Verify inventory size")
|
By("Verify inventory size")
|
||||||
invConfig.InvSizeVerifyFunc(ctx, c, inventoryName, namespaceName, inventoryID, 2, 2)
|
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")
|
By("Destroy with DryRun")
|
||||||
destroyer := invConfig.DestroyerFactoryFunc()
|
destroyer := invConfig.DestroyerFactoryFunc()
|
||||||
|
|
||||||
destroyerEvents := runCollect(destroyer.Run(ctx, inventoryInfo, apply.DestroyerOptions{
|
destroyerEvents := e2eutil.RunCollect(destroyer.Run(ctx, inventoryInfo, apply.DestroyerOptions{
|
||||||
InventoryPolicy: inventory.PolicyAdoptIfNoInventory,
|
InventoryPolicy: inventory.PolicyAdoptIfNoInventory,
|
||||||
EmitStatusEvents: true,
|
EmitStatusEvents: true,
|
||||||
DryRunStrategy: common.DryRunClient,
|
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))
|
Expect(testutil.EventsToExpEvents(destroyerEvents)).To(testutil.Equal(expEvents))
|
||||||
|
|
||||||
By("Verify pod still exists")
|
By("Verify pod still exists")
|
||||||
assertUnstructuredExists(ctx, c, podBObj)
|
e2eutil.AssertUnstructuredExists(ctx, c, podBObj)
|
||||||
|
|
||||||
By("Destroy")
|
By("Destroy")
|
||||||
runWithNoErr(destroyer.Run(ctx, inventoryInfo, apply.DestroyerOptions{
|
e2eutil.RunWithNoErr(destroyer.Run(ctx, inventoryInfo, apply.DestroyerOptions{
|
||||||
InventoryPolicy: inventory.PolicyAdoptIfNoInventory,
|
InventoryPolicy: inventory.PolicyAdoptIfNoInventory,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
By("Verify pod deleted")
|
By("Verify pod deleted")
|
||||||
assertUnstructuredDoesNotExist(ctx, c, podBObj)
|
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, podBObj)
|
||||||
|
|
||||||
By("Verify inventory deleted")
|
By("Verify inventory deleted")
|
||||||
invConfig.InvNotExistsFunc(ctx, c, inventoryName, namespaceName, inventoryID)
|
invConfig.InvNotExistsFunc(ctx, c, inventoryName, namespaceName, inventoryID)
|
||||||
|
|
|
||||||
|
|
@ -12,69 +12,25 @@ import (
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
"github.com/onsi/gomega/format"
|
"github.com/onsi/gomega/format"
|
||||||
v1 "k8s.io/api/core/v1"
|
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/apis/meta/v1/unstructured"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
|
||||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
"k8s.io/kubectl/pkg/cmd/util"
|
|
||||||
"k8s.io/kubectl/pkg/scheme"
|
"k8s.io/kubectl/pkg/scheme"
|
||||||
"sigs.k8s.io/cli-utils/pkg/apply"
|
"sigs.k8s.io/cli-utils/test/e2e/e2eutil"
|
||||||
"sigs.k8s.io/cli-utils/pkg/common"
|
"sigs.k8s.io/cli-utils/test/e2e/invconfig"
|
||||||
"sigs.k8s.io/cli-utils/pkg/inventory"
|
|
||||||
"sigs.k8s.io/cli-utils/test/e2e/customprovider"
|
|
||||||
ctrl "sigs.k8s.io/controller-runtime"
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
|
"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 (
|
const (
|
||||||
ConfigMapTypeInvConfig = "ConfigMap"
|
ConfigMapTypeInvConfig = "ConfigMap"
|
||||||
CustomTypeInvConfig = "Custom"
|
CustomTypeInvConfig = "Custom"
|
||||||
)
|
)
|
||||||
|
|
||||||
var inventoryConfigs = map[string]InventoryConfig{
|
var inventoryConfigs = map[string]invconfig.InventoryConfig{}
|
||||||
ConfigMapTypeInvConfig: {
|
var inventoryConfigTypes = []string{
|
||||||
Strategy: inventory.LabelStrategy,
|
ConfigMapTypeInvConfig,
|
||||||
FactoryFunc: cmInventoryManifest,
|
CustomTypeInvConfig,
|
||||||
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,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse optional logging flags
|
// Parse optional logging flags
|
||||||
|
|
@ -101,6 +57,14 @@ var _ = Describe("Applier", func() {
|
||||||
cfg, err := ctrl.GetConfig()
|
cfg, err := ctrl.GetConfig()
|
||||||
Expect(err).NotTo(HaveOccurred())
|
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)
|
mapper, err := apiutil.NewDynamicRESTMapper(cfg)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
|
@ -112,20 +76,26 @@ var _ = Describe("Applier", func() {
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), defaultBeforeTestTimeout)
|
ctx, cancel := context.WithTimeout(context.Background(), defaultBeforeTestTimeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
createInventoryCRD(ctx, c)
|
e2eutil.CreateInventoryCRD(ctx, c)
|
||||||
Expect(ctx.Err()).To(BeNil(), "BeforeSuite context cancelled or timed out")
|
Expect(ctx.Err()).To(BeNil(), "BeforeSuite context cancelled or timed out")
|
||||||
})
|
})
|
||||||
|
|
||||||
AfterSuite(func() {
|
AfterSuite(func() {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), defaultAfterTestTimeout)
|
ctx, cancel := context.WithTimeout(context.Background(), defaultAfterTestTimeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
deleteInventoryCRD(ctx, c)
|
e2eutil.DeleteInventoryCRD(ctx, c)
|
||||||
Expect(ctx.Err()).To(BeNil(), "AfterSuite context cancelled or timed out")
|
Expect(ctx.Err()).To(BeNil(), "AfterSuite context cancelled or timed out")
|
||||||
})
|
})
|
||||||
|
|
||||||
for name := range inventoryConfigs {
|
for i := range inventoryConfigTypes {
|
||||||
invConfig := inventoryConfigs[name]
|
invType := inventoryConfigTypes[i]
|
||||||
Context(fmt.Sprintf("Inventory: %s", name), func() {
|
Context(fmt.Sprintf("Inventory: %s", invType), func() {
|
||||||
|
var invConfig invconfig.InventoryConfig
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
invConfig = inventoryConfigs[invType]
|
||||||
|
})
|
||||||
|
|
||||||
Context("Apply and destroy", func() {
|
Context("Apply and destroy", func() {
|
||||||
var namespace *v1.Namespace
|
var namespace *v1.Namespace
|
||||||
var inventoryName string
|
var inventoryName string
|
||||||
|
|
@ -134,8 +104,8 @@ var _ = Describe("Applier", func() {
|
||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
ctx, cancel = context.WithTimeout(context.Background(), defaultTestTimeout)
|
ctx, cancel = context.WithTimeout(context.Background(), defaultTestTimeout)
|
||||||
inventoryName = randomString("test-inv-")
|
inventoryName = e2eutil.RandomString("test-inv-")
|
||||||
namespace = createRandomNamespace(ctx, c)
|
namespace = e2eutil.CreateRandomNamespace(ctx, c)
|
||||||
})
|
})
|
||||||
|
|
||||||
AfterEach(func() {
|
AfterEach(func() {
|
||||||
|
|
@ -147,20 +117,20 @@ var _ = Describe("Applier", func() {
|
||||||
// clean up resources created by the tests
|
// clean up resources created by the tests
|
||||||
fields := struct{ Namespace string }{Namespace: namespace.GetName()}
|
fields := struct{ Namespace string }{Namespace: namespace.GetName()}
|
||||||
objs := []*unstructured.Unstructured{
|
objs := []*unstructured.Unstructured{
|
||||||
manifestToUnstructured(cr),
|
e2eutil.ManifestToUnstructured(cr),
|
||||||
manifestToUnstructured(crd),
|
e2eutil.ManifestToUnstructured(crd),
|
||||||
withNamespace(manifestToUnstructured(pod1), namespace.GetName()),
|
e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod1), namespace.GetName()),
|
||||||
withNamespace(manifestToUnstructured(pod2), namespace.GetName()),
|
e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod2), namespace.GetName()),
|
||||||
withNamespace(manifestToUnstructured(pod3), namespace.GetName()),
|
e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod3), namespace.GetName()),
|
||||||
templateToUnstructured(podATemplate, fields),
|
e2eutil.TemplateToUnstructured(podATemplate, fields),
|
||||||
templateToUnstructured(podBTemplate, fields),
|
e2eutil.TemplateToUnstructured(podBTemplate, fields),
|
||||||
withNamespace(manifestToUnstructured(deployment1), namespace.GetName()),
|
e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(deployment1), namespace.GetName()),
|
||||||
manifestToUnstructured(apiservice1),
|
e2eutil.ManifestToUnstructured(apiservice1),
|
||||||
}
|
}
|
||||||
for _, obj := range objs {
|
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() {
|
It("Apply and destroy", func() {
|
||||||
|
|
@ -235,7 +205,7 @@ var _ = Describe("Applier", func() {
|
||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
ctx, cancel = context.WithTimeout(context.Background(), defaultTestTimeout)
|
ctx, cancel = context.WithTimeout(context.Background(), defaultTestTimeout)
|
||||||
namespace = createRandomNamespace(ctx, c)
|
namespace = e2eutil.CreateRandomNamespace(ctx, c)
|
||||||
})
|
})
|
||||||
|
|
||||||
AfterEach(func() {
|
AfterEach(func() {
|
||||||
|
|
@ -244,8 +214,8 @@ var _ = Describe("Applier", func() {
|
||||||
// new timeout for cleanup
|
// new timeout for cleanup
|
||||||
ctx, cancel = context.WithTimeout(context.Background(), defaultAfterTestTimeout)
|
ctx, cancel = context.WithTimeout(context.Background(), defaultAfterTestTimeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
deleteUnstructuredIfExists(ctx, c, withNamespace(manifestToUnstructured(deployment1), namespace.GetName()))
|
e2eutil.DeleteUnstructuredIfExists(ctx, c, e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(deployment1), namespace.GetName()))
|
||||||
deleteNamespace(ctx, c, namespace)
|
e2eutil.DeleteNamespace(ctx, c, namespace)
|
||||||
})
|
})
|
||||||
|
|
||||||
It("MustMatch policy", func() {
|
It("MustMatch policy", func() {
|
||||||
|
|
@ -271,8 +241,8 @@ var _ = Describe("Applier", func() {
|
||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
ctx, cancel = context.WithTimeout(context.Background(), defaultTestTimeout)
|
ctx, cancel = context.WithTimeout(context.Background(), defaultTestTimeout)
|
||||||
inventoryName = randomString("test-inv-")
|
inventoryName = e2eutil.RandomString("test-inv-")
|
||||||
namespace = createRandomNamespace(ctx, c)
|
namespace = e2eutil.CreateRandomNamespace(ctx, c)
|
||||||
})
|
})
|
||||||
|
|
||||||
AfterEach(func() {
|
AfterEach(func() {
|
||||||
|
|
@ -281,8 +251,8 @@ var _ = Describe("Applier", func() {
|
||||||
// new timeout for cleanup
|
// new timeout for cleanup
|
||||||
ctx, cancel = context.WithTimeout(context.Background(), defaultAfterTestTimeout)
|
ctx, cancel = context.WithTimeout(context.Background(), defaultAfterTestTimeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
deleteUnstructuredIfExists(ctx, c, withNamespace(manifestToUnstructured(deployment1), namespace.GetName()))
|
e2eutil.DeleteUnstructuredIfExists(ctx, c, e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(deployment1), namespace.GetName()))
|
||||||
deleteNamespace(ctx, c, namespace)
|
e2eutil.DeleteNamespace(ctx, c, namespace)
|
||||||
})
|
})
|
||||||
|
|
||||||
It("Apply with existing inventory", func() {
|
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.
|
// Copyright 2020 The Kubernetes Authors.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
package e2e
|
package e2eutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
. "github.com/onsi/ginkgo"
|
"github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
"github.com/onsi/gomega"
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apimachinery/pkg/util/yaml"
|
"k8s.io/apimachinery/pkg/util/yaml"
|
||||||
"sigs.k8s.io/cli-utils/pkg/apply/event"
|
"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/kstatus/status"
|
||||||
"sigs.k8s.io/cli-utils/pkg/object/dependson"
|
"sigs.k8s.io/cli-utils/pkg/object/dependson"
|
||||||
"sigs.k8s.io/cli-utils/pkg/object/mutation"
|
"sigs.k8s.io/cli-utils/pkg/object/mutation"
|
||||||
|
"sigs.k8s.io/cli-utils/test/e2e/customprovider"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"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")
|
err := unstructured.SetNestedField(obj.Object, int64(replicas), "spec", "replicas")
|
||||||
Expect(err).NotTo(HaveOccurred())
|
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
|
|
||||||
func withNamespace(obj *unstructured.Unstructured, namespace string) *unstructured.Unstructured {
|
func WithNamespace(obj *unstructured.Unstructured, namespace string) *unstructured.Unstructured {
|
||||||
obj.SetNamespace(namespace)
|
obj.SetNamespace(namespace)
|
||||||
return obj
|
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")
|
containers, found, err := unstructured.NestedSlice(obj.Object, "spec", "containers")
|
||||||
Expect(err).NotTo(HaveOccurred())
|
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||||
Expect(found).To(BeTrue())
|
gomega.Expect(found).To(gomega.BeTrue())
|
||||||
|
|
||||||
containerFound := false
|
containerFound := false
|
||||||
for i := range containers {
|
for i := range containers {
|
||||||
|
|
@ -54,26 +54,26 @@ func podWithImage(obj *unstructured.Unstructured, containerName, image string) *
|
||||||
containerFound = true
|
containerFound = true
|
||||||
container["image"] = image
|
container["image"] = image
|
||||||
}
|
}
|
||||||
Expect(containerFound).To(BeTrue())
|
gomega.Expect(containerFound).To(gomega.BeTrue())
|
||||||
err = unstructured.SetNestedSlice(obj.Object, containers, "spec", "containers")
|
err = unstructured.SetNestedSlice(obj.Object, containers, "spec", "containers")
|
||||||
Expect(err).NotTo(HaveOccurred())
|
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||||
return obj
|
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")
|
selectors, found, err := unstructured.NestedMap(obj.Object, "spec", "nodeSelector")
|
||||||
Expect(err).NotTo(HaveOccurred())
|
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||||
|
|
||||||
if !found {
|
if !found {
|
||||||
selectors = make(map[string]interface{})
|
selectors = make(map[string]interface{})
|
||||||
}
|
}
|
||||||
selectors[key] = value
|
selectors[key] = value
|
||||||
err = unstructured.SetNestedMap(obj.Object, selectors, "spec", "nodeSelector")
|
err = unstructured.SetNestedMap(obj.Object, selectors, "spec", "nodeSelector")
|
||||||
Expect(err).NotTo(HaveOccurred())
|
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||||
return obj
|
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()
|
annotations := obj.GetAnnotations()
|
||||||
if annotations == nil {
|
if annotations == nil {
|
||||||
annotations = make(map[string]string)
|
annotations = make(map[string]string)
|
||||||
|
|
@ -83,7 +83,7 @@ func withAnnotation(obj *unstructured.Unstructured, key, value string) *unstruct
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
|
|
||||||
func withDependsOn(obj *unstructured.Unstructured, dep string) *unstructured.Unstructured {
|
func WithDependsOn(obj *unstructured.Unstructured, dep string) *unstructured.Unstructured {
|
||||||
a := obj.GetAnnotations()
|
a := obj.GetAnnotations()
|
||||||
if a == nil {
|
if a == nil {
|
||||||
a = make(map[string]string, 1)
|
a = make(map[string]string, 1)
|
||||||
|
|
@ -93,18 +93,18 @@ func withDependsOn(obj *unstructured.Unstructured, dep string) *unstructured.Uns
|
||||||
return obj
|
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)
|
ref := mutation.ResourceReferenceFromUnstructured(obj)
|
||||||
|
|
||||||
err := c.Delete(ctx, obj,
|
err := c.Delete(ctx, obj,
|
||||||
client.PropagationPolicy(metav1.DeletePropagationForeground))
|
client.PropagationPolicy(metav1.DeletePropagationForeground))
|
||||||
Expect(err).NotTo(HaveOccurred(),
|
gomega.Expect(err).NotTo(gomega.HaveOccurred(),
|
||||||
"expected DELETE to not error (%s): %s", ref, err)
|
"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)
|
ref := mutation.ResourceReferenceFromUnstructured(obj)
|
||||||
resultObj := ref.ToUnstructured()
|
resultObj := ref.ToUnstructured()
|
||||||
|
|
||||||
|
|
@ -118,7 +118,7 @@ func waitForDeletion(ctx context.Context, c client.Client, obj *unstructured.Uns
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-t.C:
|
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
|
return
|
||||||
case <-s.C:
|
case <-s.C:
|
||||||
err := c.Get(ctx, types.NamespacedName{
|
err := c.Get(ctx, types.NamespacedName{
|
||||||
|
|
@ -126,7 +126,7 @@ func waitForDeletion(ctx context.Context, c client.Client, obj *unstructured.Uns
|
||||||
Name: obj.GetName(),
|
Name: obj.GetName(),
|
||||||
}, resultObj)
|
}, resultObj)
|
||||||
if err != nil {
|
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)
|
"expected GET to error with NotFound (%s): %s", ref, err)
|
||||||
return
|
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)
|
ref := mutation.ResourceReferenceFromUnstructured(obj)
|
||||||
|
|
||||||
err := c.Create(ctx, 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)
|
"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)
|
ref := mutation.ResourceReferenceFromUnstructured(obj)
|
||||||
resultObj := ref.ToUnstructured()
|
resultObj := ref.ToUnstructured()
|
||||||
|
|
||||||
|
|
@ -159,7 +159,7 @@ func waitForCreation(ctx context.Context, c client.Client, obj *unstructured.Uns
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-t.C:
|
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
|
return
|
||||||
case <-s.C:
|
case <-s.C:
|
||||||
err := c.Get(ctx, types.NamespacedName{
|
err := c.Get(ctx, types.NamespacedName{
|
||||||
|
|
@ -169,7 +169,7 @@ func waitForCreation(ctx context.Context, c client.Client, obj *unstructured.Uns
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return
|
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)
|
"expected GET to error with NotFound (%s): %s", ref, err)
|
||||||
// if NotFound, sleep and retry
|
// if NotFound, sleep and retry
|
||||||
s = time.NewTimer(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)
|
ref := mutation.ResourceReferenceFromUnstructured(obj)
|
||||||
resultObj := ref.ToUnstructured()
|
resultObj := ref.ToUnstructured()
|
||||||
|
|
||||||
|
|
@ -185,12 +185,12 @@ func assertUnstructuredExists(ctx context.Context, c client.Client, obj *unstruc
|
||||||
Namespace: obj.GetNamespace(),
|
Namespace: obj.GetNamespace(),
|
||||||
Name: obj.GetName(),
|
Name: obj.GetName(),
|
||||||
}, resultObj)
|
}, resultObj)
|
||||||
Expect(err).NotTo(HaveOccurred(),
|
gomega.Expect(err).NotTo(gomega.HaveOccurred(),
|
||||||
"expected GET not to error (%s): %s", ref, err)
|
"expected GET not to error (%s): %s", ref, err)
|
||||||
return resultObj
|
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)
|
ref := mutation.ResourceReferenceFromUnstructured(obj)
|
||||||
resultObj := ref.ToUnstructured()
|
resultObj := ref.ToUnstructured()
|
||||||
|
|
||||||
|
|
@ -198,13 +198,13 @@ func assertUnstructuredDoesNotExist(ctx context.Context, c client.Client, obj *u
|
||||||
Namespace: obj.GetNamespace(),
|
Namespace: obj.GetNamespace(),
|
||||||
Name: obj.GetName(),
|
Name: obj.GetName(),
|
||||||
}, resultObj)
|
}, resultObj)
|
||||||
Expect(err).To(HaveOccurred(),
|
gomega.Expect(err).To(gomega.HaveOccurred(),
|
||||||
"expected GET to error (%s)", ref)
|
"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)
|
"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)
|
ref := mutation.ResourceReferenceFromUnstructured(obj)
|
||||||
resultObj := ref.ToUnstructured()
|
resultObj := ref.ToUnstructured()
|
||||||
|
|
||||||
|
|
@ -212,18 +212,18 @@ func applyUnstructured(ctx context.Context, c client.Client, obj *unstructured.U
|
||||||
Namespace: obj.GetNamespace(),
|
Namespace: obj.GetNamespace(),
|
||||||
Name: obj.GetName(),
|
Name: obj.GetName(),
|
||||||
}, resultObj)
|
}, resultObj)
|
||||||
Expect(err).NotTo(HaveOccurred(),
|
gomega.Expect(err).NotTo(gomega.HaveOccurred(),
|
||||||
"expected GET not to error (%s)", ref)
|
"expected GET not to error (%s)", ref)
|
||||||
|
|
||||||
err = c.Patch(ctx, obj, client.MergeFrom(resultObj))
|
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)
|
"expected PATCH not to error (%s): %s", ref, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertUnstructuredAvailable(obj *unstructured.Unstructured) {
|
func AssertUnstructuredAvailable(obj *unstructured.Unstructured) {
|
||||||
ref := mutation.ResourceReferenceFromUnstructured(obj)
|
ref := mutation.ResourceReferenceFromUnstructured(obj)
|
||||||
objc, err := status.GetObjectWithConditions(obj.Object)
|
objc, err := status.GetObjectWithConditions(obj.Object)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||||
available := false
|
available := false
|
||||||
for _, c := range objc.Status.Conditions {
|
for _, c := range objc.Status.Conditions {
|
||||||
// appsv1.DeploymentAvailable && corev1.ConditionTrue
|
// appsv1.DeploymentAvailable && corev1.ConditionTrue
|
||||||
|
|
@ -232,16 +232,30 @@ func assertUnstructuredAvailable(obj *unstructured.Unstructured) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expect(available).To(BeTrue(),
|
gomega.Expect(available).To(gomega.BeTrue(),
|
||||||
"expected Available condition to be True (%s)", ref)
|
"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()
|
randomSuffix := common.RandomStr()
|
||||||
return fmt.Sprintf("%s%s", prefix, randomSuffix)
|
return fmt.Sprintf("%s%s", prefix, randomSuffix)
|
||||||
}
|
}
|
||||||
|
|
||||||
func run(ch <-chan event.Event) error {
|
func Run(ch <-chan event.Event) error {
|
||||||
var err error
|
var err error
|
||||||
for e := range ch {
|
for e := range ch {
|
||||||
if e.Type == event.ErrorType {
|
if e.Type == event.ErrorType {
|
||||||
|
|
@ -251,11 +265,11 @@ func run(ch <-chan event.Event) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func runWithNoErr(ch <-chan event.Event) {
|
func RunWithNoErr(ch <-chan event.Event) {
|
||||||
runCollectNoErr(ch)
|
RunCollectNoErr(ch)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runCollect(ch <-chan event.Event) []event.Event {
|
func RunCollect(ch <-chan event.Event) []event.Event {
|
||||||
var events []event.Event
|
var events []event.Event
|
||||||
for e := range ch {
|
for e := range ch {
|
||||||
events = append(events, e)
|
events = append(events, e)
|
||||||
|
|
@ -263,53 +277,15 @@ func runCollect(ch <-chan event.Event) []event.Event {
|
||||||
return events
|
return events
|
||||||
}
|
}
|
||||||
|
|
||||||
func runCollectNoErr(ch <-chan event.Event) []event.Event {
|
func RunCollectNoErr(ch <-chan event.Event) []event.Event {
|
||||||
events := runCollect(ch)
|
events := RunCollect(ch)
|
||||||
for _, e := range events {
|
for _, e := range events {
|
||||||
Expect(e.Type).NotTo(Equal(event.ErrorType))
|
gomega.Expect(e.Type).NotTo(gomega.Equal(event.ErrorType))
|
||||||
}
|
}
|
||||||
return events
|
return events
|
||||||
}
|
}
|
||||||
|
|
||||||
func cmInventoryManifest(name, namespace, id string) *unstructured.Unstructured {
|
func ManifestToUnstructured(manifest []byte) *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 {
|
|
||||||
u := make(map[string]interface{})
|
u := make(map[string]interface{})
|
||||||
err := yaml.Unmarshal(manifest, &u)
|
err := yaml.Unmarshal(manifest, &u)
|
||||||
if err != nil {
|
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)
|
t, err := template.New("manifest").Parse(tmpl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Errorf("failed to parse manifest go-template: %w", err))
|
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 {
|
if err != nil {
|
||||||
panic(fmt.Errorf("failed to execute manifest go-template: %w", err))
|
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/apply/event"
|
||||||
"sigs.k8s.io/cli-utils/pkg/inventory"
|
"sigs.k8s.io/cli-utils/pkg/inventory"
|
||||||
"sigs.k8s.io/cli-utils/pkg/testutil"
|
"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"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
//nolint:dupl // expEvents similar to other tests
|
//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")
|
By("Apply zero resources")
|
||||||
applier := invConfig.ApplierFactoryFunc()
|
applier := invConfig.ApplierFactoryFunc()
|
||||||
|
|
||||||
|
|
@ -27,7 +29,7 @@ func emptySetTest(ctx context.Context, c client.Client, invConfig InventoryConfi
|
||||||
|
|
||||||
resources := []*unstructured.Unstructured{}
|
resources := []*unstructured.Unstructured{}
|
||||||
|
|
||||||
applierEvents := runCollect(applier.Run(ctx, inventoryInfo, resources, apply.ApplierOptions{
|
applierEvents := e2eutil.RunCollect(applier.Run(ctx, inventoryInfo, resources, apply.ApplierOptions{
|
||||||
EmitStatusEvents: true,
|
EmitStatusEvents: true,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|
@ -83,7 +85,7 @@ func emptySetTest(ctx context.Context, c client.Client, invConfig InventoryConfi
|
||||||
destroyer := invConfig.DestroyerFactoryFunc()
|
destroyer := invConfig.DestroyerFactoryFunc()
|
||||||
|
|
||||||
options := apply.DestroyerOptions{InventoryPolicy: inventory.PolicyAdoptIfNoInventory}
|
options := apply.DestroyerOptions{InventoryPolicy: inventory.PolicyAdoptIfNoInventory}
|
||||||
destroyerEvents := runCollect(destroyer.Run(ctx, inventoryInfo, options))
|
destroyerEvents := e2eutil.RunCollect(destroyer.Run(ctx, inventoryInfo, options))
|
||||||
|
|
||||||
expEvents = []testutil.ExpEvent{
|
expEvents = []testutil.ExpEvent{
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,12 @@ import (
|
||||||
"sigs.k8s.io/cli-utils/pkg/object"
|
"sigs.k8s.io/cli-utils/pkg/object"
|
||||||
"sigs.k8s.io/cli-utils/pkg/object/validation"
|
"sigs.k8s.io/cli-utils/pkg/object/validation"
|
||||||
"sigs.k8s.io/cli-utils/pkg/testutil"
|
"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"
|
"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")
|
By("exit early on invalid object")
|
||||||
applier := invConfig.ApplierFactoryFunc()
|
applier := invConfig.ApplierFactoryFunc()
|
||||||
|
|
||||||
|
|
@ -27,12 +29,12 @@ func exitEarlyTest(ctx context.Context, c client.Client, invConfig InventoryConf
|
||||||
|
|
||||||
fields := struct{ Namespace string }{Namespace: namespaceName}
|
fields := struct{ Namespace string }{Namespace: namespaceName}
|
||||||
// valid pod
|
// valid pod
|
||||||
pod1Obj := withNamespace(manifestToUnstructured(pod1), namespaceName)
|
pod1Obj := e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod1), namespaceName)
|
||||||
// valid deployment with dependency
|
// 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()))
|
fmt.Sprintf("/namespaces/%s/Pod/%s", namespaceName, pod1Obj.GetName()))
|
||||||
// missing name
|
// missing name
|
||||||
invalidPodObj := templateToUnstructured(invalidPodTemplate, fields)
|
invalidPodObj := e2eutil.TemplateToUnstructured(invalidPodTemplate, fields)
|
||||||
|
|
||||||
resources := []*unstructured.Unstructured{
|
resources := []*unstructured.Unstructured{
|
||||||
pod1Obj,
|
pod1Obj,
|
||||||
|
|
@ -40,7 +42,7 @@ func exitEarlyTest(ctx context.Context, c client.Client, invConfig InventoryConf
|
||||||
invalidPodObj,
|
invalidPodObj,
|
||||||
}
|
}
|
||||||
|
|
||||||
applierEvents := runCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
applierEvents := e2eutil.RunCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
||||||
EmitStatusEvents: false,
|
EmitStatusEvents: false,
|
||||||
ValidationPolicy: validation.ExitEarly,
|
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))
|
Expect(testutil.EventsToExpEvents(applierEvents)).To(testutil.Equal(expEvents))
|
||||||
|
|
||||||
By("verify pod1 not found")
|
By("verify pod1 not found")
|
||||||
assertUnstructuredDoesNotExist(ctx, c, pod1Obj)
|
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, pod1Obj)
|
||||||
|
|
||||||
By("verify deployment1 not found")
|
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/kstatus/status"
|
||||||
"sigs.k8s.io/cli-utils/pkg/object"
|
"sigs.k8s.io/cli-utils/pkg/object"
|
||||||
"sigs.k8s.io/cli-utils/pkg/testutil"
|
"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"
|
"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")
|
By("Apply first set of resources")
|
||||||
applier := invConfig.ApplierFactoryFunc()
|
applier := invConfig.ApplierFactoryFunc()
|
||||||
|
|
||||||
firstInvName := randomString("first-inv-")
|
firstInvName := e2eutil.RandomString("first-inv-")
|
||||||
firstInv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(firstInvName, namespaceName, firstInvName))
|
firstInv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(firstInvName, namespaceName, firstInvName))
|
||||||
deployment1Obj := withNamespace(manifestToUnstructured(deployment1), namespaceName)
|
deployment1Obj := e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(deployment1), namespaceName)
|
||||||
firstResources := []*unstructured.Unstructured{
|
firstResources := []*unstructured.Unstructured{
|
||||||
deployment1Obj,
|
deployment1Obj,
|
||||||
}
|
}
|
||||||
|
|
||||||
runWithNoErr(applier.Run(ctx, firstInv, firstResources, apply.ApplierOptions{
|
e2eutil.RunWithNoErr(applier.Run(ctx, firstInv, firstResources, apply.ApplierOptions{
|
||||||
ReconcileTimeout: 2 * time.Minute,
|
ReconcileTimeout: 2 * time.Minute,
|
||||||
EmitStatusEvents: true,
|
EmitStatusEvents: true,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
By("Apply second set of resources")
|
By("Apply second set of resources")
|
||||||
secondInvName := randomString("second-inv-")
|
secondInvName := e2eutil.RandomString("second-inv-")
|
||||||
secondInv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(secondInvName, namespaceName, secondInvName))
|
secondInv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(secondInvName, namespaceName, secondInvName))
|
||||||
deployment1Obj = withNamespace(manifestToUnstructured(deployment1), namespaceName)
|
deployment1Obj = e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(deployment1), namespaceName)
|
||||||
secondResources := []*unstructured.Unstructured{
|
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,
|
ReconcileTimeout: 2 * time.Minute,
|
||||||
EmitStatusEvents: true,
|
EmitStatusEvents: true,
|
||||||
InventoryPolicy: inventory.PolicyMustMatch,
|
InventoryPolicy: inventory.PolicyMustMatch,
|
||||||
|
|
@ -178,7 +180,7 @@ func inventoryPolicyMustMatchTest(ctx context.Context, c client.Client, invConfi
|
||||||
Expect(received).To(testutil.Equal(expEvents))
|
Expect(received).To(testutil.Equal(expEvents))
|
||||||
|
|
||||||
By("Verify resource wasn't updated")
|
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")
|
replicas, found, err := object.NestedField(result.Object, "spec", "replicas")
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(found).To(BeTrue())
|
Expect(found).To(BeTrue())
|
||||||
|
|
@ -187,22 +189,22 @@ func inventoryPolicyMustMatchTest(ctx context.Context, c client.Client, invConfi
|
||||||
invConfig.InvCountVerifyFunc(ctx, c, namespaceName, 2)
|
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")
|
By("Create unmanaged resource")
|
||||||
deployment1Obj := withNamespace(manifestToUnstructured(deployment1), namespaceName)
|
deployment1Obj := e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(deployment1), namespaceName)
|
||||||
createUnstructuredAndWait(ctx, c, deployment1Obj)
|
e2eutil.CreateUnstructuredAndWait(ctx, c, deployment1Obj)
|
||||||
|
|
||||||
By("Apply resources")
|
By("Apply resources")
|
||||||
applier := invConfig.ApplierFactoryFunc()
|
applier := invConfig.ApplierFactoryFunc()
|
||||||
|
|
||||||
invName := randomString("test-inv-")
|
invName := e2eutil.RandomString("test-inv-")
|
||||||
inv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(invName, namespaceName, invName))
|
inv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(invName, namespaceName, invName))
|
||||||
deployment1Obj = withNamespace(manifestToUnstructured(deployment1), namespaceName)
|
deployment1Obj = e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(deployment1), namespaceName)
|
||||||
resources := []*unstructured.Unstructured{
|
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,
|
ReconcileTimeout: 2 * time.Minute,
|
||||||
EmitStatusEvents: true,
|
EmitStatusEvents: true,
|
||||||
InventoryPolicy: inventory.PolicyAdoptIfNoInventory,
|
InventoryPolicy: inventory.PolicyAdoptIfNoInventory,
|
||||||
|
|
@ -344,7 +346,7 @@ func inventoryPolicyAdoptIfNoInventoryTest(ctx context.Context, c client.Client,
|
||||||
Expect(received).To(testutil.Equal(expEvents))
|
Expect(received).To(testutil.Equal(expEvents))
|
||||||
|
|
||||||
By("Verify resource was updated and added to inventory")
|
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")
|
replicas, found, err := object.NestedField(result.Object, "spec", "replicas")
|
||||||
Expect(err).NotTo(HaveOccurred())
|
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)
|
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")
|
By("Apply an initial set of resources")
|
||||||
applier := invConfig.ApplierFactoryFunc()
|
applier := invConfig.ApplierFactoryFunc()
|
||||||
|
|
||||||
firstInvName := randomString("first-inv-")
|
firstInvName := e2eutil.RandomString("first-inv-")
|
||||||
firstInv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(firstInvName, namespaceName, firstInvName))
|
firstInv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(firstInvName, namespaceName, firstInvName))
|
||||||
deployment1Obj := withNamespace(manifestToUnstructured(deployment1), namespaceName)
|
deployment1Obj := e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(deployment1), namespaceName)
|
||||||
firstResources := []*unstructured.Unstructured{
|
firstResources := []*unstructured.Unstructured{
|
||||||
deployment1Obj,
|
deployment1Obj,
|
||||||
}
|
}
|
||||||
|
|
||||||
runWithNoErr(applier.Run(ctx, firstInv, firstResources, apply.ApplierOptions{
|
e2eutil.RunWithNoErr(applier.Run(ctx, firstInv, firstResources, apply.ApplierOptions{
|
||||||
ReconcileTimeout: 2 * time.Minute,
|
ReconcileTimeout: 2 * time.Minute,
|
||||||
EmitStatusEvents: true,
|
EmitStatusEvents: true,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
By("Apply resources")
|
By("Apply resources")
|
||||||
secondInvName := randomString("test-inv-")
|
secondInvName := e2eutil.RandomString("test-inv-")
|
||||||
secondInv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(secondInvName, namespaceName, secondInvName))
|
secondInv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(secondInvName, namespaceName, secondInvName))
|
||||||
deployment1Obj = withNamespace(manifestToUnstructured(deployment1), namespaceName)
|
deployment1Obj = e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(deployment1), namespaceName)
|
||||||
secondResources := []*unstructured.Unstructured{
|
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,
|
ReconcileTimeout: 2 * time.Minute,
|
||||||
EmitStatusEvents: true,
|
EmitStatusEvents: true,
|
||||||
InventoryPolicy: inventory.PolicyAdoptAll,
|
InventoryPolicy: inventory.PolicyAdoptAll,
|
||||||
|
|
@ -526,7 +528,7 @@ func inventoryPolicyAdoptAllTest(ctx context.Context, c client.Client, invConfig
|
||||||
Expect(received).To(testutil.Equal(expEvents))
|
Expect(received).To(testutil.Equal(expEvents))
|
||||||
|
|
||||||
By("Verify resource was updated and added to inventory")
|
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")
|
replicas, found, err := object.NestedField(result.Object, "spec", "replicas")
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@ import (
|
||||||
"sigs.k8s.io/cli-utils/pkg/inventory"
|
"sigs.k8s.io/cli-utils/pkg/inventory"
|
||||||
"sigs.k8s.io/cli-utils/pkg/object"
|
"sigs.k8s.io/cli-utils/pkg/object"
|
||||||
"sigs.k8s.io/cli-utils/pkg/testutil"
|
"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"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -32,15 +34,15 @@ import (
|
||||||
// port from pod-b into an environment variable of pod-a.
|
// port from pod-b into an environment variable of pod-a.
|
||||||
|
|
||||||
//nolint:dupl // expEvents similar to CRD tests
|
//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")
|
By("apply resources in order with substitutions based on apply-time-mutation annotation")
|
||||||
applier := invConfig.ApplierFactoryFunc()
|
applier := invConfig.ApplierFactoryFunc()
|
||||||
|
|
||||||
inv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(inventoryName, namespaceName, "test"))
|
inv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(inventoryName, namespaceName, "test"))
|
||||||
|
|
||||||
fields := struct{ Namespace string }{Namespace: namespaceName}
|
fields := struct{ Namespace string }{Namespace: namespaceName}
|
||||||
podAObj := templateToUnstructured(podATemplate, fields)
|
podAObj := e2eutil.TemplateToUnstructured(podATemplate, fields)
|
||||||
podBObj := templateToUnstructured(podBTemplate, fields)
|
podBObj := e2eutil.TemplateToUnstructured(podBTemplate, fields)
|
||||||
|
|
||||||
// Dependency order: podA -> podB
|
// Dependency order: podA -> podB
|
||||||
// Apply order: podB, podA
|
// Apply order: podB, podA
|
||||||
|
|
@ -49,7 +51,7 @@ func mutationTest(ctx context.Context, c client.Client, invConfig InventoryConfi
|
||||||
podBObj,
|
podBObj,
|
||||||
}
|
}
|
||||||
|
|
||||||
applierEvents := runCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
applierEvents := e2eutil.RunCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
||||||
EmitStatusEvents: false,
|
EmitStatusEvents: false,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|
@ -227,7 +229,7 @@ func mutationTest(ctx context.Context, c client.Client, invConfig InventoryConfi
|
||||||
Expect(testutil.EventsToExpEvents(applierEvents)).To(testutil.Equal(expEvents))
|
Expect(testutil.EventsToExpEvents(applierEvents)).To(testutil.Equal(expEvents))
|
||||||
|
|
||||||
By("verify podB is created and ready")
|
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")
|
podIP, found, err := object.NestedField(result.Object, "status", "podIP")
|
||||||
Expect(err).NotTo(HaveOccurred())
|
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)
|
host := fmt.Sprintf("%s:%d", podIP, containerPort)
|
||||||
|
|
||||||
By("verify podA is mutated, created, and ready")
|
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")
|
podIP, found, err = object.NestedField(result.Object, "status", "podIP")
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
@ -257,7 +259,7 @@ func mutationTest(ctx context.Context, c client.Client, invConfig InventoryConfi
|
||||||
By("destroy resources in opposite order")
|
By("destroy resources in opposite order")
|
||||||
destroyer := invConfig.DestroyerFactoryFunc()
|
destroyer := invConfig.DestroyerFactoryFunc()
|
||||||
options := apply.DestroyerOptions{InventoryPolicy: inventory.PolicyAdoptIfNoInventory}
|
options := apply.DestroyerOptions{InventoryPolicy: inventory.PolicyAdoptIfNoInventory}
|
||||||
destroyerEvents := runCollect(destroyer.Run(ctx, inv, options))
|
destroyerEvents := e2eutil.RunCollect(destroyer.Run(ctx, inv, options))
|
||||||
|
|
||||||
expEvents = []testutil.ExpEvent{
|
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))
|
Expect(testutil.EventsToExpEvents(destroyerEvents)).To(testutil.Equal(expEvents))
|
||||||
|
|
||||||
By("verify podB deleted")
|
By("verify podB deleted")
|
||||||
assertUnstructuredDoesNotExist(ctx, c, podBObj)
|
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, podBObj)
|
||||||
|
|
||||||
By("verify podA deleted")
|
By("verify podA deleted")
|
||||||
assertUnstructuredDoesNotExist(ctx, c, podAObj)
|
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, podAObj)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,12 @@ import (
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"sigs.k8s.io/cli-utils/pkg/apply"
|
"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"
|
"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")
|
By("Apply first set of resources")
|
||||||
applier := invConfig.ApplierFactoryFunc()
|
applier := invConfig.ApplierFactoryFunc()
|
||||||
orgInventoryID := fmt.Sprintf("%s-%s", inventoryName, namespaceName)
|
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))
|
orgApplyInv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(inventoryName, namespaceName, orgInventoryID))
|
||||||
|
|
||||||
resources := []*unstructured.Unstructured{
|
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,
|
ReconcileTimeout: 2 * time.Minute,
|
||||||
EmitStatusEvents: true,
|
EmitStatusEvents: true,
|
||||||
}))
|
}))
|
||||||
|
|
@ -38,7 +40,7 @@ func applyWithExistingInvTest(ctx context.Context, c client.Client, invConfig In
|
||||||
secondInventoryID := fmt.Sprintf("%s-%s-2", inventoryName, namespaceName)
|
secondInventoryID := fmt.Sprintf("%s-%s-2", inventoryName, namespaceName)
|
||||||
secondApplyInv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(inventoryName, namespaceName, secondInventoryID))
|
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,
|
ReconcileTimeout: 2 * time.Minute,
|
||||||
EmitStatusEvents: true,
|
EmitStatusEvents: true,
|
||||||
}))
|
}))
|
||||||
|
|
|
||||||
|
|
@ -14,11 +14,13 @@ import (
|
||||||
"sigs.k8s.io/cli-utils/pkg/apply/event"
|
"sigs.k8s.io/cli-utils/pkg/apply/event"
|
||||||
"sigs.k8s.io/cli-utils/pkg/object"
|
"sigs.k8s.io/cli-utils/pkg/object"
|
||||||
"sigs.k8s.io/cli-utils/pkg/testutil"
|
"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"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
//nolint:dupl // expEvents similar to other tests
|
//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")
|
By("apply resources in order based on depends-on annotation")
|
||||||
applier := invConfig.ApplierFactoryFunc()
|
applier := invConfig.ApplierFactoryFunc()
|
||||||
|
|
||||||
|
|
@ -27,8 +29,8 @@ func namespaceFilterTest(ctx context.Context, c client.Client, invConfig Invento
|
||||||
namespace1Name := fmt.Sprintf("%s-ns1", namespaceName)
|
namespace1Name := fmt.Sprintf("%s-ns1", namespaceName)
|
||||||
|
|
||||||
fields := struct{ Namespace string }{Namespace: namespace1Name}
|
fields := struct{ Namespace string }{Namespace: namespace1Name}
|
||||||
namespace1Obj := templateToUnstructured(namespaceTemplate, fields)
|
namespace1Obj := e2eutil.TemplateToUnstructured(namespaceTemplate, fields)
|
||||||
podBObj := templateToUnstructured(podBTemplate, fields)
|
podBObj := e2eutil.TemplateToUnstructured(podBTemplate, fields)
|
||||||
|
|
||||||
// Dependency order: podB -> namespace1
|
// Dependency order: podB -> namespace1
|
||||||
// Apply order: namespace1, podB
|
// Apply order: namespace1, podB
|
||||||
|
|
@ -39,11 +41,11 @@ func namespaceFilterTest(ctx context.Context, c client.Client, invConfig Invento
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
defer func(ctx context.Context, c client.Client) {
|
defer func(ctx context.Context, c client.Client) {
|
||||||
deleteUnstructuredIfExists(ctx, c, podBObj)
|
e2eutil.DeleteUnstructuredIfExists(ctx, c, podBObj)
|
||||||
deleteUnstructuredIfExists(ctx, c, namespace1Obj)
|
e2eutil.DeleteUnstructuredIfExists(ctx, c, namespace1Obj)
|
||||||
}(ctx, c)
|
}(ctx, c)
|
||||||
|
|
||||||
applierEvents := runCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
applierEvents := e2eutil.RunCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
||||||
EmitStatusEvents: false,
|
EmitStatusEvents: false,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|
@ -221,10 +223,10 @@ func namespaceFilterTest(ctx context.Context, c client.Client, invConfig Invento
|
||||||
Expect(testutil.EventsToExpEvents(applierEvents)).To(testutil.Equal(expEvents))
|
Expect(testutil.EventsToExpEvents(applierEvents)).To(testutil.Equal(expEvents))
|
||||||
|
|
||||||
By("verify namespace1 created")
|
By("verify namespace1 created")
|
||||||
assertUnstructuredExists(ctx, c, namespace1Obj)
|
e2eutil.AssertUnstructuredExists(ctx, c, namespace1Obj)
|
||||||
|
|
||||||
By("verify podB created and ready")
|
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")
|
podIP, found, err := object.NestedField(result.Object, "status", "podIP")
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(found).To(BeTrue())
|
Expect(found).To(BeTrue())
|
||||||
|
|
@ -235,7 +237,7 @@ func namespaceFilterTest(ctx context.Context, c client.Client, invConfig Invento
|
||||||
podBObj,
|
podBObj,
|
||||||
}
|
}
|
||||||
|
|
||||||
applierEvents = runCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
applierEvents = e2eutil.RunCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
||||||
EmitStatusEvents: false,
|
EmitStatusEvents: false,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|
@ -395,13 +397,13 @@ func namespaceFilterTest(ctx context.Context, c client.Client, invConfig Invento
|
||||||
Expect(testutil.EventsToExpEvents(applierEvents)).To(testutil.Equal(expEvents))
|
Expect(testutil.EventsToExpEvents(applierEvents)).To(testutil.Equal(expEvents))
|
||||||
|
|
||||||
By("verify namespace1 not deleted")
|
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")
|
ts, found, err := object.NestedField(result.Object, "metadata", "deletionTimestamp")
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(found).To(BeFalse(), "deletionTimestamp found: ", ts)
|
Expect(found).To(BeFalse(), "deletionTimestamp found: ", ts)
|
||||||
|
|
||||||
By("verify podB not deleted")
|
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")
|
ts, found, err = object.NestedField(result.Object, "metadata", "deletionTimestamp")
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(found).To(BeFalse(), "deletionTimestamp found: ", ts)
|
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/inventory"
|
||||||
"sigs.k8s.io/cli-utils/pkg/object"
|
"sigs.k8s.io/cli-utils/pkg/object"
|
||||||
"sigs.k8s.io/cli-utils/pkg/testutil"
|
"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"
|
"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")
|
By("apply a single resource, which is referenced in the inventory")
|
||||||
applier := invConfig.ApplierFactoryFunc()
|
applier := invConfig.ApplierFactoryFunc()
|
||||||
|
|
||||||
inventoryID := fmt.Sprintf("%s-%s", inventoryName, namespaceName)
|
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{
|
resource1 := []*unstructured.Unstructured{
|
||||||
pod1Obj,
|
pod1Obj,
|
||||||
}
|
}
|
||||||
|
|
||||||
applierEvents := runCollect(applier.Run(ctx, inv, resource1, apply.ApplierOptions{
|
applierEvents := e2eutil.RunCollect(applier.Run(ctx, inv, resource1, apply.ApplierOptions{
|
||||||
EmitStatusEvents: false,
|
EmitStatusEvents: false,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|
@ -145,7 +147,7 @@ func pruneRetrieveErrorTest(ctx context.Context, c client.Client, invConfig Inve
|
||||||
Expect(testutil.EventsToExpEvents(applierEvents)).To(testutil.Equal(expEvents))
|
Expect(testutil.EventsToExpEvents(applierEvents)).To(testutil.Equal(expEvents))
|
||||||
|
|
||||||
By("Verify pod1 created and ready")
|
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")
|
podIP, found, err := object.NestedField(result.Object, "status", "podIP")
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(found).To(BeTrue())
|
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.
|
// Delete the previously applied resource, which is referenced in the inventory.
|
||||||
By("delete 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")
|
By("Verify inventory")
|
||||||
// The inventory should still have the previously deleted item.
|
// The inventory should still have the previously deleted item.
|
||||||
invConfig.InvSizeVerifyFunc(ctx, c, inventoryName, namespaceName, inventoryID, 1, 1)
|
invConfig.InvSizeVerifyFunc(ctx, c, inventoryName, namespaceName, inventoryID, 1, 1)
|
||||||
|
|
||||||
By("apply a different resource, and validate the inventory accurately reflects only this object")
|
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{
|
resource2 := []*unstructured.Unstructured{
|
||||||
pod2Obj,
|
pod2Obj,
|
||||||
}
|
}
|
||||||
|
|
||||||
applierEvents2 := runCollect(applier.Run(ctx, inv, resource2, apply.ApplierOptions{
|
applierEvents2 := e2eutil.RunCollect(applier.Run(ctx, inv, resource2, apply.ApplierOptions{
|
||||||
EmitStatusEvents: false,
|
EmitStatusEvents: false,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|
@ -280,14 +282,14 @@ func pruneRetrieveErrorTest(ctx context.Context, c client.Client, invConfig Inve
|
||||||
Expect(testutil.EventsToExpEvents(applierEvents2)).To(testutil.Equal(expEvents2))
|
Expect(testutil.EventsToExpEvents(applierEvents2)).To(testutil.Equal(expEvents2))
|
||||||
|
|
||||||
By("Verify pod2 created and ready")
|
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")
|
podIP, found, err = object.NestedField(result.Object, "status", "podIP")
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(found).To(BeTrue())
|
Expect(found).To(BeTrue())
|
||||||
Expect(podIP).NotTo(BeEmpty()) // use podIP as proxy for readiness
|
Expect(podIP).NotTo(BeEmpty()) // use podIP as proxy for readiness
|
||||||
|
|
||||||
By("Verify pod1 still deleted")
|
By("Verify pod1 still deleted")
|
||||||
assertUnstructuredDoesNotExist(ctx, c, pod1Obj)
|
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, pod1Obj)
|
||||||
|
|
||||||
By("Verify inventory")
|
By("Verify inventory")
|
||||||
// The inventory should only have the currently applied item.
|
// 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()
|
destroyer := invConfig.DestroyerFactoryFunc()
|
||||||
|
|
||||||
options := apply.DestroyerOptions{InventoryPolicy: inventory.PolicyAdoptIfNoInventory}
|
options := apply.DestroyerOptions{InventoryPolicy: inventory.PolicyAdoptIfNoInventory}
|
||||||
destroyerEvents := runCollect(destroyer.Run(ctx, inv, options))
|
destroyerEvents := e2eutil.RunCollect(destroyer.Run(ctx, inv, options))
|
||||||
|
|
||||||
expEvents3 := []testutil.ExpEvent{
|
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))
|
Expect(testutil.EventsToExpEvents(destroyerEvents)).To(testutil.Equal(expEvents3))
|
||||||
|
|
||||||
By("Verify pod1 is deleted")
|
By("Verify pod1 is deleted")
|
||||||
assertUnstructuredDoesNotExist(ctx, c, pod1Obj)
|
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, pod1Obj)
|
||||||
|
|
||||||
By("Verify pod2 is deleted")
|
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/apply/event"
|
||||||
"sigs.k8s.io/cli-utils/pkg/object"
|
"sigs.k8s.io/cli-utils/pkg/object"
|
||||||
"sigs.k8s.io/cli-utils/pkg/testutil"
|
"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")
|
By("Apply resources")
|
||||||
applier := invConfig.ApplierFactoryFunc()
|
applier := invConfig.ApplierFactoryFunc()
|
||||||
inventoryID := fmt.Sprintf("%s-%s", inventoryName, namespaceName)
|
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{
|
resources := []*unstructured.Unstructured{
|
||||||
podObj,
|
podObj,
|
||||||
}
|
}
|
||||||
|
|
||||||
applierEvents := runCollect(applier.Run(ctx, inventoryInfo, resources, apply.ApplierOptions{
|
applierEvents := e2eutil.RunCollect(applier.Run(ctx, inventoryInfo, resources, apply.ApplierOptions{
|
||||||
ReconcileTimeout: 2 * time.Minute,
|
ReconcileTimeout: 2 * time.Minute,
|
||||||
EmitStatusEvents: false,
|
EmitStatusEvents: false,
|
||||||
}))
|
}))
|
||||||
|
|
@ -40,19 +42,19 @@ func reconciliationFailed(ctx context.Context, invConfig InventoryConfig, invent
|
||||||
Expect(received).To(testutil.Equal(expEvents))
|
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")
|
By("Apply resources")
|
||||||
applier := invConfig.ApplierFactoryFunc()
|
applier := invConfig.ApplierFactoryFunc()
|
||||||
inventoryID := fmt.Sprintf("%s-%s", inventoryName, namespaceName)
|
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{
|
resources := []*unstructured.Unstructured{
|
||||||
podObj,
|
podObj,
|
||||||
}
|
}
|
||||||
|
|
||||||
applierEvents := runCollect(applier.Run(ctx, inventoryInfo, resources, apply.ApplierOptions{
|
applierEvents := e2eutil.RunCollect(applier.Run(ctx, inventoryInfo, resources, apply.ApplierOptions{
|
||||||
ReconcileTimeout: 30 * time.Second,
|
ReconcileTimeout: 30 * time.Second,
|
||||||
EmitStatusEvents: false,
|
EmitStatusEvents: false,
|
||||||
}))
|
}))
|
||||||
|
|
|
||||||
|
|
@ -14,20 +14,22 @@ import (
|
||||||
"sigs.k8s.io/cli-utils/pkg/apply"
|
"sigs.k8s.io/cli-utils/pkg/apply"
|
||||||
"sigs.k8s.io/cli-utils/pkg/common"
|
"sigs.k8s.io/cli-utils/pkg/common"
|
||||||
"sigs.k8s.io/cli-utils/pkg/object"
|
"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"
|
"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")
|
By("Apply a Deployment and an APIService by server-side apply")
|
||||||
applier := invConfig.ApplierFactoryFunc()
|
applier := invConfig.ApplierFactoryFunc()
|
||||||
|
|
||||||
inv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(inventoryName, namespaceName, "test"))
|
inv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(inventoryName, namespaceName, "test"))
|
||||||
firstResources := []*unstructured.Unstructured{
|
firstResources := []*unstructured.Unstructured{
|
||||||
withNamespace(manifestToUnstructured(deployment1), namespaceName),
|
e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(deployment1), namespaceName),
|
||||||
manifestToUnstructured(apiservice1),
|
e2eutil.ManifestToUnstructured(apiservice1),
|
||||||
}
|
}
|
||||||
|
|
||||||
runWithNoErr(applier.Run(ctx, inv, firstResources, apply.ApplierOptions{
|
e2eutil.RunWithNoErr(applier.Run(ctx, inv, firstResources, apply.ApplierOptions{
|
||||||
ReconcileTimeout: 2 * time.Minute,
|
ReconcileTimeout: 2 * time.Minute,
|
||||||
EmitStatusEvents: true,
|
EmitStatusEvents: true,
|
||||||
ServerSideOptions: common.ServerSideOptions{
|
ServerSideOptions: common.ServerSideOptions{
|
||||||
|
|
@ -38,7 +40,7 @@ func serversideApplyTest(ctx context.Context, c client.Client, invConfig Invento
|
||||||
}))
|
}))
|
||||||
|
|
||||||
By("Verify deployment is server-side applied")
|
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.
|
// 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)
|
_, 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"))
|
Expect(manager).To(Equal("test"))
|
||||||
|
|
||||||
By("Verify APIService is server-side applied")
|
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.
|
// 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)
|
_, 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/mutation"
|
||||||
"sigs.k8s.io/cli-utils/pkg/object/validation"
|
"sigs.k8s.io/cli-utils/pkg/object/validation"
|
||||||
"sigs.k8s.io/cli-utils/pkg/testutil"
|
"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"
|
"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")
|
By("apply valid objects and skip invalid objects")
|
||||||
applier := invConfig.ApplierFactoryFunc()
|
applier := invConfig.ApplierFactoryFunc()
|
||||||
|
|
||||||
|
|
@ -32,19 +34,19 @@ func skipInvalidTest(ctx context.Context, c client.Client, invConfig InventoryCo
|
||||||
|
|
||||||
fields := struct{ Namespace string }{Namespace: namespaceName}
|
fields := struct{ Namespace string }{Namespace: namespaceName}
|
||||||
// valid pod
|
// valid pod
|
||||||
pod1Obj := withNamespace(manifestToUnstructured(pod1), namespaceName)
|
pod1Obj := e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod1), namespaceName)
|
||||||
// valid deployment with dependency
|
// 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()))
|
fmt.Sprintf("/namespaces/%s/Pod/%s", namespaceName, pod1Obj.GetName()))
|
||||||
// external/missing dependency
|
// 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))
|
fmt.Sprintf("/namespaces/%s/Pod/pod0", namespaceName))
|
||||||
// cyclic dependency (podB)
|
// cyclic dependency (podB)
|
||||||
podAObj := templateToUnstructured(podATemplate, fields)
|
podAObj := e2eutil.TemplateToUnstructured(podATemplate, fields)
|
||||||
// cyclic dependency (podA) & invalid source reference (dependency not in object set)
|
// cyclic dependency (podA) & invalid source reference (dependency not in object set)
|
||||||
podBObj := templateToUnstructured(invalidMutationPodBTemplate, fields)
|
podBObj := e2eutil.TemplateToUnstructured(invalidMutationPodBTemplate, fields)
|
||||||
// missing name
|
// missing name
|
||||||
invalidPodObj := templateToUnstructured(invalidPodTemplate, fields)
|
invalidPodObj := e2eutil.TemplateToUnstructured(invalidPodTemplate, fields)
|
||||||
|
|
||||||
resources := []*unstructured.Unstructured{
|
resources := []*unstructured.Unstructured{
|
||||||
pod1Obj,
|
pod1Obj,
|
||||||
|
|
@ -55,7 +57,7 @@ func skipInvalidTest(ctx context.Context, c client.Client, invConfig InventoryCo
|
||||||
invalidPodObj,
|
invalidPodObj,
|
||||||
}
|
}
|
||||||
|
|
||||||
applierEvents := runCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
applierEvents := e2eutil.RunCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
|
||||||
EmitStatusEvents: false,
|
EmitStatusEvents: false,
|
||||||
ValidationPolicy: validation.SkipInvalid,
|
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))
|
Expect(testutil.EventsToExpEvents(applierEvents)).To(testutil.Equal(expEvents))
|
||||||
|
|
||||||
By("verify pod1 created and ready")
|
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")
|
podIP, found, err := object.NestedField(result.Object, "status", "podIP")
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(found).To(BeTrue())
|
Expect(found).To(BeTrue())
|
||||||
Expect(podIP).NotTo(BeEmpty()) // use podIP as proxy for readiness
|
Expect(podIP).NotTo(BeEmpty()) // use podIP as proxy for readiness
|
||||||
|
|
||||||
By("verify deployment1 created and ready")
|
By("verify deployment1 created and ready")
|
||||||
result = assertUnstructuredExists(ctx, c, deployment1Obj)
|
result = e2eutil.AssertUnstructuredExists(ctx, c, deployment1Obj)
|
||||||
assertUnstructuredAvailable(result)
|
e2eutil.AssertUnstructuredAvailable(result)
|
||||||
|
|
||||||
By("verify pod3 not found")
|
By("verify pod3 not found")
|
||||||
assertUnstructuredDoesNotExist(ctx, c, pod3Obj)
|
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, pod3Obj)
|
||||||
|
|
||||||
By("verify podA not found")
|
By("verify podA not found")
|
||||||
assertUnstructuredDoesNotExist(ctx, c, podAObj)
|
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, podAObj)
|
||||||
|
|
||||||
By("verify podB not found")
|
By("verify podB not found")
|
||||||
assertUnstructuredDoesNotExist(ctx, c, podBObj)
|
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, podBObj)
|
||||||
|
|
||||||
By("modify deployment1 depends-on annotation to be invalid")
|
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")
|
By("destroy valid objects and skip invalid objects")
|
||||||
destroyer := invConfig.DestroyerFactoryFunc()
|
destroyer := invConfig.DestroyerFactoryFunc()
|
||||||
destroyerEvents := runCollect(destroyer.Run(ctx, inv, apply.DestroyerOptions{
|
destroyerEvents := e2eutil.RunCollect(destroyer.Run(ctx, inv, apply.DestroyerOptions{
|
||||||
InventoryPolicy: inventory.PolicyAdoptIfNoInventory,
|
InventoryPolicy: inventory.PolicyAdoptIfNoInventory,
|
||||||
ValidationPolicy: validation.SkipInvalid,
|
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))
|
Expect(testutil.EventsToExpEvents(destroyerEvents)).To(testutil.Equal(expEvents))
|
||||||
|
|
||||||
By("verify pod1 deleted")
|
By("verify pod1 deleted")
|
||||||
assertUnstructuredDoesNotExist(ctx, c, pod1Obj)
|
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, pod1Obj)
|
||||||
|
|
||||||
By("verify deployment1 not deleted")
|
By("verify deployment1 not deleted")
|
||||||
assertUnstructuredExists(ctx, c, deployment1Obj)
|
e2eutil.AssertUnstructuredExists(ctx, c, deployment1Obj)
|
||||||
deleteUnstructuredIfExists(ctx, c, deployment1Obj)
|
e2eutil.DeleteUnstructuredIfExists(ctx, c, deployment1Obj)
|
||||||
|
|
||||||
By("verify pod3 not found")
|
By("verify pod3 not found")
|
||||||
assertUnstructuredDoesNotExist(ctx, c, pod3Obj)
|
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, pod3Obj)
|
||||||
|
|
||||||
By("verify podA not found")
|
By("verify podA not found")
|
||||||
assertUnstructuredDoesNotExist(ctx, c, podAObj)
|
e2eutil.AssertUnstructuredDoesNotExist(ctx, c, podAObj)
|
||||||
|
|
||||||
By("verify podB not found")
|
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