diff --git a/examples/real_cluster/README.md b/examples/real_cluster/README.md new file mode 100644 index 00000000..9d659471 --- /dev/null +++ b/examples/real_cluster/README.md @@ -0,0 +1,138 @@ +# Real cluster example (including cloud provider) + +This package shows how the test framework can be used with a real self-managed or cloud vendor managed cluster (AKS/GKE/EKS), since one may want to launch some tests inside the cluster. This example creates a random namespace, deploys simple deployment and if done removes the namespace. + +To properly connect to a cloud provider cluster it is required to import for side effects one of auth modules. If testing on a self-managed cluster there is no need to include these dependencies. +```go + _ "k8s.io/client-go/plugin/pkg/client/auth/azure" // auth for AKS clusters + _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" // auth for GKE clusters + _ "k8s.io/client-go/plugin/pkg/client/auth/oidc" // auth for OIDC (EKS) +``` + +ResolveKubeConfigFile() function is called to get kubeconfig loaded, it uses either `--kubeconfig` flag, `KUBECONFIG` env or by default ` $HOME/.kube/config` path. + +```go +func TestMain(m *testing.M) { + testenv = env.New() + path := conf.ResolveKubeConfigFile() + cfg := envconf.NewWithKubeConfig(path) + testenv = env.NewWithConfig(cfg) +``` + +Later testing is the same as on Kind cluster. + +```go + testenv.Setup( + envfuncs.CreateNamespace(namespace), + ) + testenv.Finish( + envfuncs.DeleteNamespace(namespace), + ) + os.Exit(testenv.Run(m)) +``` + +### AKS Example + +Below you can find a complete example of running a sample test on AKS cluster. Notice that the import block contains auth library for Azure. + +##### main_test.go + +```go + +package e2e + +import ( + _ "k8s.io/client-go/plugin/pkg/client/auth/azure" + "os" + "sigs.k8s.io/e2e-framework/klient/conf" + "sigs.k8s.io/e2e-framework/pkg/env" + "sigs.k8s.io/e2e-framework/pkg/envconf" + "sigs.k8s.io/e2e-framework/pkg/envfuncs" + "testing" +) + +var testenv env.Environment + +func TestMain(m *testing.M) { + testenv = env.New() + path := conf.ResolveKubeConfigFile() + cfg := envconf.NewWithKubeConfig(path) + testenv = env.NewWithConfig(cfg) + namespace := envconf.RandomName("sample-ns", 16) + testenv.Setup( + envfuncs.CreateNamespace(namespace), + ) + testenv.Finish( + envfuncs.DeleteNamespace(namespace), + ) + os.Exit(testenv.Run(m)) +} +``` +##### kind_with_config_test.go + +```go + + +package e2e + +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 TestRealCluster(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/real_cluster/kind_with_config_test.go b/examples/real_cluster/kind_with_config_test.go new file mode 100644 index 00000000..78eb95da --- /dev/null +++ b/examples/real_cluster/kind_with_config_test.go @@ -0,0 +1,77 @@ +/* +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 e2e + +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 TestRealCluster(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/real_cluster/main_test.go b/examples/real_cluster/main_test.go new file mode 100644 index 00000000..01270a0e --- /dev/null +++ b/examples/real_cluster/main_test.go @@ -0,0 +1,63 @@ +/* +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 e2e + +import ( + // If testing with a cloud vendor managed cluster uncomment one of the below dependencies to properly get authorised. + //_ "k8s.io/client-go/plugin/pkg/client/auth/azure" // auth for AKS clusters + //_ "k8s.io/client-go/plugin/pkg/client/auth/gcp" // auth for GKE clusters + //_ "k8s.io/client-go/plugin/pkg/client/auth/oidc" // auth for OIDC + "os" + "sigs.k8s.io/e2e-framework/klient/conf" + "sigs.k8s.io/e2e-framework/pkg/env" + "sigs.k8s.io/e2e-framework/pkg/envconf" + "sigs.k8s.io/e2e-framework/pkg/envfuncs" + "testing" +) + +var testenv env.Environment + +func TestMain(m *testing.M) { + testenv = env.New() + namespace := envconf.RandomName("sample-ns", 16) + if os.Getenv("REAL_CLUSTER") == "true" { + path := conf.ResolveKubeConfigFile() + cfg := envconf.NewWithKubeConfig(path) + testenv = env.NewWithConfig(cfg) + + testenv.Setup( + envfuncs.CreateNamespace(namespace), + ) + testenv.Finish( + envfuncs.DeleteNamespace(namespace), + ) + } else { + kindClusterName := envconf.RandomName("kind-with-config", 16) + + testenv.Setup( + envfuncs.CreateKindCluster(kindClusterName), + envfuncs.CreateNamespace(namespace), + ) + + testenv.Finish( + envfuncs.DeleteNamespace(namespace), + envfuncs.DestroyKindCluster(kindClusterName), + ) + } + + os.Exit(testenv.Run(m)) +}