Skip to content

Commit

Permalink
Merge pull request #70 from helayoty/helayoty/kind-cluster-with-param
Browse files Browse the repository at this point in the history
feat: Kind Cluster with Config
  • Loading branch information
k8s-ci-robot authored Nov 5, 2021
2 parents ebed032 + 7635793 commit 8412394
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 0 deletions.
6 changes: 6 additions & 0 deletions examples/kind/kind_with_config/kind-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker
78 changes: 78 additions & 0 deletions examples/kind/kind_with_config/kind_with_config_test.go
Original file line number Diff line number Diff line change
@@ -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"}}},
},
},
}
}
47 changes: 47 additions & 0 deletions examples/kind/kind_with_config/main_test.go
Original file line number Diff line number Diff line change
@@ -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))
}
25 changes: 25 additions & 0 deletions pkg/envfuncs/kind_funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
//
Expand Down
45 changes: 45 additions & 0 deletions support/kind/kind.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down

0 comments on commit 8412394

Please sign in to comment.