From 76357930f69041e09d83c3f53c72068bd08c3169 Mon Sep 17 00:00:00 2001 From: Heba Elayoty Date: Thu, 28 Oct 2021 19:15:24 -0700 Subject: [PATCH] Kind Cluster with parameter re-organize test and rename functions use test harness API and remove kubeconfig flag fix linting --- .../kind/kind_with_config/kind-config.yaml | 6 ++ .../kind_with_config/kind_with_config_test.go | 78 +++++++++++++++++++ examples/kind/kind_with_config/main_test.go | 47 +++++++++++ pkg/envfuncs/kind_funcs.go | 25 ++++++ support/kind/kind.go | 45 +++++++++++ 5 files changed, 201 insertions(+) create mode 100644 examples/kind/kind_with_config/kind-config.yaml create mode 100644 examples/kind/kind_with_config/kind_with_config_test.go create mode 100644 examples/kind/kind_with_config/main_test.go diff --git a/examples/kind/kind_with_config/kind-config.yaml b/examples/kind/kind_with_config/kind-config.yaml new file mode 100644 index 00000000..752e993c --- /dev/null +++ b/examples/kind/kind_with_config/kind-config.yaml @@ -0,0 +1,6 @@ +kind: Cluster +apiVersion: kind.x-k8s.io/v1alpha4 +nodes: +- role: control-plane +- role: worker +- role: worker diff --git a/examples/kind/kind_with_config/kind_with_config_test.go b/examples/kind/kind_with_config/kind_with_config_test.go new file mode 100644 index 00000000..c229d013 --- /dev/null +++ b/examples/kind/kind_with_config/kind_with_config_test.go @@ -0,0 +1,78 @@ +/* +Copyright 2021 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package kind + +import ( + "context" + "testing" + "time" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/e2e-framework/pkg/envconf" + "sigs.k8s.io/e2e-framework/pkg/features" +) + +func TestKindCluster(t *testing.T) { + + deploymentFeature := features.New("appsv1/deployment"). + Setup(func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context { + // start a deployment + deployment := newDeployment(cfg.Namespace(), "test-deployment", 1) + if err := cfg.Client().Resources().Create(ctx, deployment); err != nil { + t.Fatal(err) + } + time.Sleep(2 * time.Second) + return ctx + }). + Assess("deployment creation", func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context { + var dep appsv1.Deployment + if err := cfg.Client().Resources().Get(ctx, "test-deployment", cfg.Namespace(), &dep); err != nil { + t.Fatal(err) + } + if &dep != nil { + t.Logf("deployment found: %s", dep.Name) + } + return context.WithValue(ctx, "test-deployment", &dep) + }). + Teardown(func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context { + dep := ctx.Value("test-deployment").(*appsv1.Deployment) + if err := cfg.Client().Resources().Delete(ctx, dep); err != nil { + t.Fatal(err) + } + return ctx + }).Feature() + + testenv.Test(t, deploymentFeature) +} + +func newDeployment(namespace string, name string, replicaCount int32) *appsv1.Deployment { + return &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: namespace, Labels: map[string]string{"app": "test-app"}}, + Spec: appsv1.DeploymentSpec{ + Replicas: &replicaCount, + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"app": "test-app"}, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "test-app"}}, + Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}}, + }, + }, + } +} diff --git a/examples/kind/kind_with_config/main_test.go b/examples/kind/kind_with_config/main_test.go new file mode 100644 index 00000000..ec96eacc --- /dev/null +++ b/examples/kind/kind_with_config/main_test.go @@ -0,0 +1,47 @@ +/* +Copyright 2021 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package kind + +import ( + "os" + "testing" + + "sigs.k8s.io/e2e-framework/pkg/env" + "sigs.k8s.io/e2e-framework/pkg/envconf" + "sigs.k8s.io/e2e-framework/pkg/envfuncs" +) + +var ( + testenv env.Environment +) + +func TestMain(m *testing.M) { + testenv = env.New() + kindClusterName := envconf.RandomName("kind-with-config", 16) + namespace := envconf.RandomName("kind-ns", 16) + + testenv.Setup( + envfuncs.CreateKindClusterWithConfig(kindClusterName, "kindest/node:v1.22.2", "kind-config.yaml"), + envfuncs.CreateNamespace(namespace), + ) + + testenv.Finish( + envfuncs.DeleteNamespace(namespace), + envfuncs.DestroyKindCluster(kindClusterName), + ) + os.Exit(testenv.Run(m)) +} diff --git a/pkg/envfuncs/kind_funcs.go b/pkg/envfuncs/kind_funcs.go index 85e00a7f..61a150b2 100644 --- a/pkg/envfuncs/kind_funcs.go +++ b/pkg/envfuncs/kind_funcs.go @@ -53,6 +53,31 @@ func CreateKindCluster(clusterName string) env.Func { } } +// CreateKindClusterWithConfig returns an env.Func that is used to +// create a kind cluster that is then injected in the context +// using the name as a key. +// +// NOTE: the returned function will update its env config with the +// kubeconfig file for the config client. +// +func CreateKindClusterWithConfig(clusterName, image, configFilePath string) env.Func { + return func(ctx context.Context, cfg *envconf.Config) (context.Context, error) { + k := kind.NewCluster(clusterName) + kubecfg, err := k.CreateWithConfig(image, configFilePath) + if err != nil { + return ctx, err + } + + // stall, wait for pods initializations + time.Sleep(7 * time.Second) + + // update envconfig with kubeconfig + cfg.WithKubeconfigFile(kubecfg) + // store entire cluster value in ctx for future access using the cluster name + return context.WithValue(ctx, kindContextKey(clusterName), k), nil + } +} + // DestroyKindCluster returns an EnvFunc that // retrieves a previously saved kind Cluster in the context (using the name), then deletes it. // diff --git a/support/kind/kind.go b/support/kind/kind.go index 275d868a..bf7460fc 100644 --- a/support/kind/kind.go +++ b/support/kind/kind.go @@ -46,6 +46,51 @@ func (k *Cluster) WithVersion(ver string) *Cluster { return k } +func (k *Cluster) CreateWithConfig(imageName, kindConfigFile string) (string, error) { + log.Println("Creating kind cluster ", k.name) + if err := k.findOrInstallKind(k.e); err != nil { + return "", err + } + + if strings.Contains(k.e.Run("kind get clusters"), k.name) { + log.Println("Skipping Kind Cluster.Create: cluster already created: ", k.name) + return "", nil + } + + log.Println("launching: kind create cluster --name", k.name, "--image", imageName, "--config", kindConfigFile) + p := k.e.RunProc(fmt.Sprintf(`kind create cluster --name %s --image %s --config %s`, k.name, imageName, kindConfigFile)) + if p.Err() != nil { + return "", fmt.Errorf("failed to create kind cluster: %s : %s", p.Err(), p.Result()) + } + + clusters := k.e.Run("kind get clusters") + if !strings.Contains(clusters, k.name) { + return "", fmt.Errorf("kind Cluster.Create: cluster %v still not in 'cluster list' after creation: %v", k.name, clusters) + } + log.Println("kind clusters available: ", clusters) + + // Grab kubeconfig file for cluster. + kubecfg := fmt.Sprintf("%s-kubecfg", k.name) + p = k.e.RunProc(fmt.Sprintf(`kind get kubeconfig --name %s`, k.name)) + if p.Err() != nil { + return "", fmt.Errorf("kind get kubeconfig: %s: %w", p.Result(), p.Err()) + } + + file, err := ioutil.TempFile("", fmt.Sprintf("kind-cluser-%s", kubecfg)) + if err != nil { + return "", fmt.Errorf("kind kubeconfig file: %w", err) + } + defer file.Close() + + k.kubecfgFile = file.Name() + + if n, err := io.Copy(file, strings.NewReader(p.Result())); n == 0 || err != nil { + return "", fmt.Errorf("kind kubecfg file: bytes copied: %d: %w]", n, err) + } + + return file.Name(), nil +} + func (k *Cluster) Create() (string, error) { log.Println("Creating kind cluster ", k.name) if err := k.findOrInstallKind(k.e); err != nil {