From 04ae8e9b2e8d1a566d5ee4fd3d25114917ded198 Mon Sep 17 00:00:00 2001 From: justinsb Date: Tue, 14 Mar 2023 16:43:55 +0000 Subject: [PATCH] kubectl prunev2: simple e2e/integration test Starting with the most basic e2e test, checking that we can create and prune configmaps. --- test/e2e/kubectl/kubectl.go | 97 +++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/test/e2e/kubectl/kubectl.go b/test/e2e/kubectl/kubectl.go index d3eca7ad274..bfedbcadf76 100644 --- a/test/e2e/kubectl/kubectl.go +++ b/test/e2e/kubectl/kubectl.go @@ -38,6 +38,7 @@ import ( "time" openapi_v2 "github.com/google/gnostic/openapiv2" + "github.com/google/go-cmp/cmp" "sigs.k8s.io/yaml" @@ -45,9 +46,11 @@ import ( rbacv1 "k8s.io/api/rbac/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" utilnet "k8s.io/apimachinery/pkg/util/net" utilnettesting "k8s.io/apimachinery/pkg/util/net/testing" @@ -846,6 +849,65 @@ metadata: }) }) + ginkgo.Describe("Kubectl prune with applyset", func() { + ginkgo.It("should apply and prune objects", func(ctx context.Context) { + framework.Logf("applying manifest1") + manifest1 := ` +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm1 + namespace: {{ns}} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm2 + namespace: {{ns}} +` + + manifest1 = strings.ReplaceAll(manifest1, "{{ns}}", ns) + args := []string{"apply", "--prune", "--applyset=applyset1", "-f", "-"} + e2ekubectl.NewKubectlCommand(ns, args...).WithEnv([]string{"KUBECTL_APPLYSET=true"}).WithStdinData(manifest1).ExecOrDie(ns) + + framework.Logf("checking which objects exist") + objects := mustListObjectsInNamespace(ctx, c, ns) + names := mustGetNames(objects) + if diff := cmp.Diff(names, []string{"cm1", "cm2"}); diff != "" { + framework.Failf("unexpected configmap names (-want +got):\n%s", diff) + } + + framework.Logf("applying manifest2") + manifest2 := ` +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm1 + namespace: {{ns}} +` + manifest2 = strings.ReplaceAll(manifest2, "{{ns}}", ns) + + e2ekubectl.NewKubectlCommand(ns, args...).WithEnv([]string{"KUBECTL_APPLYSET=true"}).WithStdinData(manifest2).ExecOrDie(ns) + + framework.Logf("checking which objects exist") + objects = mustListObjectsInNamespace(ctx, c, ns) + names = mustGetNames(objects) + if diff := cmp.Diff(names, []string{"cm1"}); diff != "" { + framework.Failf("unexpected configmap names (-want +got):\n%s", diff) + } + + framework.Logf("applying manifest2 (again)") + e2ekubectl.NewKubectlCommand(ns, args...).WithEnv([]string{"KUBECTL_APPLYSET=true"}).WithStdinData(manifest2).ExecOrDie(ns) + + framework.Logf("checking which objects exist") + objects = mustListObjectsInNamespace(ctx, c, ns) + names = mustGetNames(objects) + if diff := cmp.Diff(names, []string{"cm1"}); diff != "" { + framework.Failf("unexpected configmap names (-want +got):\n%s", diff) + } + }) + }) + ginkgo.Describe("Kubectl apply", func() { ginkgo.It("should apply a new configuration to an existing RC", func(ctx context.Context) { controllerJSON := commonutils.SubstituteImageName(string(readTestFileOrDie(agnhostControllerFilename))) @@ -2349,3 +2411,38 @@ waitLoop: // Reaching here means that one of more checks failed multiple times. Assuming its not a race condition, something is broken. framework.Failf("Timed out after %v seconds waiting for %s pods to reach valid state", framework.PodStartTimeout.Seconds(), testname) } + +// mustListObjectsInNamespace queries all the objects we use for testing in the given namespace. +// Currently this is just ConfigMaps. +// We filter our "system" configmaps, like "kube-root-ca.crt". +func mustListObjectsInNamespace(ctx context.Context, c clientset.Interface, ns string) []runtime.Object { + var objects []runtime.Object + configMaps, err := c.CoreV1().ConfigMaps(ns).List(ctx, metav1.ListOptions{}) + if err != nil { + framework.Failf("error listing configmaps: %v", err) + } + for i := range configMaps.Items { + cm := &configMaps.Items[i] + if cm.Name == "kube-root-ca.crt" { + // Ignore system objects + continue + } + objects = append(objects, cm) + } + return objects +} + +// mustGetNames returns a slice containing the metadata.name for each object. +func mustGetNames(objects []runtime.Object) []string { + var names []string + for _, obj := range objects { + metaAccessor, err := meta.Accessor(obj) + if err != nil { + framework.Failf("error getting accessor for %T: %v", obj, err) + } + name := metaAccessor.GetName() + names = append(names, name) + } + sort.Strings(names) + return names +}