From fa79e279652a9a8aa5e0fe7c772d8ecb450f98b1 Mon Sep 17 00:00:00 2001 From: Tim Schrodi Date: Thu, 14 Mar 2019 15:36:30 +0100 Subject: [PATCH] Refactor testrunner to use controller-runtime client --- Gopkg.lock | 19 ++- Gopkg.toml | 2 +- .../cmd/runtemplate/run_template.go | 23 ++- cmd/testrunner/cmd/runtestrun/run_testrun.go | 19 ++- pkg/testmachinery/types.go | 21 +++ pkg/testrunner/result/collect.go | 7 +- pkg/testrunner/result/ingest.go | 20 +-- pkg/testrunner/result/output.go | 21 ++- pkg/testrunner/run.go | 15 +- pkg/testrunner/template/render.go | 9 +- pkg/testrunner/template/template.go | 14 +- pkg/testrunner/testrunner.go | 19 +-- pkg/testrunner/types.go | 6 +- .../garbagecollection_test.go | 32 ++-- .../resultcollection/resultcollection_test.go | 46 +++--- .../testdefinition_suite_test.go | 48 +++--- .../testflow/testflow_suite_test.go | 96 ++++++----- .../testrunner_output_execution_test.go | 39 ++--- test/testrunner/run/testrunner_run_test.go | 27 ++- test/utils/utils.go | 32 ++-- .../testrun_validation_test.go | 55 ++++--- .../terraformer/charts/terraformer-common | 1 - .../charts/terraformer/charts/utils-templates | 1 - .../charts/original/charts/utils-templates | 1 - .../gardener/pkg/apis/garden/types.go | 30 +++- .../pkg/apis/garden/v1beta1/defaults.go | 13 +- .../gardener/pkg/apis/garden/v1beta1/types.go | 38 ++++- .../garden/v1beta1/zz_generated.conversion.go | 4 + .../garden/v1beta1/zz_generated.deepcopy.go | 10 ++ .../pkg/apis/garden/zz_generated.deepcopy.go | 10 ++ .../gardener/pkg/chartrenderer/default.go | 6 +- .../gardener/pkg/client/kubernetes/apply.go | 154 ++++++++++++------ .../gardener/pkg/client/kubernetes/client.go | 43 ++--- .../pkg/client/kubernetes/clientset.go | 10 -- .../pkg/client/kubernetes/deployments.go | 29 ---- .../gardener/pkg/client/kubernetes/pods.go | 92 +++++++++-- .../gardener/pkg/client/kubernetes/types.go | 33 ++-- .../machine/v1alpha1/generated_expansion.go | 2 + .../typed/machine/v1alpha1/machine.go | 17 ++ .../typed/machine/v1alpha1/machine_client.go | 5 + .../gardener/gardener/pkg/logger/logger.go | 7 + .../pkg/utils/kubernetes/kubernetes.go | 70 +++++++- .../apimachinery/pkg/apis/config/doc.go | 19 --- .../apimachinery/pkg/apis/config/types.go | 33 ---- .../pkg/apis/config/zz_generated.deepcopy.go | 37 ----- 45 files changed, 716 insertions(+), 519 deletions(-) delete mode 120000 vendor/github.com/gardener/gardener/charts/seed-terraformer/charts/terraformer/charts/terraformer-common delete mode 120000 vendor/github.com/gardener/gardener/charts/seed-terraformer/charts/terraformer/charts/utils-templates delete mode 120000 vendor/github.com/gardener/gardener/charts/shoot-cloud-config/charts/original/charts/utils-templates delete mode 100644 vendor/k8s.io/apimachinery/pkg/apis/config/doc.go delete mode 100644 vendor/k8s.io/apimachinery/pkg/apis/config/types.go delete mode 100644 vendor/k8s.io/apimachinery/pkg/apis/config/zz_generated.deepcopy.go diff --git a/Gopkg.lock b/Gopkg.lock index 54cbb67f85..b27bff40a9 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -126,17 +126,20 @@ version = "v2.8.1" [[projects]] - digest = "1:cd416c63f1c2d80ce6ba41ede17f2d4c61c4f98257db342066a8e92c99d03471" + digest = "1:23ae19f1ae067e50086d1c224fb8cb78e46ff60ef3d2d82c194a61d1a4b7d508" name = "github.com/gardener/gardener" packages = [ "pkg/apis/core", "pkg/apis/core/v1alpha1", + "pkg/apis/extensions", + "pkg/apis/extensions/v1alpha1", "pkg/apis/garden", "pkg/apis/garden/v1beta1", "pkg/chartrenderer", "pkg/client/core/clientset/versioned", "pkg/client/core/clientset/versioned/scheme", "pkg/client/core/clientset/versioned/typed/core/v1alpha1", + "pkg/client/extensions/clientset/versioned/scheme", "pkg/client/garden/clientset/versioned", "pkg/client/garden/clientset/versioned/scheme", "pkg/client/garden/clientset/versioned/typed/garden/v1beta1", @@ -150,8 +153,8 @@ "pkg/utils/kubernetes/health", ] pruneopts = "NUT" - revision = "400b0dc2072974264873dfcf2ce2b6a261319061" - version = "0.17.1" + revision = "4fdf8d7bad282404d6b158e56778027b1723a1b1" + version = "0.19.0" [[projects]] digest = "1:45ef8724981e1412df2734c5af2c75775e94d8efa5289ff24c06010476380b35" @@ -905,14 +908,13 @@ revision = "cf30b7cf64c2979f27127ba17706f30a3489337c" [[projects]] - digest = "1:38842bf323d0f82fa0c69e1c687fb24bf966ac891f57bc98f62c25af679e3520" + digest = "1:177a717548eae47d6c848b4c3f09e4017ade53059d25fe27be0613ffc80bd9e9" name = "k8s.io/apimachinery" packages = [ "pkg/api/equality", "pkg/api/errors", "pkg/api/meta", "pkg/api/resource", - "pkg/apis/config", "pkg/apis/meta/internalversion", "pkg/apis/meta/v1", "pkg/apis/meta/v1/unstructured", @@ -944,6 +946,7 @@ "pkg/util/naming", "pkg/util/net", "pkg/util/rand", + "pkg/util/remotecommand", "pkg/util/runtime", "pkg/util/sets", "pkg/util/strategicpatch", @@ -963,7 +966,7 @@ version = "kubernetes-1.12.1" [[projects]] - digest = "1:e93f52a99cce1849b402315d38c47bc1cd2e6feacc658f963c8246354767e2a9" + digest = "1:f77fd462adf1e74eba8f6b0e57473be4bf56076fbd487754dfbef7a64aba179c" name = "k8s.io/client-go" packages = [ "discovery", @@ -1025,11 +1028,13 @@ "tools/portforward", "tools/record", "tools/reference", + "tools/remotecommand", "transport", "transport/spdy", "util/buffer", "util/cert", "util/connrotation", + "util/exec", "util/flowcontrol", "util/homedir", "util/integer", @@ -1196,6 +1201,7 @@ "github.com/Masterminds/semver", "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1", "github.com/argoproj/argo/pkg/client/clientset/versioned", + "github.com/argoproj/argo/pkg/client/clientset/versioned/scheme", "github.com/gardener/gardener/pkg/apis/garden/v1beta1", "github.com/gardener/gardener/pkg/chartrenderer", "github.com/gardener/gardener/pkg/client/kubernetes", @@ -1228,6 +1234,7 @@ "k8s.io/apimachinery/pkg/watch", "k8s.io/client-go/discovery", "k8s.io/client-go/discovery/fake", + "k8s.io/client-go/kubernetes/scheme", "k8s.io/client-go/rest", "k8s.io/client-go/testing", "k8s.io/client-go/tools/cache", diff --git a/Gopkg.toml b/Gopkg.toml index 7298b607cf..703c3848a1 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -10,7 +10,7 @@ required = [ [[constraint]] name = "github.com/gardener/gardener" - version = "^0.17.0" + version = "^0.19.0" [[override]] name = "github.com/gardener/machine-controller-manager" diff --git a/cmd/testrunner/cmd/runtemplate/run_template.go b/cmd/testrunner/cmd/runtemplate/run_template.go index 77b8a3bb35..2c15487bf7 100644 --- a/cmd/testrunner/cmd/runtemplate/run_template.go +++ b/cmd/testrunner/cmd/runtemplate/run_template.go @@ -18,6 +18,10 @@ import ( "fmt" "os" + "github.com/gardener/gardener/pkg/client/kubernetes" + "github.com/gardener/test-infra/pkg/testmachinery" + "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/gardener/test-infra/pkg/testrunner" "github.com/gardener/test-infra/pkg/testrunner/result" testrunnerTemplate "github.com/gardener/test-infra/pkg/testrunner/template" @@ -87,12 +91,19 @@ var runCmd = &cobra.Command{ log.Debugf("Error loading .env file: %s", err.Error()) } + tmClient, err := kubernetes.NewClientFromFile("", tmKubeconfigPath, client.Options{ + Scheme: testmachinery.TestMachineryScheme, + }) + if err != nil { + log.Fatalf("Cannot build kubernetes client from %s: %s", tmKubeconfigPath, err.Error()) + } + testrunName := fmt.Sprintf("%s-%s-", testrunNamePrefix, cloudprovider) config := &testrunner.Config{ - TmKubeconfigPath: tmKubeconfigPath, - Namespace: namespace, - Timeout: timeout, - Interval: interval, + TmClient: tmClient, + Namespace: namespace, + Timeout: timeout, + Interval: interval, } rsConfig := &result.Config{ @@ -129,13 +140,13 @@ var runCmd = &cobra.Command{ CloudProvider: parameters.Cloudprovider, KubernetesVersion: parameters.K8sVersion, } - testruns, err := testrunnerTemplate.Render(config.TmKubeconfigPath, parameters, metadata) + testruns, err := testrunnerTemplate.Render(tmClient, parameters, metadata) if err != nil { log.Fatal(err) } finishedTestruns, err := testrunner.Run(config, testruns, testrunName) - failed, err := result.Collect(rsConfig, config.TmKubeconfigPath, config.Namespace, finishedTestruns, metadata) + failed, err := result.Collect(rsConfig, tmClient, config.Namespace, finishedTestruns, metadata) if err != nil { log.Fatal(err) } diff --git a/cmd/testrunner/cmd/runtestrun/run_testrun.go b/cmd/testrunner/cmd/runtestrun/run_testrun.go index 2cd6459af9..953455277b 100644 --- a/cmd/testrunner/cmd/runtestrun/run_testrun.go +++ b/cmd/testrunner/cmd/runtestrun/run_testrun.go @@ -17,6 +17,10 @@ package runtestrun import ( "fmt" + "github.com/gardener/gardener/pkg/client/kubernetes" + "github.com/gardener/test-infra/pkg/testmachinery" + "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/gardener/test-infra/pkg/util" "github.com/joho/godotenv" @@ -64,11 +68,18 @@ var runTestrunCmd = &cobra.Command{ log.Debugf("Error loading .env file: %s", err.Error()) } + tmClient, err := kubernetes.NewClientFromFile("", tmKubeconfigPath, client.Options{ + Scheme: testmachinery.TestMachineryScheme, + }) + if err != nil { + log.Fatalf("Cannot build kubernetes client from %s: %s", tmKubeconfigPath, err.Error()) + } + config := &testrunner.Config{ - TmKubeconfigPath: tmKubeconfigPath, - Namespace: namespace, - Timeout: timeout, - Interval: interval, + TmClient: tmClient, + Namespace: namespace, + Timeout: timeout, + Interval: interval, } tr, err := util.ParseTestrunFromFile(testrunPath) diff --git a/pkg/testmachinery/types.go b/pkg/testmachinery/types.go index a3d796fecf..6a82173c35 100644 --- a/pkg/testmachinery/types.go +++ b/pkg/testmachinery/types.go @@ -14,6 +14,14 @@ package testmachinery +import ( + argoscheme "github.com/argoproj/argo/pkg/client/clientset/versioned/scheme" + tmscheme "github.com/gardener/test-infra/pkg/client/testmachinery/clientset/versioned/scheme" + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + corescheme "k8s.io/client-go/kubernetes/scheme" +) + const ( // TM_KUBECONFIG_PATH is the path where kubeconfigs are mounted to tests. TM_KUBECONFIG_PATH = "/tmp/env/kubeconfig" @@ -82,3 +90,16 @@ type TechnicalUser struct { Password string `yaml:"password"` AuthToken string `yaml:"authToken"` } + +// TestMachineryScheme is the scheme used in the testmachinery and testrunner. +var TestMachineryScheme = runtime.NewScheme() + +func init() { + testmachinerySchemeBuilder := runtime.NewSchemeBuilder( + corescheme.AddToScheme, + tmscheme.AddToScheme, + argoscheme.AddToScheme, + ) + + utilruntime.Must(testmachinerySchemeBuilder.AddToScheme(TestMachineryScheme)) +} diff --git a/pkg/testrunner/result/collect.go b/pkg/testrunner/result/collect.go index 603976ef80..b747959b47 100644 --- a/pkg/testrunner/result/collect.go +++ b/pkg/testrunner/result/collect.go @@ -17,6 +17,7 @@ package result import ( "fmt" + "github.com/gardener/gardener/pkg/client/kubernetes" tmv1beta1 "github.com/gardener/test-infra/pkg/apis/testmachinery/v1beta1" "github.com/gardener/test-infra/pkg/util" log "github.com/sirupsen/logrus" @@ -24,10 +25,10 @@ import ( // Collect collects results of all testruns and write them to a file. // It returns wheter there are failed testruns or not. -func Collect(config *Config, tmKubeconfigPath, namespace string, testruns []*tmv1beta1.Testrun, metadata *Metadata) (bool, error) { +func Collect(config *Config, tmClient kubernetes.Interface, namespace string, testruns []*tmv1beta1.Testrun, metadata *Metadata) (bool, error) { testrunsFailed := false for _, tr := range testruns { - err := Output(config, tmKubeconfigPath, namespace, tr, metadata) + err := Output(config, tmClient, namespace, tr, metadata) if err != nil { return false, err } @@ -36,7 +37,7 @@ func Collect(config *Config, tmKubeconfigPath, namespace string, testruns []*tmv if err != nil { log.Errorf("Cannot persist file %s: %s", config.OutputFile, err.Error()) } else { - err := MarkTestrunsAsIngested(tmKubeconfigPath, testruns) + err := MarkTestrunsAsIngested(tmClient, testruns) if err != nil { log.Warn(err.Error()) } diff --git a/pkg/testrunner/result/ingest.go b/pkg/testrunner/result/ingest.go index 13344d8c6c..1522c3ca3a 100644 --- a/pkg/testrunner/result/ingest.go +++ b/pkg/testrunner/result/ingest.go @@ -15,14 +15,14 @@ package result import ( - "fmt" + "context" "os" "os/exec" + "github.com/gardener/gardener/pkg/client/kubernetes" + tmv1beta1 "github.com/gardener/test-infra/pkg/apis/testmachinery/v1beta1" - tmclientset "github.com/gardener/test-infra/pkg/client/testmachinery/clientset/versioned" log "github.com/sirupsen/logrus" - "k8s.io/client-go/tools/clientcmd" ) const ( @@ -46,18 +46,12 @@ func IngestFile(file, esCfgName string) error { } // MarkTestrunsAsIngested sets the ingest status of testruns to true -func MarkTestrunsAsIngested(tmKubeconfigPath string, testruns []*tmv1beta1.Testrun) error { - tmConfig, err := clientcmd.BuildConfigFromFlags("", tmKubeconfigPath) - if err != nil { - return fmt.Errorf("Cannot build kubernetes client from %s: %s", tmKubeconfigPath, err.Error()) - } - tmClient, err := tmclientset.NewForConfig(tmConfig) - if err != nil { - return fmt.Errorf("Canno build testmachinery kubernetes client: %s", err.Error()) - } +func MarkTestrunsAsIngested(tmClient kubernetes.Interface, testruns []*tmv1beta1.Testrun) error { + ctx := context.Background() + defer ctx.Done() for _, tr := range testruns { tr.Status.Ingested = true - _, err := tmClient.Testmachinery().Testruns(tr.Namespace).UpdateStatus(tr) + err := tmClient.Client().Update(ctx, tr) if err != nil { log.Errorf("Cannot update status off testrun %s in namespace %s: %s", tr.Name, tr.Namespace, err.Error()) continue diff --git a/pkg/testrunner/result/output.go b/pkg/testrunner/result/output.go index 97f2ddb673..8206bb22cc 100644 --- a/pkg/testrunner/result/output.go +++ b/pkg/testrunner/result/output.go @@ -18,6 +18,7 @@ import ( "archive/tar" "bytes" "compress/gzip" + "context" "encoding/json" "fmt" "io" @@ -33,10 +34,11 @@ import ( tmv1beta1 "github.com/gardener/test-infra/pkg/apis/testmachinery/v1beta1" minio "github.com/minio/minio-go" log "github.com/sirupsen/logrus" + corev1 "k8s.io/api/core/v1" ) // Output takes a completed testrun status and writes the results to elastic search bulk json file. -func Output(config *Config, tmKubeconfigPath, namespace string, tr *tmv1beta1.Testrun, metadata *Metadata) error { +func Output(config *Config, tmClient kubernetes.Interface, namespace string, tr *tmv1beta1.Testrun, metadata *Metadata) error { if config.OutputFile == "" { return nil } @@ -58,7 +60,7 @@ func Output(config *Config, tmKubeconfigPath, namespace string, tr *tmv1beta1.Te return err } - osConfig, err := getOSConfig(tmKubeconfigPath, namespace, config.S3Endpoint, config.S3SSL) + osConfig, err := getOSConfig(tmClient, namespace, config.S3Endpoint, config.S3SSL) if err != nil { log.Warnf("Cannot get exported Test results of steps: %s", err.Error()) } else { @@ -225,16 +227,17 @@ func writeToFile(fielPath string, data []byte) error { return nil } -func getOSConfig(tmKubeconfigPath, namespace, minioEndpoint string, ssl bool) (*testmachinery.ObjectStoreConfig, error) { - clusterClient, err := kubernetes.NewClientFromFile(tmKubeconfigPath, nil, client.Options{}) - if err != nil { - return nil, fmt.Errorf("Cannot create client for %s: %s", tmKubeconfigPath, err.Error()) - } - minioConfig, err := clusterClient.GetConfigMap(namespace, "tm-config") +func getOSConfig(tmClient kubernetes.Interface, namespace, minioEndpoint string, ssl bool) (*testmachinery.ObjectStoreConfig, error) { + ctx := context.Background() + defer ctx.Done() + + minioConfig := &corev1.ConfigMap{} + err := tmClient.Client().Get(ctx, client.ObjectKey{Namespace: namespace, Name: "tm-config"}, minioConfig) if err != nil { return nil, fmt.Errorf("Cannot get ConfigMap 'tm-config': %s", err.Error()) } - minioSecrets, err := clusterClient.GetSecret(namespace, minioConfig.Data["objectstore.secretName"]) + minioSecrets := &corev1.Secret{} + err = tmClient.Client().Get(ctx, client.ObjectKey{Namespace: namespace, Name: minioConfig.Data["objectstore.secretName"]}, minioSecrets) if err != nil { return nil, fmt.Errorf("Cannot get Secret '%s': %s", minioConfig.Data["objectstore.secretName"], err.Error()) } diff --git a/pkg/testrunner/run.go b/pkg/testrunner/run.go index 9a59a86691..52dd95f722 100644 --- a/pkg/testrunner/run.go +++ b/pkg/testrunner/run.go @@ -15,23 +15,28 @@ package testrunner import ( + "context" "fmt" "time" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/gardener/gardener/pkg/client/kubernetes" + tmv1beta1 "github.com/gardener/test-infra/pkg/apis/testmachinery/v1beta1" - tmclientset "github.com/gardener/test-infra/pkg/client/testmachinery/clientset/versioned" "github.com/gardener/test-infra/pkg/util" log "github.com/sirupsen/logrus" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/wait" ) -func runTestrun(tmClient *tmclientset.Clientset, tr *tmv1beta1.Testrun, namespace, name string) (*tmv1beta1.Testrun, error) { +func runTestrun(tmClient kubernetes.Interface, tr *tmv1beta1.Testrun, namespace, name string) (*tmv1beta1.Testrun, error) { + ctx := context.Background() + defer ctx.Done() // TODO: Remove legacy name attribute. Instead enforce usage of generateName. tr.Name = "" tr.GenerateName = name tr.Namespace = namespace - tr, err := tmClient.Testmachinery().Testruns(namespace).Create(tr) + err := tmClient.Client().Create(ctx, tr) if err != nil { return nil, fmt.Errorf("Cannot create testrun: %s", err.Error()) } @@ -41,7 +46,7 @@ func runTestrun(tmClient *tmclientset.Clientset, tr *tmv1beta1.Testrun, namespac interval := time.Duration(pollIntervalSeconds) * time.Second timeout := time.Duration(maxWaitTimeSeconds) * time.Second err = wait.PollImmediate(interval, timeout, func() (bool, error) { - tr, err = tmClient.Testmachinery().Testruns(namespace).Get(tr.Name, metav1.GetOptions{}) + err := tmClient.Client().Get(ctx, client.ObjectKey{Namespace: namespace, Name: tr.Name}, tr) if err != nil { log.Errorf("Cannot get testrun: %s", err.Error()) } diff --git a/pkg/testrunner/template/render.go b/pkg/testrunner/template/render.go index 9dcd9aafda..da819cf68d 100644 --- a/pkg/testrunner/template/render.go +++ b/pkg/testrunner/template/render.go @@ -8,19 +8,14 @@ import ( "github.com/gardener/gardener/pkg/client/kubernetes" "github.com/gardener/test-infra/pkg/util" log "github.com/sirupsen/logrus" - "sigs.k8s.io/controller-runtime/pkg/client" ) // RenderChart renders the provided helm chart with testruns, adds the testrun parameters and returns the templated files. -func RenderChart(tmKubeconfigPath string, parameters *TestrunParameters, versions []string) ([]string, error) { +func RenderChart(tmClient kubernetes.Interface, parameters *TestrunParameters, versions []string) ([]string, error) { log.Debugf("Parameters: %+v", util.PrettyPrintStruct(parameters)) log.Debugf("Render chart from %s", parameters.TestrunChartPath) - tmClusterClient, err := kubernetes.NewClientFromFile(tmKubeconfigPath, nil, client.Options{}) - if err != nil { - return nil, fmt.Errorf("couldn't create k8s client from kubeconfig filepath %s: %v", tmKubeconfigPath, err) - } - tmChartRenderer, err := chartrenderer.New(tmClusterClient) + tmChartRenderer, err := chartrenderer.New(tmClient) if err != nil { return nil, fmt.Errorf("Cannot create chartrenderer for gardener: %s", err.Error()) } diff --git a/pkg/testrunner/template/template.go b/pkg/testrunner/template/template.go index a35956cea5..3d8475d022 100644 --- a/pkg/testrunner/template/template.go +++ b/pkg/testrunner/template/template.go @@ -18,6 +18,7 @@ import ( "fmt" "io/ioutil" + "github.com/gardener/gardener/pkg/client/kubernetes" tmv1beta1 "github.com/gardener/test-infra/pkg/apis/testmachinery/v1beta1" "github.com/gardener/test-infra/pkg/testrunner/componentdescriptor" "github.com/gardener/test-infra/pkg/testrunner/result" @@ -26,7 +27,7 @@ import ( ) // Render renders a helm chart with containing testruns, adds the provided parameters and values, and returns the parsed and modified testruns. -func Render(tmKubeconfigPath string, parameters *TestrunParameters, metadata *result.Metadata) ([]*tmv1beta1.Testrun, error) { +func Render(tmClient kubernetes.Interface, parameters *TestrunParameters, metadata *result.Metadata) ([]*tmv1beta1.Testrun, error) { versions, err := getK8sVersions(parameters) if err != nil { log.Fatal(err.Error()) @@ -35,17 +36,16 @@ func Render(tmKubeconfigPath string, parameters *TestrunParameters, metadata *re if parameters.ComponentDescriptorPath != "" { data, err := ioutil.ReadFile(parameters.ComponentDescriptorPath) if err != nil { - log.Warnf("Cannot read component descriptor file %s: %s", parameters.ComponentDescriptorPath, err.Error()) + return nil, fmt.Errorf("Cannot read component descriptor file %s: %s", parameters.ComponentDescriptorPath, err.Error()) } components, err := componentdescriptor.GetComponents(data) if err != nil { - log.Warnf("Cannot decode and parse BOM %s", err.Error()) - } else { - metadata.BOM = components + return nil, fmt.Errorf("Cannot decode and parse BOM %s", err.Error()) } + metadata.BOM = components } - files, err := RenderChart(tmKubeconfigPath, parameters, versions) + files, err := RenderChart(tmClient, parameters, versions) if err != nil { return nil, err } @@ -58,7 +58,7 @@ func Render(tmKubeconfigPath string, parameters *TestrunParameters, metadata *re log.Warnf("Cannot parse rendered file: %s", err.Error()) } - // Add current dependency repositories to the testrun location. + // Add all repositories defined in the component descriptor to the testrun locations. // This gives us all dependent repositories as well as there deployed version. addBOMLocationsToTestrun(&tr, metadata.BOM) diff --git a/pkg/testrunner/testrunner.go b/pkg/testrunner/testrunner.go index 0ff99303d6..0362c9d3e3 100644 --- a/pkg/testrunner/testrunner.go +++ b/pkg/testrunner/testrunner.go @@ -16,15 +16,13 @@ package testrunner import ( "errors" - "fmt" "sync" + "github.com/gardener/gardener/pkg/client/kubernetes" + tmv1beta1 "github.com/gardener/test-infra/pkg/apis/testmachinery/v1beta1" "github.com/gardener/test-infra/pkg/util" - "k8s.io/client-go/tools/clientcmd" - - tmclientset "github.com/gardener/test-infra/pkg/client/testmachinery/clientset/versioned" log "github.com/sirupsen/logrus" ) @@ -39,16 +37,7 @@ func Run(config *Config, testruns []*tmv1beta1.Testrun, testrunNamePrefix string maxWaitTimeSeconds = config.Timeout pollIntervalSeconds = config.Interval - tmConfig, err := clientcmd.BuildConfigFromFlags("", config.TmKubeconfigPath) - if err != nil { - return nil, fmt.Errorf("Cannot build kubernetes client from %s: %s", config.TmKubeconfigPath, err.Error()) - } - tmClient, err := tmclientset.NewForConfig(tmConfig) - if err != nil { - return nil, err - } - - finishedTestruns := runChart(tmClient, testruns, config.Namespace, testrunNamePrefix) + finishedTestruns := runChart(config.TmClient, testruns, config.Namespace, testrunNamePrefix) if len(finishedTestruns) == 0 { return nil, errors.New("No testruns finished") @@ -59,7 +48,7 @@ func Run(config *Config, testruns []*tmv1beta1.Testrun, testrunNamePrefix string // runChart tries to parse each rendered file of a chart into a testrun. // If a filecontent is a testrun then it is deployed into the testmachinery. -func runChart(tmClient *tmclientset.Clientset, testruns []*tmv1beta1.Testrun, namespace, testrunNamePrefix string) []*tmv1beta1.Testrun { +func runChart(tmClient kubernetes.Interface, testruns []*tmv1beta1.Testrun, namespace, testrunNamePrefix string) []*tmv1beta1.Testrun { var wg sync.WaitGroup mutex := &sync.Mutex{} finishedTestruns := []*tmv1beta1.Testrun{} diff --git a/pkg/testrunner/types.go b/pkg/testrunner/types.go index 27ff995faf..63c2c36b3c 100644 --- a/pkg/testrunner/types.go +++ b/pkg/testrunner/types.go @@ -14,11 +14,13 @@ package testrunner +import "github.com/gardener/gardener/pkg/client/kubernetes" + // Config are configuration of the evironment like the testmachinery cluster or S3 store // where the testrunner executes the testrun. type Config struct { - // Path to the kubeconfig where the testmachinery is running. - TmKubeconfigPath string + // Kubernetes client for the testmachinery k8s cluster + TmClient kubernetes.Interface // Namespace where the testrun is deployed. Namespace string diff --git a/test/controller/garbagecollection/garbagecollection_test.go b/test/controller/garbagecollection/garbagecollection_test.go index 66309db315..27167a76e2 100644 --- a/test/controller/garbagecollection/garbagecollection_test.go +++ b/test/controller/garbagecollection/garbagecollection_test.go @@ -15,11 +15,14 @@ package garbagecollection_test import ( + "context" "fmt" "net/http" "os" "time" + "github.com/gardener/test-infra/pkg/testmachinery" + "github.com/gardener/gardener/pkg/client/kubernetes" "sigs.k8s.io/controller-runtime/pkg/client" @@ -29,14 +32,9 @@ import ( . "github.com/onsi/gomega" "k8s.io/apimachinery/pkg/api/errors" - argoclientset "github.com/argoproj/argo/pkg/client/clientset/versioned" - tmclientset "github.com/gardener/test-infra/pkg/client/testmachinery/clientset/versioned" "github.com/gardener/test-infra/pkg/util" "github.com/gardener/test-infra/test/resources" "github.com/gardener/test-infra/test/utils" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "k8s.io/client-go/tools/clientcmd" ) var ( @@ -48,8 +46,7 @@ var _ = Describe("Garbage collection tests", func() { var ( commitSha string namespace string - tmClient *tmclientset.Clientset - argoClient *argoclientset.Clientset + tmClient kubernetes.Interface minioClient *minio.Client minioBucket string ) @@ -61,18 +58,13 @@ var _ = Describe("Garbage collection tests", func() { namespace = os.Getenv("TM_NAMESPACE") minioEndpoint := os.Getenv("S3_ENDPOINT") - tmConfig, err := clientcmd.BuildConfigFromFlags("", tmKubeconfig) - Expect(err).ToNot(HaveOccurred(), "couldn't create k8s client from kubeconfig filepath %s", tmKubeconfig) - - tmClient = tmclientset.NewForConfigOrDie(tmConfig) - - argoClient = argoclientset.NewForConfigOrDie(tmConfig) - - clusterClient, err := kubernetes.NewClientFromFile(tmKubeconfig, nil, client.Options{}) + tmClient, err = kubernetes.NewClientFromFile("", tmKubeconfig, client.Options{ + Scheme: testmachinery.TestMachineryScheme, + }) Expect(err).ToNot(HaveOccurred()) - utils.WaitForClusterReadiness(clusterClient, namespace, maxWaitTime) - osConfig := utils.WaitForMinioService(clusterClient, minioEndpoint, namespace, maxWaitTime) + utils.WaitForClusterReadiness(tmClient, namespace, maxWaitTime) + osConfig := utils.WaitForMinioService(tmClient, minioEndpoint, namespace, maxWaitTime) minioBucket = osConfig.BucketName minioClient, err = minio.New(osConfig.Endpoint, osConfig.AccessKey, osConfig.SecretKey, false) @@ -80,9 +72,11 @@ var _ = Describe("Garbage collection tests", func() { }) It("should cleanup all artifacts when a TestDef is deleted", func() { + ctx := context.Background() + defer ctx.Done() tr := resources.GetBasicTestrun(namespace, commitSha) - tr, wf, err := utils.RunTestrun(tmClient, argoClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) + tr, wf, err := utils.RunTestrun(ctx, tmClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) Expect(err).ToNot(HaveOccurred()) utils.DeleteTestrun(tmClient, tr) @@ -90,7 +84,7 @@ var _ = Describe("Garbage collection tests", func() { for { Expect(util.MaxTimeExceeded(startTime, maxWaitTime)).To(BeFalse(), "Max Wait time exceeded.") - if _, err := tmClient.Testmachinery().Testruns(namespace).Get(tr.Name, metav1.GetOptions{}); err != nil { + if err := tmClient.Client().Get(ctx, client.ObjectKey{Namespace: namespace, Name: tr.Name}, nil); err != nil { Expect(errors.IsNotFound(err)).To(BeTrue(), "Testrun: %s", tr.Name) break } diff --git a/test/controller/resultcollection/resultcollection_test.go b/test/controller/resultcollection/resultcollection_test.go index b81935b176..b7a63d321a 100644 --- a/test/controller/resultcollection/resultcollection_test.go +++ b/test/controller/resultcollection/resultcollection_test.go @@ -15,23 +15,21 @@ package resultcollection_test import ( + "context" "os" "time" + "github.com/gardener/test-infra/pkg/testmachinery" + argov1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "sigs.k8s.io/controller-runtime/pkg/client" - argoclientset "github.com/argoproj/argo/pkg/client/clientset/versioned" "github.com/gardener/gardener/pkg/client/kubernetes" tmv1beta1 "github.com/gardener/test-infra/pkg/apis/testmachinery/v1beta1" - tmclientset "github.com/gardener/test-infra/pkg/client/testmachinery/clientset/versioned" "github.com/gardener/test-infra/test/resources" "github.com/gardener/test-infra/test/utils" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "k8s.io/client-go/tools/clientcmd" ) var ( @@ -41,10 +39,9 @@ var ( var _ = Describe("Result collection tests", func() { var ( - commitSha string - namespace string - tmClient *tmclientset.Clientset - argoClient *argoclientset.Clientset + commitSha string + namespace string + tmClient kubernetes.Interface ) BeforeSuite(func() { @@ -53,30 +50,27 @@ var _ = Describe("Result collection tests", func() { tmKubeconfig := os.Getenv("TM_KUBECONFIG_PATH") namespace = os.Getenv("TM_NAMESPACE") - tmConfig, err := clientcmd.BuildConfigFromFlags("", tmKubeconfig) - Expect(err).ToNot(HaveOccurred(), "couldn't create k8s client from kubeconfig filepath %s", tmKubeconfig) - - tmClient = tmclientset.NewForConfigOrDie(tmConfig) - - argoClient = argoclientset.NewForConfigOrDie(tmConfig) - - clusterClient, err := kubernetes.NewClientFromFile(tmKubeconfig, nil, client.Options{}) + tmClient, err = kubernetes.NewClientFromFile("", tmKubeconfig, client.Options{ + Scheme: testmachinery.TestMachineryScheme, + }) Expect(err).ToNot(HaveOccurred()) - utils.WaitForClusterReadiness(clusterClient, namespace, maxWaitTime) + utils.WaitForClusterReadiness(tmClient, namespace, maxWaitTime) }) Context("step status", func() { It("should update status immediately with all steps of the generated testflow", func() { + ctx := context.Background() + defer ctx.Done() tr := resources.GetBasicTestrun(namespace, commitSha) - tr, err := tmClient.Testmachinery().Testruns(tr.Namespace).Create(tr) + err := tmClient.Client().Create(ctx, tr) Expect(err).ToNot(HaveOccurred()) defer utils.DeleteTestrun(tmClient, tr) time.Sleep(5 * time.Second) - tr, err = tmClient.Testmachinery().Testruns(namespace).Get(tr.Name, metav1.GetOptions{}) + err = tmClient.Client().Get(ctx, client.ObjectKey{Namespace: namespace, Name: tr.Name}, tr) Expect(err).ToNot(HaveOccurred()) Expect(utils.TestflowLen(tr.Status.Steps)).To(Equal(1), "Should be one steps status") @@ -86,9 +80,11 @@ var _ = Describe("Result collection tests", func() { }) It("should collect status of all workflow nodes", func() { + ctx := context.Background() + defer ctx.Done() tr := resources.GetBasicTestrun(namespace, commitSha) - tr, _, err := utils.RunTestrun(tmClient, argoClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) + tr, _, err := utils.RunTestrun(ctx, tmClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) Expect(err).ToNot(HaveOccurred()) defer utils.DeleteTestrun(tmClient, tr) @@ -102,6 +98,8 @@ var _ = Describe("Result collection tests", func() { }) It("should collect status of multiple workflow nodes", func() { + ctx := context.Background() + defer ctx.Done() tr := resources.GetBasicTestrun(namespace, commitSha) tr.Spec.TestFlow = [][]tmv1beta1.TestflowStep{ { @@ -119,7 +117,7 @@ var _ = Describe("Result collection tests", func() { }, } - tr, _, err := utils.RunTestrun(tmClient, argoClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) + tr, _, err := utils.RunTestrun(ctx, tmClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) Expect(err).ToNot(HaveOccurred()) defer utils.DeleteTestrun(tmClient, tr) @@ -138,6 +136,8 @@ var _ = Describe("Result collection tests", func() { }) It("should collect status of multiple workflow nodes with a failing step", func() { + ctx := context.Background() + defer ctx.Done() tr := resources.GetBasicTestrun(namespace, commitSha) tr.Spec.TestFlow = [][]tmv1beta1.TestflowStep{ { @@ -155,7 +155,7 @@ var _ = Describe("Result collection tests", func() { }, } - tr, _, err := utils.RunTestrun(tmClient, argoClient, tr, argov1.NodeFailed, namespace, maxWaitTime) + tr, _, err := utils.RunTestrun(ctx, tmClient, tr, argov1.NodeFailed, namespace, maxWaitTime) Expect(err).ToNot(HaveOccurred()) defer utils.DeleteTestrun(tmClient, tr) diff --git a/test/controller/testdefinition/testdefinition_suite_test.go b/test/controller/testdefinition/testdefinition_suite_test.go index dd310d1a9d..621912fda4 100644 --- a/test/controller/testdefinition/testdefinition_suite_test.go +++ b/test/controller/testdefinition/testdefinition_suite_test.go @@ -15,9 +15,12 @@ package testdefinition_test import ( + "context" "os" "testing" + "github.com/gardener/test-infra/pkg/testmachinery" + argov1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" "github.com/gardener/gardener/pkg/client/kubernetes" tmv1beta1 "github.com/gardener/test-infra/pkg/apis/testmachinery/v1beta1" @@ -26,12 +29,8 @@ import ( corev1 "k8s.io/api/core/v1" "sigs.k8s.io/controller-runtime/pkg/client" - argoclientset "github.com/argoproj/argo/pkg/client/clientset/versioned" - tmclientset "github.com/gardener/test-infra/pkg/client/testmachinery/clientset/versioned" "github.com/gardener/test-infra/test/resources" "github.com/gardener/test-infra/test/utils" - - "k8s.io/client-go/tools/clientcmd" ) var ( @@ -46,11 +45,9 @@ func TestValidationWebhook(t *testing.T) { var _ = Describe("Testflow execution tests", func() { var ( - commitSha string - namespace string - tmClient *tmclientset.Clientset - argoClient *argoclientset.Clientset - clusterClient kubernetes.Interface + commitSha string + namespace string + tmClient kubernetes.Interface ) BeforeSuite(func() { @@ -59,22 +56,19 @@ var _ = Describe("Testflow execution tests", func() { namespace = os.Getenv("TM_NAMESPACE") tmKubeconfig := os.Getenv("TM_KUBECONFIG_PATH") - tmConfig, err := clientcmd.BuildConfigFromFlags("", tmKubeconfig) - Expect(err).ToNot(HaveOccurred(), "couldn't create k8s client from kubeconfig filepath %s", tmKubeconfig) - - tmClient = tmclientset.NewForConfigOrDie(tmConfig) - - argoClient = argoclientset.NewForConfigOrDie(tmConfig) - - clusterClient, err = kubernetes.NewClientFromFile(tmKubeconfig, nil, client.Options{}) + tmClient, err = kubernetes.NewClientFromFile("", tmKubeconfig, client.Options{ + Scheme: testmachinery.TestMachineryScheme, + }) Expect(err).ToNot(HaveOccurred()) - utils.WaitForClusterReadiness(clusterClient, namespace, maxWaitTime) + utils.WaitForClusterReadiness(tmClient, namespace, maxWaitTime) }) Context("config", func() { Context("type environment variable", func() { It("should run a TesDef with a environment variable defined by value", func() { + ctx := context.Background() + defer ctx.Done() tr := resources.GetBasicTestrun(namespace, commitSha) tr.Spec.TestFlow = [][]tmv1beta1.TestflowStep{ { @@ -84,12 +78,14 @@ var _ = Describe("Testflow execution tests", func() { }, } - tr, _, err := utils.RunTestrun(tmClient, argoClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) + tr, _, err := utils.RunTestrun(ctx, tmClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) defer utils.DeleteTestrun(tmClient, tr) Expect(err).ToNot(HaveOccurred()) }) It("should run a TesDef with a evironment variable defined by a secret", func() { + ctx := context.Background() + defer ctx.Done() tr := resources.GetBasicTestrun(namespace, commitSha) tr.Spec.TestFlow = [][]tmv1beta1.TestflowStep{ { @@ -99,16 +95,16 @@ var _ = Describe("Testflow execution tests", func() { }, } - _, err := clusterClient.CreateSecret(namespace, "test-secret", corev1.SecretTypeOpaque, map[string][]byte{ + _, err := tmClient.CreateSecret(namespace, "test-secret", corev1.SecretTypeOpaque, map[string][]byte{ "test": []byte("test"), }, false) Expect(err).ToNot(HaveOccurred()) defer func() { - err := clusterClient.DeleteSecret(namespace, "test-secret") + err := tmClient.DeleteSecret(namespace, "test-secret") Expect(err).ToNot(HaveOccurred(), "Cannot delete secret") }() - tr, _, err = utils.RunTestrun(tmClient, argoClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) + tr, _, err = utils.RunTestrun(ctx, tmClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) defer utils.DeleteTestrun(tmClient, tr) Expect(err).ToNot(HaveOccurred()) }) @@ -116,6 +112,8 @@ var _ = Describe("Testflow execution tests", func() { Context("type file", func() { It("should run a TesDef with a file defined by a secret", func() { + ctx := context.Background() + defer ctx.Done() tr := resources.GetBasicTestrun(namespace, commitSha) tr.Spec.TestFlow = [][]tmv1beta1.TestflowStep{ { @@ -125,16 +123,16 @@ var _ = Describe("Testflow execution tests", func() { }, } - _, err := clusterClient.CreateSecret(namespace, "test-secret-file", corev1.SecretTypeOpaque, map[string][]byte{ + _, err := tmClient.CreateSecret(namespace, "test-secret-file", corev1.SecretTypeOpaque, map[string][]byte{ "test": []byte("test"), }, false) Expect(err).ToNot(HaveOccurred()) defer func() { - err := clusterClient.DeleteSecret(namespace, "test-secret-file") + err := tmClient.DeleteSecret(namespace, "test-secret-file") Expect(err).ToNot(HaveOccurred(), "Cannot delete secret") }() - tr, _, err = utils.RunTestrun(tmClient, argoClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) + tr, _, err = utils.RunTestrun(ctx, tmClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) defer utils.DeleteTestrun(tmClient, tr) Expect(err).ToNot(HaveOccurred()) }) diff --git a/test/controller/testflow/testflow_suite_test.go b/test/controller/testflow/testflow_suite_test.go index 01386c688a..d0420e3923 100644 --- a/test/controller/testflow/testflow_suite_test.go +++ b/test/controller/testflow/testflow_suite_test.go @@ -21,6 +21,8 @@ import ( "testing" "time" + "github.com/gardener/test-infra/pkg/testmachinery" + "github.com/gardener/gardener/pkg/client/kubernetes" "sigs.k8s.io/controller-runtime/pkg/client" @@ -29,9 +31,7 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - argoclientset "github.com/argoproj/argo/pkg/client/clientset/versioned" tmv1beta1 "github.com/gardener/test-infra/pkg/apis/testmachinery/v1beta1" - tmclientset "github.com/gardener/test-infra/pkg/client/testmachinery/clientset/versioned" "github.com/gardener/test-infra/pkg/util" "github.com/gardener/test-infra/test/resources" "github.com/gardener/test-infra/test/utils" @@ -39,7 +39,6 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/tools/clientcmd" ) var ( @@ -54,11 +53,9 @@ func TestValidationWebhook(t *testing.T) { var _ = Describe("Testflow execution tests", func() { var ( - commitSha string - namespace string - tmClient *tmclientset.Clientset - argoClient *argoclientset.Clientset - clusterClient kubernetes.Interface + commitSha string + namespace string + tmClient kubernetes.Interface ) BeforeSuite(func() { @@ -67,23 +64,20 @@ var _ = Describe("Testflow execution tests", func() { tmKubeconfig := os.Getenv("TM_KUBECONFIG_PATH") namespace = os.Getenv("TM_NAMESPACE") - tmConfig, err := clientcmd.BuildConfigFromFlags("", tmKubeconfig) - Expect(err).ToNot(HaveOccurred(), "couldn't create k8s client from kubeconfig filepath %s", tmKubeconfig) - - tmClient = tmclientset.NewForConfigOrDie(tmConfig) - - argoClient = argoclientset.NewForConfigOrDie(tmConfig) - - clusterClient, err = kubernetes.NewClientFromFile(tmKubeconfig, nil, client.Options{}) + tmClient, err = kubernetes.NewClientFromFile("", tmKubeconfig, client.Options{ + Scheme: testmachinery.TestMachineryScheme, + }) Expect(err).ToNot(HaveOccurred()) - utils.WaitForClusterReadiness(clusterClient, namespace, maxWaitTime) + utils.WaitForClusterReadiness(tmClient, namespace, maxWaitTime) }) Context("testflow", func() { It("should run a test with TestDefs defined by name", func() { + ctx := context.Background() + defer ctx.Done() tr := resources.GetBasicTestrun(namespace, commitSha) - tr, wf, err := utils.RunTestrun(tmClient, argoClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) + tr, wf, err := utils.RunTestrun(ctx, tmClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) defer utils.DeleteTestrun(tmClient, tr) Expect(err).ToNot(HaveOccurred()) @@ -98,6 +92,8 @@ var _ = Describe("Testflow execution tests", func() { }) It("should run a test with TestDefs defined by label and name", func() { + ctx := context.Background() + defer ctx.Done() tr := resources.GetBasicTestrun(namespace, commitSha) tr.Spec.TestFlow = append(tr.Spec.TestFlow, []tmv1beta1.TestflowStep{ { @@ -105,7 +101,7 @@ var _ = Describe("Testflow execution tests", func() { }, }) - tr, wf, err := utils.RunTestrun(tmClient, argoClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) + tr, wf, err := utils.RunTestrun(ctx, tmClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) defer utils.DeleteTestrun(tmClient, tr) Expect(err).ToNot(HaveOccurred()) @@ -120,6 +116,8 @@ var _ = Describe("Testflow execution tests", func() { }) It("should execute all tests in right order when no testdefs for a label can be found", func() { + ctx := context.Background() + defer ctx.Done() tr := resources.GetBasicTestrun(namespace, commitSha) tr.Spec.TestFlow = append(tr.Spec.TestFlow, []tmv1beta1.TestflowStep{ { @@ -133,7 +131,7 @@ var _ = Describe("Testflow execution tests", func() { }, }) - tr, wf, err := utils.RunTestrun(tmClient, argoClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) + tr, wf, err := utils.RunTestrun(ctx, tmClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) defer utils.DeleteTestrun(tmClient, tr) Expect(err).ToNot(HaveOccurred()) @@ -148,6 +146,8 @@ var _ = Describe("Testflow execution tests", func() { }) It("should execute serial steps after parallel steps", func() { + ctx := context.Background() + defer ctx.Done() tr := resources.GetBasicTestrun(namespace, commitSha) tr.Spec.TestFlow = [][]tmv1beta1.TestflowStep{ { @@ -157,7 +157,7 @@ var _ = Describe("Testflow execution tests", func() { }, } - tr, wf, err := utils.RunTestrun(tmClient, argoClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) + tr, wf, err := utils.RunTestrun(ctx, tmClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) defer utils.DeleteTestrun(tmClient, tr) Expect(err).ToNot(HaveOccurred()) @@ -180,6 +180,8 @@ var _ = Describe("Testflow execution tests", func() { Context("config", func() { Context("type environment variable", func() { It("should mount a config as environment variable", func() { + ctx := context.Background() + defer ctx.Done() tr := resources.GetBasicTestrun(namespace, commitSha) tr.Spec.TestFlow = [][]tmv1beta1.TestflowStep{ { @@ -196,13 +198,15 @@ var _ = Describe("Testflow execution tests", func() { }, } - tr, _, err := utils.RunTestrun(tmClient, argoClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) + tr, _, err := utils.RunTestrun(ctx, tmClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) defer utils.DeleteTestrun(tmClient, tr) Expect(err).ToNot(HaveOccurred()) }) It("should mount a global config as environement variable", func() { + ctx := context.Background() + defer ctx.Done() tr := resources.GetBasicTestrun(namespace, commitSha) tr.Spec.TestFlow = [][]tmv1beta1.TestflowStep{ { @@ -219,7 +223,7 @@ var _ = Describe("Testflow execution tests", func() { }, } - tr, _, err := utils.RunTestrun(tmClient, argoClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) + tr, _, err := utils.RunTestrun(ctx, tmClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) defer utils.DeleteTestrun(tmClient, tr) Expect(err).ToNot(HaveOccurred()) }) @@ -227,6 +231,8 @@ var _ = Describe("Testflow execution tests", func() { Context("type file", func() { It("should mount a config with value as file to a specific path", func() { + ctx := context.Background() + defer ctx.Done() tr := resources.GetBasicTestrun(namespace, commitSha) tr.Spec.TestFlow = [][]tmv1beta1.TestflowStep{ { @@ -249,7 +255,7 @@ var _ = Describe("Testflow execution tests", func() { }, } - tr, _, err := utils.RunTestrun(tmClient, argoClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) + tr, _, err := utils.RunTestrun(ctx, tmClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) defer utils.DeleteTestrun(tmClient, tr) Expect(err).ToNot(HaveOccurred()) }) @@ -267,10 +273,10 @@ var _ = Describe("Testflow execution tests", func() { "test": []byte("test"), }, } - err := clusterClient.Client().Create(ctx, secret) + err := tmClient.Client().Create(ctx, secret) Expect(err).ToNot(HaveOccurred()) defer func() { - err := clusterClient.Client().Delete(ctx, secret) + err := tmClient.Client().Delete(ctx, secret) Expect(err).ToNot(HaveOccurred(), "Cannot delete secret") }() @@ -303,7 +309,7 @@ var _ = Describe("Testflow execution tests", func() { }, } - tr, _, err = utils.RunTestrun(tmClient, argoClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) + tr, _, err = utils.RunTestrun(ctx, tmClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) defer utils.DeleteTestrun(tmClient, tr) Expect(err).ToNot(HaveOccurred()) @@ -321,10 +327,10 @@ var _ = Describe("Testflow execution tests", func() { "test": "test", }, } - err := clusterClient.Client().Create(ctx, configmap) + err := tmClient.Client().Create(ctx, configmap) Expect(err).ToNot(HaveOccurred()) defer func() { - err := clusterClient.Client().Delete(ctx, configmap) + err := tmClient.Client().Delete(ctx, configmap) Expect(err).ToNot(HaveOccurred(), "Cannot delete configmap %s", configmap.Name) }() @@ -357,7 +363,7 @@ var _ = Describe("Testflow execution tests", func() { }, } - tr, _, err = utils.RunTestrun(tmClient, argoClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) + tr, _, err = utils.RunTestrun(ctx, tmClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) defer utils.DeleteTestrun(tmClient, tr) Expect(err).ToNot(HaveOccurred()) @@ -368,9 +374,11 @@ var _ = Describe("Testflow execution tests", func() { Context("onExit", func() { It("should run ExitHandlerTestDef when testflow succeeds", func() { + ctx := context.Background() + defer ctx.Done() tr := resources.GetTestrunWithExitHandler(resources.GetBasicTestrun(namespace, commitSha), tmv1beta1.ConditionTypeSuccess) - tr, wf, err := utils.RunTestrun(tmClient, argoClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) + tr, wf, err := utils.RunTestrun(ctx, tmClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) defer utils.DeleteTestrun(tmClient, tr) Expect(err).ToNot(HaveOccurred()) @@ -385,9 +393,11 @@ var _ = Describe("Testflow execution tests", func() { }) It("should not run exit-handler-testdef when testflow succeeds", func() { + ctx := context.Background() + defer ctx.Done() tr := resources.GetTestrunWithExitHandler(resources.GetBasicTestrun(namespace, commitSha), tmv1beta1.ConditionTypeError) - tr, wf, err := utils.RunTestrun(tmClient, argoClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) + tr, wf, err := utils.RunTestrun(ctx, tmClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) defer utils.DeleteTestrun(tmClient, tr) Expect(err).ToNot(HaveOccurred()) @@ -402,9 +412,11 @@ var _ = Describe("Testflow execution tests", func() { }) It("should run exit-handler-testdef when testflow fails", func() { + ctx := context.Background() + defer ctx.Done() tr := resources.GetTestrunWithExitHandler(resources.GetFailingTestrun(namespace, commitSha), tmv1beta1.ConditionTypeError) - tr, wf, err := utils.RunTestrun(tmClient, argoClient, tr, argov1.NodeFailed, namespace, maxWaitTime) + tr, wf, err := utils.RunTestrun(ctx, tmClient, tr, argov1.NodeFailed, namespace, maxWaitTime) defer utils.DeleteTestrun(tmClient, tr) Expect(err).ToNot(HaveOccurred()) @@ -421,47 +433,53 @@ var _ = Describe("Testflow execution tests", func() { Context("TTL", func() { It("should delete the testrun after ttl has finished", func() { + ctx := context.Background() + defer ctx.Done() + var ttl int32 = 90 var maxWaitTime int64 = 600 tr := resources.GetBasicTestrun(namespace, commitSha) tr.Spec.TTLSecondsAfterFinished = &ttl - tr, err := tmClient.Testmachinery().Testruns(tr.Namespace).Create(tr) + err := tmClient.Client().Create(ctx, tr) defer utils.DeleteTestrun(tmClient, tr) Expect(err).ToNot(HaveOccurred()) startTime := time.Now() for !util.MaxTimeExceeded(startTime, maxWaitTime) { - _, err := tmClient.Testmachinery().Testruns(tr.Namespace).Get(tr.Name, metav1.GetOptions{}) + err = tmClient.Client().Get(ctx, client.ObjectKey{Namespace: tr.Namespace, Name: tr.Name}, nil) if errors.IsNotFound(err) { return } time.Sleep(5 * time.Second) } - _, err = tmClient.Testmachinery().Testruns(tr.Namespace).Get(tr.Name, metav1.GetOptions{}) + err = tmClient.Client().Get(ctx, client.ObjectKey{Namespace: tr.Namespace, Name: tr.Name}, nil) Expect(errors.IsNotFound(err)).To(BeTrue(), "Testrun %s was not deleted in %d seconds", tr.Name, maxWaitTime) }) It("should delete the testrun after workflow has finished", func() { + ctx := context.Background() + defer ctx.Done() + var ttl int32 = 1 var maxWaitTime int64 = 600 tr := resources.GetBasicTestrun(namespace, commitSha) tr.Spec.TTLSecondsAfterFinished = &ttl - tr, err := tmClient.Testmachinery().Testruns(tr.Namespace).Create(tr) + err := tmClient.Client().Create(ctx, tr) defer utils.DeleteTestrun(tmClient, tr) Expect(err).ToNot(HaveOccurred()) startTime := time.Now() for !util.MaxTimeExceeded(startTime, maxWaitTime) { - _, err := tmClient.Testmachinery().Testruns(tr.Namespace).Get(tr.Name, metav1.GetOptions{}) + err = tmClient.Client().Get(ctx, client.ObjectKey{Namespace: tr.Namespace, Name: tr.Name}, nil) if errors.IsNotFound(err) { return } time.Sleep(5 * time.Second) } - _, err = tmClient.Testmachinery().Testruns(tr.Namespace).Get(tr.Name, metav1.GetOptions{}) + err = tmClient.Client().Get(ctx, client.ObjectKey{Namespace: tr.Namespace, Name: tr.Name}, nil) Expect(errors.IsNotFound(err)).To(BeTrue(), "Testrun %s was not deleted in %d seconds", tr.Name, maxWaitTime) }) }) diff --git a/test/testrunner/output/testrunner_output_execution_test.go b/test/testrunner/output/testrunner_output_execution_test.go index 54762d129f..cd897c504a 100644 --- a/test/testrunner/output/testrunner_output_execution_test.go +++ b/test/testrunner/output/testrunner_output_execution_test.go @@ -15,12 +15,15 @@ package testrunner_output_test import ( - "github.com/gardener/test-infra/pkg/testrunner/result" "bufio" + "context" "encoding/json" "os" "testing" + "github.com/gardener/test-infra/pkg/testmachinery" + "github.com/gardener/test-infra/pkg/testrunner/result" + "github.com/gardener/test-infra/pkg/util" "sigs.k8s.io/controller-runtime/pkg/client" @@ -29,12 +32,8 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - argoclientset "github.com/argoproj/argo/pkg/client/clientset/versioned" - tmclientset "github.com/gardener/test-infra/pkg/client/testmachinery/clientset/versioned" "github.com/gardener/test-infra/test/resources" "github.com/gardener/test-infra/test/utils" - - "k8s.io/client-go/tools/clientcmd" ) var ( @@ -52,8 +51,7 @@ var _ = Describe("Testrunner execution tests", func() { commitSha string namespace string tmKubeconfig string - tmClient *tmclientset.Clientset - argoClient *argoclientset.Clientset + tmClient kubernetes.Interface outputFilePath = "./out-" testrunConfig result.Config s3Endpoint string @@ -66,18 +64,13 @@ var _ = Describe("Testrunner execution tests", func() { namespace = os.Getenv("TM_NAMESPACE") s3Endpoint = os.Getenv("S3_ENDPOINT") - tmConfig, err := clientcmd.BuildConfigFromFlags("", tmKubeconfig) - Expect(err).ToNot(HaveOccurred(), "couldn't create k8s client from kubeconfig filepath %s", tmKubeconfig) - - tmClient = tmclientset.NewForConfigOrDie(tmConfig) - - argoClient = argoclientset.NewForConfigOrDie(tmConfig) - - clusterClient, err := kubernetes.NewClientFromFile(tmKubeconfig, nil, client.Options{}) + tmClient, err = kubernetes.NewClientFromFile("", tmKubeconfig, client.Options{ + Scheme: testmachinery.TestMachineryScheme, + }) Expect(err).ToNot(HaveOccurred()) - utils.WaitForClusterReadiness(clusterClient, namespace, maxWaitTime) - utils.WaitForMinioService(clusterClient, s3Endpoint, namespace, maxWaitTime) + utils.WaitForClusterReadiness(tmClient, namespace, maxWaitTime) + utils.WaitForMinioService(tmClient, s3Endpoint, namespace, maxWaitTime) }) BeforeEach(func() { @@ -90,15 +83,17 @@ var _ = Describe("Testrunner execution tests", func() { }) It("should output a summary of the testrun as elasticsearch bulk request", func() { + ctx := context.Background() + defer ctx.Done() testrunConfig.OutputFile = outputFilePath + util.RandomString(3) tr := resources.GetBasicTestrun(namespace, commitSha) - tr, _, err := utils.RunTestrun(tmClient, argoClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) + tr, _, err := utils.RunTestrun(ctx, tmClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) Expect(err).ToNot(HaveOccurred()) if err == nil { defer utils.DeleteTestrun(tmClient, tr) } - err = result.Output(&testrunConfig, tmKubeconfig, namespace, tr, &result.Metadata{}) + err = result.Output(&testrunConfig, tmClient, namespace, tr, &result.Metadata{}) Expect(err).ToNot(HaveOccurred()) file, err := os.Open(testrunConfig.OutputFile) @@ -127,15 +122,17 @@ var _ = Describe("Testrunner execution tests", func() { }) It("should add exported artifacts to the elasticsearch bulk output", func() { + ctx := context.Background() + defer ctx.Done() testrunConfig.OutputFile = outputFilePath + util.RandomString(3) tr := resources.GetBasicTestrun(namespace, commitSha) - tr, _, err := utils.RunTestrun(tmClient, argoClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) + tr, _, err := utils.RunTestrun(ctx, tmClient, tr, argov1.NodeSucceeded, namespace, maxWaitTime) Expect(err).ToNot(HaveOccurred()) if err == nil { defer utils.DeleteTestrun(tmClient, tr) } - err = result.Output(&testrunConfig, tmKubeconfig, namespace, tr, &result.Metadata{}) + err = result.Output(&testrunConfig, tmClient, namespace, tr, &result.Metadata{}) Expect(err).ToNot(HaveOccurred()) file, err := os.Open(testrunConfig.OutputFile) diff --git a/test/testrunner/run/testrunner_run_test.go b/test/testrunner/run/testrunner_run_test.go index 2224cd00c5..a8392027f9 100644 --- a/test/testrunner/run/testrunner_run_test.go +++ b/test/testrunner/run/testrunner_run_test.go @@ -18,7 +18,8 @@ import ( "os" "testing" - "k8s.io/client-go/tools/clientcmd" + "github.com/gardener/test-infra/pkg/testmachinery" + "sigs.k8s.io/controller-runtime/pkg/client" "github.com/gardener/gardener/pkg/client/kubernetes" @@ -27,7 +28,6 @@ import ( . "github.com/onsi/gomega" tmv1beta1 "github.com/gardener/test-infra/pkg/apis/testmachinery/v1beta1" - tmclientset "github.com/gardener/test-infra/pkg/client/testmachinery/clientset/versioned" "github.com/gardener/test-infra/test/resources" "github.com/gardener/test-infra/test/utils" ) @@ -47,7 +47,7 @@ var _ = Describe("Testrunner execution tests", func() { commitSha string namespace string tmKubeconfig string - tmClient *tmclientset.Clientset + tmClient kubernetes.Interface testrunConfig testrunner.Config s3Endpoint string ) @@ -59,24 +59,21 @@ var _ = Describe("Testrunner execution tests", func() { namespace = os.Getenv("TM_NAMESPACE") s3Endpoint = os.Getenv("S3_ENDPOINT") - tmConfig, err := clientcmd.BuildConfigFromFlags("", tmKubeconfig) - Expect(err).ToNot(HaveOccurred(), "couldn't create k8s client from kubeconfig filepath %s", tmKubeconfig) - - tmClient = tmclientset.NewForConfigOrDie(tmConfig) - - clusterClient, err := kubernetes.NewClientFromFile(tmKubeconfig, nil, client.Options{}) + tmClient, err = kubernetes.NewClientFromFile("", tmKubeconfig, client.Options{ + Scheme: testmachinery.TestMachineryScheme, + }) Expect(err).ToNot(HaveOccurred()) - utils.WaitForClusterReadiness(clusterClient, namespace, maxWaitTime) - utils.WaitForMinioService(clusterClient, s3Endpoint, namespace, maxWaitTime) + utils.WaitForClusterReadiness(tmClient, namespace, maxWaitTime) + utils.WaitForMinioService(tmClient, s3Endpoint, namespace, maxWaitTime) }) BeforeEach(func() { testrunConfig = testrunner.Config{ - TmKubeconfigPath: tmKubeconfig, - Namespace: namespace, - Timeout: maxWaitTime, - Interval: 5, + TmClient: tmClient, + Namespace: namespace, + Timeout: maxWaitTime, + Interval: 5, } }) diff --git a/test/utils/utils.go b/test/utils/utils.go index e905b78669..574c4e820d 100644 --- a/test/utils/utils.go +++ b/test/utils/utils.go @@ -15,6 +15,7 @@ package utils import ( + "context" "errors" "fmt" "net/http" @@ -22,6 +23,8 @@ import ( "strings" "time" + "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/gardener/gardener/pkg/utils/kubernetes/health" "github.com/gardener/test-infra/pkg/testmachinery" @@ -33,34 +36,29 @@ import ( argov1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" tmv1beta1 "github.com/gardener/test-infra/pkg/apis/testmachinery/v1beta1" apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - argoclientset "github.com/argoproj/argo/pkg/client/clientset/versioned" - tmclientset "github.com/gardener/test-infra/pkg/client/testmachinery/clientset/versioned" . "github.com/onsi/gomega" ) // RunTestrun executes a testrun on a cluster and returns the corresponding executed testrun and workflow. -func RunTestrun(tmClient *tmclientset.Clientset, argoClient *argoclientset.Clientset, tr *tmv1beta1.Testrun, phase argov1.NodePhase, namespace string, maxWaitTime int64) (*tmv1beta1.Testrun, *argov1.Workflow, error) { - tr, err := tmClient.Testmachinery().Testruns(tr.Namespace).Create(tr) +// Note: Deletion of the workflow on error should be handled by the calling test. +func RunTestrun(ctx context.Context, tmClient kubernetes.Interface, tr *tmv1beta1.Testrun, phase argov1.NodePhase, namespace string, maxWaitTime int64) (*tmv1beta1.Testrun, *argov1.Workflow, error) { + err := tmClient.Client().Create(ctx, tr) if err != nil { return nil, nil, err } - foundTestrun, err := WatchTestrun(tmClient, tr, namespace, maxWaitTime) + foundTestrun, err := WatchTestrun(ctx, tmClient, tr, namespace, maxWaitTime) if err != nil { - DeleteTestrun(tmClient, tr) return nil, nil, fmt.Errorf("Error watching Testrun: %s\n%s", tr.Name, err.Error()) } - wf, err := GetWorkflow(argoClient, foundTestrun) + wf, err := GetWorkflow(ctx, tmClient, foundTestrun) if err != nil { - DeleteTestrun(tmClient, tr) return nil, nil, fmt.Errorf("Cannot get Workflow for Testrun: %s\n%s", tr.Name, err.Error()) } if reflect.DeepEqual(foundTestrun.Status, tmv1beta1.TestrunStatus{}) { - DeleteTestrun(tmClient, tr) return nil, nil, fmt.Errorf("Testrun %s status is empty", tr.Name) } if foundTestrun.Status.Phase != phase { @@ -80,7 +78,6 @@ func RunTestrun(tmClient *tmclientset.Clientset, argoClient *argoclientset.Clien errMsg = fmt.Sprintf("%s.\nAdditional Errors: %s", errMsg, strings.Join(errMsgs, "; ")) } - DeleteTestrun(tmClient, tr) return nil, nil, errors.New(errMsg) } @@ -88,8 +85,9 @@ func RunTestrun(tmClient *tmclientset.Clientset, argoClient *argoclientset.Clien } // GetWorkflow returns the argo workflow of a testrun. -func GetWorkflow(argoClient *argoclientset.Clientset, tr *tmv1beta1.Testrun) (*argov1.Workflow, error) { - wf, err := argoClient.Argoproj().Workflows(tr.Namespace).Get(tr.Status.Workflow, metav1.GetOptions{}) +func GetWorkflow(ctx context.Context, tmClient kubernetes.Interface, tr *tmv1beta1.Testrun) (*argov1.Workflow, error) { + wf := &argov1.Workflow{} + err := tmClient.Client().Get(ctx, client.ObjectKey{Namespace: tr.Namespace, Name: tr.Status.Workflow}, wf) if err != nil { return nil, err } @@ -97,7 +95,7 @@ func GetWorkflow(argoClient *argoclientset.Clientset, tr *tmv1beta1.Testrun) (*a } // WatchTestrun watches a testrun to finish and returns the newest testrun object. -func WatchTestrun(tmClient *tmclientset.Clientset, tr *tmv1beta1.Testrun, namespace string, maxWaitTime int64) (*tmv1beta1.Testrun, error) { +func WatchTestrun(ctx context.Context, tmClient kubernetes.Interface, tr *tmv1beta1.Testrun, namespace string, maxWaitTime int64) (*tmv1beta1.Testrun, error) { var foundTestrun *tmv1beta1.Testrun var testrunPhase argov1.NodePhase startTime := time.Now() @@ -107,7 +105,7 @@ func WatchTestrun(tmClient *tmclientset.Clientset, tr *tmv1beta1.Testrun, namesp return nil, fmt.Errorf("Maximum wait time exceeded") } - foundTestrun, err = tmClient.Testmachinery().Testruns(namespace).Get(tr.Name, metav1.GetOptions{}) + err = tmClient.Client().Get(ctx, client.ObjectKey{Namespace: tr.Namespace, Name: tr.Name}, foundTestrun) if err != nil { return nil, err } @@ -120,12 +118,12 @@ func WatchTestrun(tmClient *tmclientset.Clientset, tr *tmv1beta1.Testrun, namesp } // DeleteTestrun deletes a testrun and expects to be successful. -func DeleteTestrun(tmClient *tmclientset.Clientset, tr *tmv1beta1.Testrun) { +func DeleteTestrun(tmClient kubernetes.Interface, tr *tmv1beta1.Testrun) { // wf is not deleted if testrun is triggered but deleted before wf can be deployed. // Strange timing in validation test with kubeconfig. // needs further investigation time.Sleep(3 * time.Second) - err := tmClient.Testmachinery().Testruns(tr.Namespace).Delete(tr.Name, &metav1.DeleteOptions{}) + err := tmClient.Client().Delete(context.TODO(), tr) if !apierrors.IsNotFound(err) { Expect(err).To(BeNil(), "Error deleting Testrun: %s", tr.Name) } diff --git a/test/validationwebhook/testrun_validation_test.go b/test/validationwebhook/testrun_validation_test.go index b55e78612d..7decd78cc1 100644 --- a/test/validationwebhook/testrun_validation_test.go +++ b/test/validationwebhook/testrun_validation_test.go @@ -15,21 +15,21 @@ package validationwebhook_test import ( + "context" "os" + "github.com/gardener/test-infra/pkg/testmachinery" + "github.com/gardener/test-infra/test/utils" "sigs.k8s.io/controller-runtime/pkg/client" "github.com/gardener/gardener/pkg/client/kubernetes" tmv1beta1 "github.com/gardener/test-infra/pkg/apis/testmachinery/v1beta1" - tmclientset "github.com/gardener/test-infra/pkg/client/testmachinery/clientset/versioned" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/gardener/test-infra/test/resources" - "k8s.io/client-go/tools/clientcmd" ) var _ = Describe("Testrun validation tests", func() { @@ -37,7 +37,7 @@ var _ = Describe("Testrun validation tests", func() { var ( commitSha string namespace string - tmClient *tmclientset.Clientset + tmClient kubernetes.Interface maxWaitTime int64 = 300 ) @@ -47,19 +47,18 @@ var _ = Describe("Testrun validation tests", func() { tmKubeconfig := os.Getenv("TM_KUBECONFIG_PATH") namespace = os.Getenv("TM_NAMESPACE") - tmConfig, err := clientcmd.BuildConfigFromFlags("", tmKubeconfig) - Expect(err).ToNot(HaveOccurred(), "couldn't create k8s client from kubeconfig filepath %s", tmKubeconfig) - - tmClient = tmclientset.NewForConfigOrDie(tmConfig) - - clusterClient, err := kubernetes.NewClientFromFile(tmKubeconfig, nil, client.Options{}) + tmClient, err = kubernetes.NewClientFromFile("", tmKubeconfig, client.Options{ + Scheme: testmachinery.TestMachineryScheme, + }) Expect(err).ToNot(HaveOccurred()) - utils.WaitForClusterReadiness(clusterClient, namespace, maxWaitTime) + utils.WaitForClusterReadiness(tmClient, namespace, maxWaitTime) }) Context("Metadata", func() { It("should reject when name contains '.'", func() { + ctx := context.Background() + defer ctx.Done() tr := resources.GetBasicTestrun(namespace, commitSha) tr.Spec.TestFlow = [][]tmv1beta1.TestflowStep{ { @@ -68,7 +67,7 @@ var _ = Describe("Testrun validation tests", func() { }, }, } - _, err := tmClient.Testmachinery().Testruns(namespace).Create(tr) + err := tmClient.Client().Create(ctx, tr) if err == nil { defer utils.DeleteTestrun(tmClient, tr) } @@ -79,11 +78,12 @@ var _ = Describe("Testrun validation tests", func() { Context("TestLocations", func() { It("should reject when no locations are defined", func() { - + ctx := context.Background() + defer ctx.Done() tr := resources.GetBasicTestrun(namespace, commitSha) tr.Spec.TestLocations = []tmv1beta1.TestLocation{} - _, err := tmClient.Testmachinery().Testruns(namespace).Create(tr) + err := tmClient.Client().Create(ctx, tr) if err == nil { defer utils.DeleteTestrun(tmClient, tr) } @@ -92,13 +92,14 @@ var _ = Describe("Testrun validation tests", func() { }) It("should reject when a local location is defined", func() { - + ctx := context.Background() + defer ctx.Done() tr := resources.GetBasicTestrun(namespace, commitSha) tr.Spec.TestLocations = append(tr.Spec.TestLocations, tmv1beta1.TestLocation{ Type: tmv1beta1.LocationTypeLocal, }) - tr, err := tmClient.Testmachinery().Testruns(namespace).Create(tr) + err := tmClient.Client().Create(ctx, tr) if err == nil { defer utils.DeleteTestrun(tmClient, tr) } @@ -109,11 +110,12 @@ var _ = Describe("Testrun validation tests", func() { Context("Testflow", func() { It("should reject when no locations can be found", func() { - + ctx := context.Background() + defer ctx.Done() tr := resources.GetBasicTestrun(namespace, commitSha) tr.Spec.TestFlow = [][]tmv1beta1.TestflowStep{} - tr, err := tmClient.Testmachinery().Testruns(namespace).Create(tr) + err := tmClient.Client().Create(ctx, tr) if err == nil { defer utils.DeleteTestrun(tmClient, tr) } @@ -122,7 +124,8 @@ var _ = Describe("Testrun validation tests", func() { }) It("should reject when a no locations for only one label in the testrun can be found", func() { - + ctx := context.Background() + defer ctx.Done() tr := resources.GetBasicTestrun(namespace, commitSha) tr.Spec.TestFlow = [][]tmv1beta1.TestflowStep{ { @@ -132,7 +135,7 @@ var _ = Describe("Testrun validation tests", func() { }, } - tr, err := tmClient.Testmachinery().Testruns(namespace).Create(tr) + err := tmClient.Client().Create(ctx, tr) if err == nil { defer utils.DeleteTestrun(tmClient, tr) } @@ -143,11 +146,12 @@ var _ = Describe("Testrun validation tests", func() { Context("Kubeconfigs", func() { It("should reject when a invalid kubeconfig is provided", func() { - + ctx := context.Background() + defer ctx.Done() tr := resources.GetBasicTestrun(namespace, commitSha) tr.Spec.Kubeconfigs.Gardener = "dGVzdGluZwo=" - tr, err := tmClient.Testmachinery().Testruns(namespace).Create(tr) + err := tmClient.Client().Create(ctx, tr) if err == nil { defer utils.DeleteTestrun(tmClient, tr) } @@ -158,15 +162,16 @@ var _ = Describe("Testrun validation tests", func() { Context("OnExit", func() { It("should accept when no steps are defined", func() { - + ctx := context.Background() + defer ctx.Done() tr := resources.GetBasicTestrun(namespace, commitSha) - tr, err := tmClient.Testmachinery().Testruns(namespace).Create(tr) + err := tmClient.Client().Create(ctx, tr) defer utils.DeleteTestrun(tmClient, tr) Expect(err).ToNot(HaveOccurred()) - _, err = tmClient.Testmachinery().Testruns(namespace).Get(tr.Name, metav1.GetOptions{}) + err = tmClient.Client().Get(ctx, client.ObjectKey{Namespace: namespace, Name: tr.Name}, nil) Expect(err).ToNot(HaveOccurred()) }) diff --git a/vendor/github.com/gardener/gardener/charts/seed-terraformer/charts/terraformer/charts/terraformer-common b/vendor/github.com/gardener/gardener/charts/seed-terraformer/charts/terraformer/charts/terraformer-common deleted file mode 120000 index c690daa804..0000000000 --- a/vendor/github.com/gardener/gardener/charts/seed-terraformer/charts/terraformer/charts/terraformer-common +++ /dev/null @@ -1 +0,0 @@ -../../terraformer-common \ No newline at end of file diff --git a/vendor/github.com/gardener/gardener/charts/seed-terraformer/charts/terraformer/charts/utils-templates b/vendor/github.com/gardener/gardener/charts/seed-terraformer/charts/terraformer/charts/utils-templates deleted file mode 120000 index 84502af3c5..0000000000 --- a/vendor/github.com/gardener/gardener/charts/seed-terraformer/charts/terraformer/charts/utils-templates +++ /dev/null @@ -1 +0,0 @@ -../../../../utils-templates \ No newline at end of file diff --git a/vendor/github.com/gardener/gardener/charts/shoot-cloud-config/charts/original/charts/utils-templates b/vendor/github.com/gardener/gardener/charts/shoot-cloud-config/charts/original/charts/utils-templates deleted file mode 120000 index 84502af3c5..0000000000 --- a/vendor/github.com/gardener/gardener/charts/shoot-cloud-config/charts/original/charts/utils-templates +++ /dev/null @@ -1 +0,0 @@ -../../../../utils-templates \ No newline at end of file diff --git a/vendor/github.com/gardener/gardener/pkg/apis/garden/types.go b/vendor/github.com/gardener/gardener/pkg/apis/garden/types.go index a6c39aefaf..7f6f902f66 100644 --- a/vendor/github.com/gardener/gardener/pkg/apis/garden/types.go +++ b/vendor/github.com/gardener/gardener/pkg/apis/garden/types.go @@ -200,7 +200,7 @@ type GCPMachineImage struct { // Name is the name of the image. Name MachineImageName // Image is the technical name of the image. It contains the image name and the Google Cloud project. - // Example: projects/coreos-cloud/global/images/coreos-stable-1576-5-0-v20180105 + // Example: projects//global/images/version23 Image string } @@ -381,7 +381,11 @@ type MachineImageName string const ( // MachineImageCoreOS is a constant for the CoreOS machine image. - MachineImageCoreOS MachineImageName = "CoreOS" + MachineImageCoreOS MachineImageName = "coreos" + // MachineImageCoreOSAlicloud is a constant for the CoreOS machine image used by Alicloud. + // The Alicloud CoreOS image is modified (e.g., it does not support cloud-config, and is therefore + // treated like another OS). + MachineImageCoreOSAlicloud MachineImageName = "coreos-alicloud" ) //////////////////////////////////////////////////// @@ -940,6 +944,8 @@ type GCPNetworks struct { // VPC indicates whether to use an existing VPC or create a new one. // +optional VPC *GCPVPC + // Internal is a private subnet (used for internal load balancers). + Internal *CIDR // Workers is a list of CIDRs of worker subnets (private) to create (used for the VMs). Workers []CIDR } @@ -1371,8 +1377,28 @@ type KubeSchedulerConfig struct { // KubeProxyConfig contains configuration settings for the kube-proxy. type KubeProxyConfig struct { KubernetesConfig + // Mode specifies which proxy mode to use. + // defaults to IPTables. + Mode *ProxyMode } +// ProxyMode available in Linux platform: 'userspace' (older, going to be EOL), 'iptables' +// (newer, faster), 'ipvs'(newest, better in performance and scalability). +// +// As of now only 'iptables' and 'ipvs' is supported by Gardener. +// +// In Linux platform, if the iptables proxy is selected, regardless of how, but the system's kernel or iptables versions are +// insufficient, this always falls back to the userspace proxy. IPVS mode will be enabled when proxy mode is set to 'ipvs', +// and the fall back path is firstly iptables and then userspace. +type ProxyMode string + +const ( + // ProxyModeIPTables uses iptables as proxy implementation. + ProxyModeIPTables ProxyMode = "IPTables" + // ProxyModeIPVS uses ipvs as proxy implementation. + ProxyModeIPVS ProxyMode = "IPVS" +) + // KubeletConfig contains configuration settings for the kubelet. type KubeletConfig struct { KubernetesConfig diff --git a/vendor/github.com/gardener/gardener/pkg/apis/garden/v1beta1/defaults.go b/vendor/github.com/gardener/gardener/pkg/apis/garden/v1beta1/defaults.go index 6bc4d9bb2c..e8ee556c24 100644 --- a/vendor/github.com/gardener/gardener/pkg/apis/garden/v1beta1/defaults.go +++ b/vendor/github.com/gardener/gardener/pkg/apis/garden/v1beta1/defaults.go @@ -30,6 +30,7 @@ func SetDefaults_Shoot(obj *Shoot) { cloud = obj.Spec.Cloud defaultPodCIDR = DefaultPodNetworkCIDR defaultServiceCIDR = DefaultServiceNetworkCIDR + defaultProxyMode = ProxyModeIPTables ) if cloud.AWS != nil { @@ -74,10 +75,12 @@ func SetDefaults_Shoot(obj *Shoot) { if cloud.Alicloud != nil { if cloud.Alicloud.Networks.Pods == nil { - obj.Spec.Cloud.Alicloud.Networks.Pods = &defaultPodCIDR + podCIDR := CIDR("100.64.0.0/11") + obj.Spec.Cloud.Alicloud.Networks.Pods = &podCIDR } if cloud.Alicloud.Networks.Services == nil { - obj.Spec.Cloud.Alicloud.Networks.Services = &defaultServiceCIDR + svcCIDR := CIDR("100.104.0.0/13") + obj.Spec.Cloud.Alicloud.Networks.Services = &svcCIDR } if cloud.Alicloud.Networks.Nodes == nil { if cloud.Alicloud.Networks.VPC.CIDR != nil { @@ -117,6 +120,12 @@ func SetDefaults_Shoot(obj *Shoot) { obj.Spec.Kubernetes.AllowPrivilegedContainers = &trueVar } + if obj.Spec.Kubernetes.KubeProxy != nil { + if obj.Spec.Kubernetes.KubeProxy.Mode == nil { + obj.Spec.Kubernetes.KubeProxy.Mode = &defaultProxyMode + } + } + if obj.Spec.Maintenance == nil { mt := utils.RandomMaintenanceTimeWindow() diff --git a/vendor/github.com/gardener/gardener/pkg/apis/garden/v1beta1/types.go b/vendor/github.com/gardener/gardener/pkg/apis/garden/v1beta1/types.go index 336fd4c55e..1991e3cd29 100644 --- a/vendor/github.com/gardener/gardener/pkg/apis/garden/v1beta1/types.go +++ b/vendor/github.com/gardener/gardener/pkg/apis/garden/v1beta1/types.go @@ -201,7 +201,7 @@ type GCPMachineImage struct { // Name is the name of the image. Name MachineImageName `json:"name"` // Image is the technical name of the image. It contains the image name and the Google Cloud project. - // Example: projects/coreos-cloud/global/images/coreos-stable-1576-5-0-v20180105 + // Example: projects//global/images/version23 Image string `json:"image"` } @@ -375,7 +375,13 @@ type MachineImageName string const ( // MachineImageCoreOS is a constant for the CoreOS machine image. - MachineImageCoreOS MachineImageName = "CoreOS" + // deprecated + MachineImageCoreOS MachineImageName = "coreos" + // MachineImageCoreOSAlicloud is a constant for the CoreOS machine image used by Alicloud. + // The Alicloud CoreOS image is modified (e.g., it does not support cloud-config, and is therefore + // treated like another OS). + // deprecated + MachineImageCoreOSAlicloud MachineImageName = "coreos-alicloud" ) //////////////////////////////////////////////////// @@ -827,10 +833,10 @@ type Alicloud struct { type AlicloudVPC struct { // ID is the Alicloud VPC id of an existing VPC. // +optional - ID *string ` json:"id"` + ID *string `json:"id,omitempty"` // CIDR is a CIDR range for a new VPC. // +optional - CIDR *CIDR `json:"cidr"` + CIDR *CIDR `json:"cidr,omitempty"` } // AlicloudNetworks holds information about the Kubernetes and infrastructure networks. @@ -924,6 +930,9 @@ type GCPNetworks struct { VPC *GCPVPC `json:"vpc,omitempty"` // Workers is a list of CIDRs of worker subnets (private) to create (used for the VMs). Workers []CIDR `json:"workers"` + // Internal is a private subnet (used for internal load balancers). + // +optional + Internal *CIDR `json:"internal,omitempty"` } // GCPVPC indicates whether to use an existing VPC or create a new one. @@ -1416,8 +1425,29 @@ type KubeSchedulerConfig struct { // KubeProxyConfig contains configuration settings for the kube-proxy. type KubeProxyConfig struct { KubernetesConfig `json:",inline"` + // Mode specifies which proxy mode to use. + // defaults to IPTables. + // +optional + Mode *ProxyMode `json:"mode,omitempty"` } +// ProxyMode available in Linux platform: 'userspace' (older, going to be EOL), 'iptables' +// (newer, faster), 'ipvs'(newest, better in performance and scalability). +// +// As of now only 'iptables' and 'ipvs' is supported by Gardener. +// +// In Linux platform, if the iptables proxy is selected, regardless of how, but the system's kernel or iptables versions are +// insufficient, this always falls back to the userspace proxy. IPVS mode will be enabled when proxy mode is set to 'ipvs', +// and the fall back path is firstly iptables and then userspace. +type ProxyMode string + +const ( + // ProxyModeIPTables uses iptables as proxy implementation. + ProxyModeIPTables ProxyMode = "IPTables" + // ProxyModeIPVS uses ipvs as proxy implementation. + ProxyModeIPVS ProxyMode = "IPVS" +) + // KubeletConfig contains configuration settings for the kubelet. type KubeletConfig struct { KubernetesConfig `json:",inline"` diff --git a/vendor/github.com/gardener/gardener/pkg/apis/garden/v1beta1/zz_generated.conversion.go b/vendor/github.com/gardener/gardener/pkg/apis/garden/v1beta1/zz_generated.conversion.go index 0fe22c4820..2a270e5137 100644 --- a/vendor/github.com/gardener/gardener/pkg/apis/garden/v1beta1/zz_generated.conversion.go +++ b/vendor/github.com/gardener/gardener/pkg/apis/garden/v1beta1/zz_generated.conversion.go @@ -2686,6 +2686,7 @@ func autoConvert_v1beta1_GCPNetworks_To_garden_GCPNetworks(in *GCPNetworks, out } out.VPC = (*garden.GCPVPC)(unsafe.Pointer(in.VPC)) out.Workers = *(*[]garden.CIDR)(unsafe.Pointer(&in.Workers)) + out.Internal = (*garden.CIDR)(unsafe.Pointer(in.Internal)) return nil } @@ -2699,6 +2700,7 @@ func autoConvert_garden_GCPNetworks_To_v1beta1_GCPNetworks(in *garden.GCPNetwork return err } out.VPC = (*GCPVPC)(unsafe.Pointer(in.VPC)) + out.Internal = (*CIDR)(unsafe.Pointer(in.Internal)) out.Workers = *(*[]CIDR)(unsafe.Pointer(&in.Workers)) return nil } @@ -3090,6 +3092,7 @@ func autoConvert_v1beta1_KubeProxyConfig_To_garden_KubeProxyConfig(in *KubeProxy if err := Convert_v1beta1_KubernetesConfig_To_garden_KubernetesConfig(&in.KubernetesConfig, &out.KubernetesConfig, s); err != nil { return err } + out.Mode = (*garden.ProxyMode)(unsafe.Pointer(in.Mode)) return nil } @@ -3102,6 +3105,7 @@ func autoConvert_garden_KubeProxyConfig_To_v1beta1_KubeProxyConfig(in *garden.Ku if err := Convert_garden_KubernetesConfig_To_v1beta1_KubernetesConfig(&in.KubernetesConfig, &out.KubernetesConfig, s); err != nil { return err } + out.Mode = (*ProxyMode)(unsafe.Pointer(in.Mode)) return nil } diff --git a/vendor/github.com/gardener/gardener/pkg/apis/garden/v1beta1/zz_generated.deepcopy.go b/vendor/github.com/gardener/gardener/pkg/apis/garden/v1beta1/zz_generated.deepcopy.go index 7602619a5c..ee9f4869d6 100644 --- a/vendor/github.com/gardener/gardener/pkg/apis/garden/v1beta1/zz_generated.deepcopy.go +++ b/vendor/github.com/gardener/gardener/pkg/apis/garden/v1beta1/zz_generated.deepcopy.go @@ -1316,6 +1316,11 @@ func (in *GCPNetworks) DeepCopyInto(out *GCPNetworks) { *out = make([]CIDR, len(*in)) copy(*out, *in) } + if in.Internal != nil { + in, out := &in.Internal, &out.Internal + *out = new(CIDR) + **out = **in + } return } @@ -1698,6 +1703,11 @@ func (in *KubeLego) DeepCopy() *KubeLego { func (in *KubeProxyConfig) DeepCopyInto(out *KubeProxyConfig) { *out = *in in.KubernetesConfig.DeepCopyInto(&out.KubernetesConfig) + if in.Mode != nil { + in, out := &in.Mode, &out.Mode + *out = new(ProxyMode) + **out = **in + } return } diff --git a/vendor/github.com/gardener/gardener/pkg/apis/garden/zz_generated.deepcopy.go b/vendor/github.com/gardener/gardener/pkg/apis/garden/zz_generated.deepcopy.go index 7ef536de59..56597ed01e 100644 --- a/vendor/github.com/gardener/gardener/pkg/apis/garden/zz_generated.deepcopy.go +++ b/vendor/github.com/gardener/gardener/pkg/apis/garden/zz_generated.deepcopy.go @@ -1308,6 +1308,11 @@ func (in *GCPNetworks) DeepCopyInto(out *GCPNetworks) { *out = new(GCPVPC) **out = **in } + if in.Internal != nil { + in, out := &in.Internal, &out.Internal + *out = new(CIDR) + **out = **in + } if in.Workers != nil { in, out := &in.Workers, &out.Workers *out = make([]CIDR, len(*in)) @@ -1679,6 +1684,11 @@ func (in *KubeLego) DeepCopy() *KubeLego { func (in *KubeProxyConfig) DeepCopyInto(out *KubeProxyConfig) { *out = *in in.KubernetesConfig.DeepCopyInto(&out.KubernetesConfig) + if in.Mode != nil { + in, out := &in.Mode, &out.Mode + *out = new(ProxyMode) + **out = **in + } return } diff --git a/vendor/github.com/gardener/gardener/pkg/chartrenderer/default.go b/vendor/github.com/gardener/gardener/pkg/chartrenderer/default.go index f6d847019e..1be2992da6 100644 --- a/vendor/github.com/gardener/gardener/pkg/chartrenderer/default.go +++ b/vendor/github.com/gardener/gardener/pkg/chartrenderer/default.go @@ -21,10 +21,10 @@ import ( "path" "strings" - "k8s.io/helm/pkg/engine" + "k8s.io/client-go/kubernetes" - "github.com/gardener/gardener/pkg/client/kubernetes" "k8s.io/helm/pkg/chartutil" + "k8s.io/helm/pkg/engine" chartapi "k8s.io/helm/pkg/proto/hapi/chart" "k8s.io/helm/pkg/timeconv" ) @@ -43,7 +43,7 @@ type DefaultChartRenderer struct { // New creates a new DefaultChartRenderer object. It requires a Kubernetes client as input which will be // injected in the Tiller environment. func New(client kubernetes.Interface) (ChartRenderer, error) { - sv, err := client.Kubernetes().Discovery().ServerVersion() + sv, err := client.Discovery().ServerVersion() if err != nil { return nil, fmt.Errorf("failed to get kubernetes server version %v", err) } diff --git a/vendor/github.com/gardener/gardener/pkg/client/kubernetes/apply.go b/vendor/github.com/gardener/gardener/pkg/client/kubernetes/apply.go index 220f42bd27..fab52e936c 100644 --- a/vendor/github.com/gardener/gardener/pkg/client/kubernetes/apply.go +++ b/vendor/github.com/gardener/gardener/pkg/client/kubernetes/apply.go @@ -18,7 +18,6 @@ import ( "bytes" "context" "fmt" - "io" "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -67,7 +66,7 @@ func NewApplierForConfig(config *rest.Config) (*Applier, error) { return NewApplierInternal(config, cachedDiscoveryClient) } -func (c *Applier) applyObject(ctx context.Context, desired *unstructured.Unstructured) error { +func (c *Applier) applyObject(ctx context.Context, desired *unstructured.Unstructured, options ApplierOptions) error { if desired.GetNamespace() == "" { desired.SetNamespace(metav1.NamespaceDefault) } @@ -95,50 +94,59 @@ func (c *Applier) applyObject(ctx context.Context, desired *unstructured.Unstruc return err } - if err := c.mergeObjects(desired, current); err != nil { + if err := c.mergeObjects(desired, current, options.MergeFuncs); err != nil { return err } return c.client.Update(ctx, desired) } -func (c *Applier) mergeObjects(newObj *unstructured.Unstructured, oldObj *unstructured.Unstructured) error { +// DefaultApplierOptions contains options for common k8s objects, e.g. Service, ServiceAccount. +var DefaultApplierOptions = ApplierOptions{ + MergeFuncs: map[Kind]MergeFunc{ + "Service": func(newObj, oldObj *unstructured.Unstructured) { + // We do not want to overwrite a Service's `.spec.clusterIP' or '.spec.ports[*].nodePort' values. + oldPorts := oldObj.Object["spec"].(map[string]interface{})["ports"].([]interface{}) + newPorts := newObj.Object["spec"].(map[string]interface{})["ports"].([]interface{}) + ports := []map[string]interface{}{} + + // Check whether ports of the newObj have also been present previously. If yes, take the nodePort + // of the existing object. + for _, newPort := range newPorts { + np := newPort.(map[string]interface{}) + + for _, oldPort := range oldPorts { + op := oldPort.(map[string]interface{}) + // np["port"] is of type float64 (due to Helm Tiller rendering) while op["port"] is of type int64. + // Equality can only be checked via their string representations. + if fmt.Sprintf("%v", np["port"]) == fmt.Sprintf("%v", op["port"]) { + if nodePort, ok := op["nodePort"]; ok { + np["nodePort"] = nodePort + } + } + } + ports = append(ports, np) + } + + newObj.Object["spec"].(map[string]interface{})["clusterIP"] = oldObj.Object["spec"].(map[string]interface{})["clusterIP"] + newObj.Object["spec"].(map[string]interface{})["ports"] = ports + }, + "ServiceAccount": func(newObj, oldObj *unstructured.Unstructured) { + // We do not want to overwrite a ServiceAccount's `.secrets[]` list or `.imagePullSecrets[]`. + newObj.Object["secrets"] = oldObj.Object["secrets"] + newObj.Object["imagePullSecrets"] = oldObj.Object["imagePullSecrets"] + }, + }, +} + +func (c *Applier) mergeObjects(newObj, oldObj *unstructured.Unstructured, mergeFuncs map[Kind]MergeFunc) error { newObj.SetResourceVersion(oldObj.GetResourceVersion()) // We do not want to overwrite the Finalizers. newObj.Object["metadata"].(map[string]interface{})["finalizers"] = oldObj.Object["metadata"].(map[string]interface{})["finalizers"] - switch newObj.GetKind() { - case "Service": - // We do not want to overwrite a Service's `.spec.clusterIP' or '.spec.ports[*].nodePort' values. - oldPorts := oldObj.Object["spec"].(map[string]interface{})["ports"].([]interface{}) - newPorts := newObj.Object["spec"].(map[string]interface{})["ports"].([]interface{}) - ports := []map[string]interface{}{} - - // Check whether ports of the newObj have also been present previously. If yes, take the nodePort - // of the existing object. - for _, newPort := range newPorts { - np := newPort.(map[string]interface{}) - - for _, oldPort := range oldPorts { - op := oldPort.(map[string]interface{}) - // np["port"] is of type float64 (due to Helm Tiller rendering) while op["port"] is of type int64. - // Equality can only be checked via their string representations. - if fmt.Sprintf("%v", np["port"]) == fmt.Sprintf("%v", op["port"]) { - if nodePort, ok := op["nodePort"]; ok { - np["nodePort"] = nodePort - } - } - } - ports = append(ports, np) - } - - newObj.Object["spec"].(map[string]interface{})["clusterIP"] = oldObj.Object["spec"].(map[string]interface{})["clusterIP"] - newObj.Object["spec"].(map[string]interface{})["ports"] = ports - case "ServiceAccount": - // We do not want to overwrite a ServiceAccount's `.secrets[]` list or `.imagePullSecrets[]`. - newObj.Object["secrets"] = oldObj.Object["secrets"] - newObj.Object["imagePullSecrets"] = oldObj.Object["imagePullSecrets"] + if merge, ok := mergeFuncs[Kind(newObj.GetKind())]; ok { + merge(newObj, oldObj) } return nil @@ -147,28 +155,74 @@ func (c *Applier) mergeObjects(newObj *unstructured.Unstructured, oldObj *unstru // ApplyManifest is a function which does the same like `kubectl apply -f `. It takes a bunch of manifests , // all concatenated in a byte slice, and sends them one after the other to the API server. If a resource // already exists at the API server, it will update it. It returns an error as soon as the first error occurs. -func (c *Applier) ApplyManifest(ctx context.Context, m []byte) error { +func (c *Applier) ApplyManifest(ctx context.Context, r UnstructuredReader, options ApplierOptions) error { + for obj, err := r.Read(); err == nil; obj, err = r.Read() { + if obj == nil { + continue + } + if err := c.applyObject(ctx, obj, options); err != nil { + return err + } + } + return nil +} + +// UnstructuredReader an interface that all manifest readers should implement +type UnstructuredReader interface { + Read() (*unstructured.Unstructured, error) +} + +// NewManifestReader initializes a reader for yaml manifests +func NewManifestReader(manifest []byte) UnstructuredReader { + return &manifestReader{ + decoder: yaml.NewYAMLOrJSONDecoder(bytes.NewReader(manifest), 1024), + } +} + +// manifestReader is an unstructured reader that contains a JSONDecoder +type manifestReader struct { + decoder *yaml.YAMLOrJSONDecoder +} + +// Read decodes yaml data into an unstructured object +func (m *manifestReader) Read() (*unstructured.Unstructured, error) { var ( - decoder = yaml.NewYAMLOrJSONDecoder(bytes.NewReader(m), 1024) - data map[string]interface{} - err error + data map[string]interface{} + err error ) - for err = decoder.Decode(&data); err == nil; err = decoder.Decode(&data) { + // loop for skipping empty yaml objects + for err = m.decoder.Decode(&data); err == nil; err = m.decoder.Decode(&data) { if data == nil { continue } + return &unstructured.Unstructured{Object: data}, nil + } + return nil, err +} - obj := &unstructured.Unstructured{Object: data} - data = nil - - if err := c.applyObject(ctx, obj); err != nil { - return err - } - obj = nil +// NewNamespaceSettingReader initializes a reader for yaml manifests with support for setting the namespace +func NewNamespaceSettingReader(mReader UnstructuredReader, namespace string) UnstructuredReader { + return &namespaceSettingReader{ + reader: mReader, + namespace: namespace, } - if err != io.EOF { - return err +} + +// namespaceSettingReader is an unstructured reader that contains a JSONDecoder and a manifest reader (or other reader types) +type namespaceSettingReader struct { + reader UnstructuredReader + namespace string +} + +// Read decodes yaml data into an unstructured object +func (n *namespaceSettingReader) Read() (*unstructured.Unstructured, error) { + readObj, err := n.reader.Read() + if err != nil { + return nil, err } - return nil + + readObj.SetNamespace(n.namespace) + + return readObj, nil } diff --git a/vendor/github.com/gardener/gardener/pkg/client/kubernetes/client.go b/vendor/github.com/gardener/gardener/pkg/client/kubernetes/client.go index 08d52032c5..2d996f7e1a 100644 --- a/vendor/github.com/gardener/gardener/pkg/client/kubernetes/client.go +++ b/vendor/github.com/gardener/gardener/pkg/client/kubernetes/client.go @@ -27,7 +27,6 @@ import ( corev1 "k8s.io/api/core/v1" apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" - apimachineryconfig "k8s.io/apimachinery/pkg/apis/config" kubernetesclientset "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" @@ -35,31 +34,25 @@ import ( ) // NewClientFromFile creates a new Client struct for a given kubeconfig. The kubeconfig will be -// read from the filesystem at location . +// read from the filesystem at location . If given, overrides the +// master URL in the kubeconfig. // If no filepath is given, the in-cluster configuration will be taken into account. -func NewClientFromFile(kubeconfigPath string, clientConnection *apimachineryconfig.ClientConnectionConfiguration, opts client.Options) (Interface, error) { - clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( - &clientcmd.ClientConfigLoadingRules{ExplicitPath: kubeconfigPath}, - &clientcmd.ConfigOverrides{}, - ) - config, err := CreateRESTConfig(clientConfig, clientConnection) +func NewClientFromFile(masterURL, kubeconfigPath string, opts client.Options) (Interface, error) { + config, err := clientcmd.BuildConfigFromFlags(masterURL, kubeconfigPath) if err != nil { return nil, err } + return NewForConfig(config, opts) } // NewClientFromBytes creates a new Client struct for a given kubeconfig byte slice. -func NewClientFromBytes(kubeconfig []byte, clientConnection *apimachineryconfig.ClientConnectionConfiguration, opts client.Options) (Interface, error) { - configObj, err := clientcmd.Load(kubeconfig) - if err != nil { - return nil, err - } - clientConfig := clientcmd.NewDefaultClientConfig(*configObj, &clientcmd.ConfigOverrides{}) - config, err := CreateRESTConfig(clientConfig, clientConnection) +func NewClientFromBytes(kubeconfig []byte, opts client.Options) (Interface, error) { + config, err := clientcmd.RESTConfigFromKubeConfig(kubeconfig) if err != nil { return nil, err } + return NewForConfig(config, opts) } @@ -79,25 +72,9 @@ func NewClientFromSecret(k8sClient Interface, namespace, secretName string, opts // contain a field "kubeconfig" which will be used. func NewClientFromSecretObject(secret *corev1.Secret, opts client.Options) (Interface, error) { if kubeconfig, ok := secret.Data["kubeconfig"]; ok { - return NewClientFromBytes(kubeconfig, nil, opts) - } - return nil, errors.New("The secret does not contain a field with name 'kubeconfig'") -} - -// CreateRESTConfig creates a Config object for a rest client. If a clientConnection configuration object is passed -// as well then the specified fields will be taken over as well. -func CreateRESTConfig(clientConfig clientcmd.ClientConfig, clientConnection *apimachineryconfig.ClientConnectionConfiguration) (*rest.Config, error) { - config, err := clientConfig.ClientConfig() - if err != nil { - return nil, err - } - if clientConnection != nil { - config.Burst = int(clientConnection.Burst) - config.QPS = clientConnection.QPS - config.AcceptContentTypes = clientConnection.AcceptContentTypes - config.ContentType = clientConnection.ContentType + return NewClientFromBytes(kubeconfig, opts) } - return config, nil + return nil, errors.New("the secret does not contain a field with name 'kubeconfig'") } var supportedKubernetesVersions = []string{ diff --git a/vendor/github.com/gardener/gardener/pkg/client/kubernetes/clientset.go b/vendor/github.com/gardener/gardener/pkg/client/kubernetes/clientset.go index 794571465a..a6835f610b 100644 --- a/vendor/github.com/gardener/gardener/pkg/client/kubernetes/clientset.go +++ b/vendor/github.com/gardener/gardener/pkg/client/kubernetes/clientset.go @@ -105,16 +105,6 @@ func (c *Clientset) RESTClient() rest.Interface { return c.restClient } -// SetGarden will set the garden attribute of the Client object. -func (c *Clientset) SetGarden(client gardenclientset.Interface) { - c.garden = client -} - -// SetGardenCore will set the gardenCore attribute of the Client object. -func (c *Clientset) SetGardenCore(client gardencoreclientset.Interface) { - c.gardenCore = client -} - // Version returns the GitVersion of the Kubernetes client stored on the object. func (c *Clientset) Version() string { return c.version diff --git a/vendor/github.com/gardener/gardener/pkg/client/kubernetes/deployments.go b/vendor/github.com/gardener/gardener/pkg/client/kubernetes/deployments.go index 11bdd85ff4..32c30eef3a 100644 --- a/vendor/github.com/gardener/gardener/pkg/client/kubernetes/deployments.go +++ b/vendor/github.com/gardener/gardener/pkg/client/kubernetes/deployments.go @@ -17,8 +17,6 @@ package kubernetes import ( "sort" - kutil "github.com/gardener/gardener/pkg/utils/kubernetes" - appsv1 "k8s.io/api/apps/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" @@ -46,33 +44,6 @@ func (c *Clientset) PatchDeployment(namespace, name string, body []byte) (*appsv return c.Kubernetes().AppsV1().Deployments(namespace).Patch(name, types.JSONPatchType, body) } -// ScaleDeployment scales a Deployment object. -func (c *Clientset) ScaleDeployment(namespace, name string, replicas int32) (*appsv1.Deployment, error) { - old, err := c.GetDeployment(namespace, name) - if err != nil { - return nil, err - } - - new := old.DeepCopy() - new.Spec.Replicas = &replicas - - return c.StrategicMergePatchDeployment(old, new) -} - -// StrategicMergePatchDeployment performs a strategic merge patch on a Deployment object. -func (c *Clientset) StrategicMergePatchDeployment(oldObj, newObj *appsv1.Deployment) (*appsv1.Deployment, error) { - patch, err := kutil.CreateTwoWayMergePatch(oldObj, newObj) - if err != nil { - return nil, err - } - - if kutil.IsEmptyPatch(patch) { - return oldObj, nil - } - - return c.kubernetes.AppsV1().Deployments(oldObj.Namespace).Patch(oldObj.Name, types.StrategicMergePatchType, patch) -} - // DeleteDeployment deletes a Deployment object. func (c *Clientset) DeleteDeployment(namespace, name string) error { return c.Kubernetes().AppsV1().Deployments(namespace).Delete(name, &defaultDeleteOptions) diff --git a/vendor/github.com/gardener/gardener/pkg/client/kubernetes/pods.go b/vendor/github.com/gardener/gardener/pkg/client/kubernetes/pods.go index a83d70e4bf..d975fd30ae 100644 --- a/vendor/github.com/gardener/gardener/pkg/client/kubernetes/pods.go +++ b/vendor/github.com/gardener/gardener/pkg/client/kubernetes/pods.go @@ -16,55 +16,113 @@ package kubernetes import ( "bytes" + "context" "errors" "fmt" "io" "io/ioutil" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" "net/http" "sort" + "strings" "time" + corev1client "k8s.io/client-go/kubernetes/typed/core/v1" + + "k8s.io/client-go/rest" + "github.com/gardener/gardener/pkg/utils" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/tools/portforward" + "k8s.io/client-go/tools/remotecommand" "k8s.io/client-go/transport/spdy" ) -// GetPod will return the Pod object for the given in the given . -func (c *Clientset) GetPod(namespace, name string) (*corev1.Pod, error) { - return c.kubernetes.CoreV1().Pods(namespace).Get(name, metav1.GetOptions{}) +// NewPodExecutor returns a podExecutor +func NewPodExecutor(config *rest.Config) PodExecutor { + return &podExecutor{ + config: config, + } } -// ListPods will list all the Pods in the given for the given . -func (c *Clientset) ListPods(namespace string, listOptions metav1.ListOptions) (*corev1.PodList, error) { - pods, err := c.kubernetes.CoreV1().Pods(namespace).List(listOptions) +// PodExecutor is the pod executor interface +type PodExecutor interface { + Execute(ctx context.Context, name, namespace, containerName, command string) (io.Reader, error) +} + +type podExecutor struct { + config *rest.Config +} + +// Execute executes a command on a pod +func (p *podExecutor) Execute(ctx context.Context, namespace, name, containerName, command string) (io.Reader, error) { + client, err := corev1client.NewForConfig(p.config) if err != nil { return nil, err } - sort.Slice(pods.Items, func(i, j int) bool { - return pods.Items[i].ObjectMeta.CreationTimestamp.Before(&pods.Items[j].ObjectMeta.CreationTimestamp) + + var stdout, stderr bytes.Buffer + request := client.RESTClient(). + Post(). + Resource("pods"). + Name(name). + Namespace(namespace). + SubResource("exec"). + Param("container", containerName). + Param("command", "/bin/sh"). + Param("stdin", "true"). + Param("stdout", "true"). + Param("stderr", "true"). + Param("tty", "false"). + Context(ctx) + + executor, err := remotecommand.NewSPDYExecutor(p.config, http.MethodPost, request.URL()) + if err != nil { + return nil, fmt.Errorf("failed to initialized the command exector: %v", err) + } + + err = executor.Stream(remotecommand.StreamOptions{ + Stdin: strings.NewReader(command), + Stdout: &stdout, + Stderr: &stderr, + Tty: false, }) - return pods, nil + if err != nil { + return nil, err + } + + return &stdout, nil } -// GetPodLogs will get the logs of all containers within the Pod for the given in the given -// for the given . -func (c *Clientset) GetPodLogs(namespace, name string, podLogOptions *corev1.PodLogOptions) (*bytes.Buffer, error) { - request := c.kubernetes.CoreV1().Pods(namespace).GetLogs(name, podLogOptions) +// GetPodLogs retrieves the pod logs of the pod of the given name with the given options. +func GetPodLogs(podInterface corev1client.PodInterface, name string, options *corev1.PodLogOptions) ([]byte, error) { + request := podInterface.GetLogs(name, options) stream, err := request.Stream() if err != nil { return nil, err } + defer func() { utilruntime.HandleError(stream.Close()) }() - defer stream.Close() - buffer := bytes.NewBuffer(nil) - _, err = io.Copy(buffer, stream) + return ioutil.ReadAll(stream) +} + +// GetPod will return the Pod object for the given in the given . +func (c *Clientset) GetPod(namespace, name string) (*corev1.Pod, error) { + return c.kubernetes.CoreV1().Pods(namespace).Get(name, metav1.GetOptions{}) +} + +// ListPods will list all the Pods in the given for the given . +func (c *Clientset) ListPods(namespace string, listOptions metav1.ListOptions) (*corev1.PodList, error) { + pods, err := c.kubernetes.CoreV1().Pods(namespace).List(listOptions) if err != nil { return nil, err } - return buffer, nil + sort.Slice(pods.Items, func(i, j int) bool { + return pods.Items[i].ObjectMeta.CreationTimestamp.Before(&pods.Items[j].ObjectMeta.CreationTimestamp) + }) + return pods, nil } // ForwardPodPort tries to forward the port of the pod with name in namespace to diff --git a/vendor/github.com/gardener/gardener/pkg/client/kubernetes/types.go b/vendor/github.com/gardener/gardener/pkg/client/kubernetes/types.go index 300e65f84d..f4535d33dc 100644 --- a/vendor/github.com/gardener/gardener/pkg/client/kubernetes/types.go +++ b/vendor/github.com/gardener/gardener/pkg/client/kubernetes/types.go @@ -1,4 +1,4 @@ -// Copyright (c) 2018 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the LICENSE file +// Copyright (c) 2019 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the LICENSE file // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,10 +15,11 @@ package kubernetes import ( - "bytes" "context" gardencoreclientset "github.com/gardener/gardener/pkg/client/core/clientset/versioned" + gardencorescheme "github.com/gardener/gardener/pkg/client/core/clientset/versioned/scheme" + gardenextensionsscheme "github.com/gardener/gardener/pkg/client/extensions/clientset/versioned/scheme" gardenclientset "github.com/gardener/gardener/pkg/client/garden/clientset/versioned" gardenscheme "github.com/gardener/gardener/pkg/client/garden/clientset/versioned/scheme" machineclientset "github.com/gardener/gardener/pkg/client/machine/clientset/versioned" @@ -34,6 +35,7 @@ import ( apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" "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/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/client-go/discovery" @@ -117,14 +119,15 @@ func init() { gardenSchemeBuilder := runtime.NewSchemeBuilder( corescheme.AddToScheme, gardenscheme.AddToScheme, + gardencorescheme.AddToScheme, ) utilruntime.Must(gardenSchemeBuilder.AddToScheme(GardenScheme)) seedSchemeBuilder := runtime.NewSchemeBuilder( corescheme.AddToScheme, - gardenscheme.AddToScheme, machinescheme.AddToScheme, + gardenextensionsscheme.AddToScheme, ) utilruntime.Must(seedSchemeBuilder.AddToScheme(SeedScheme)) @@ -173,10 +176,21 @@ type Applier struct { discovery discovery.CachedDiscoveryInterface } +// Kind is a type alias for a k8s Kind of ObjectKind. +type Kind string + +// MergeFunc determines how oldOj is merged into new oldObj. +type MergeFunc func(newObj, oldObj *unstructured.Unstructured) + +// ApplierOptions contains options used by the Applier. +type ApplierOptions struct { + MergeFuncs map[Kind]MergeFunc +} + // ApplierInterface is an interface which describes declarative operations to apply multiple // Kubernetes objects. type ApplierInterface interface { - ApplyManifest(ctx context.Context, data []byte) error + ApplyManifest(ctx context.Context, unstructured UnstructuredReader, options ApplierOptions) error } // Interface is used to wrap the interactions with a Kubernetes cluster @@ -197,11 +211,6 @@ type Interface interface { APIExtension() apiextensionsclientset.Interface APIRegistration() apiregistrationclientset.Interface - // Deprecated: Use `Client()` and utils instead. - SetGarden(gardenclientset.Interface) - // Deprecated: Use `Client()` and utils instead. - SetGardenCore(gardencoreclientset.Interface) - // Cleanup // Deprecated: Use `RESTMapper()` and utils instead. GetResourceAPIGroups() map[string][]string @@ -262,8 +271,6 @@ type Interface interface { // Deprecated: Use `Client()` and utils instead. PatchDeployment(string, string, []byte) (*appsv1.Deployment, error) // Deprecated: Use `Client()` and utils instead. - ScaleDeployment(string, string, int32) (*appsv1.Deployment, error) - // Deprecated: Use `Client()` and utils instead. DeleteDeployment(string, string) error // StatefulSets @@ -289,9 +296,9 @@ type Interface interface { GetPod(string, string) (*corev1.Pod, error) // Deprecated: Use `Client()` and utils instead. ListPods(string, metav1.ListOptions) (*corev1.PodList, error) + // Deprecated: Use `Client()` and utils instead. - GetPodLogs(string, string, *corev1.PodLogOptions) (*bytes.Buffer, error) - // Deprecated: Use `Client()` and utils instead. + ForwardPodPort(string, string, int, int) (chan struct{}, error) CheckForwardPodPort(string, string, int, int) (bool, error) // Deprecated: Use `Client()` and utils instead. DeletePod(string, string) error diff --git a/vendor/github.com/gardener/gardener/pkg/client/machine/clientset/versioned/typed/machine/v1alpha1/generated_expansion.go b/vendor/github.com/gardener/gardener/pkg/client/machine/clientset/versioned/typed/machine/v1alpha1/generated_expansion.go index 0a56e67b58..d19589dccd 100644 --- a/vendor/github.com/gardener/gardener/pkg/client/machine/clientset/versioned/typed/machine/v1alpha1/generated_expansion.go +++ b/vendor/github.com/gardener/gardener/pkg/client/machine/clientset/versioned/typed/machine/v1alpha1/generated_expansion.go @@ -36,4 +36,6 @@ type MachineTemplateExpansion interface{} type OpenStackMachineClassExpansion interface{} +type PacketMachineClassExpansion interface{} + type ScaleExpansion interface{} diff --git a/vendor/github.com/gardener/gardener/pkg/client/machine/clientset/versioned/typed/machine/v1alpha1/machine.go b/vendor/github.com/gardener/gardener/pkg/client/machine/clientset/versioned/typed/machine/v1alpha1/machine.go index 1cee3796a0..cc586c1eea 100644 --- a/vendor/github.com/gardener/gardener/pkg/client/machine/clientset/versioned/typed/machine/v1alpha1/machine.go +++ b/vendor/github.com/gardener/gardener/pkg/client/machine/clientset/versioned/typed/machine/v1alpha1/machine.go @@ -39,6 +39,7 @@ type MachinesGetter interface { type MachineInterface interface { Create(*v1alpha1.Machine) (*v1alpha1.Machine, error) Update(*v1alpha1.Machine) (*v1alpha1.Machine, error) + UpdateStatus(*v1alpha1.Machine) (*v1alpha1.Machine, error) Delete(name string, options *v1.DeleteOptions) error DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error Get(name string, options v1.GetOptions) (*v1alpha1.Machine, error) @@ -132,6 +133,22 @@ func (c *machines) Update(machine *v1alpha1.Machine) (result *v1alpha1.Machine, return } +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + +func (c *machines) UpdateStatus(machine *v1alpha1.Machine) (result *v1alpha1.Machine, err error) { + result = &v1alpha1.Machine{} + err = c.client.Put(). + Namespace(c.ns). + Resource("machines"). + Name(machine.Name). + SubResource("status"). + Body(machine). + Do(). + Into(result) + return +} + // Delete takes name of the machine and deletes it. Returns an error if one occurs. func (c *machines) Delete(name string, options *v1.DeleteOptions) error { return c.client.Delete(). diff --git a/vendor/github.com/gardener/gardener/pkg/client/machine/clientset/versioned/typed/machine/v1alpha1/machine_client.go b/vendor/github.com/gardener/gardener/pkg/client/machine/clientset/versioned/typed/machine/v1alpha1/machine_client.go index 489ecee27c..e881a99e90 100644 --- a/vendor/github.com/gardener/gardener/pkg/client/machine/clientset/versioned/typed/machine/v1alpha1/machine_client.go +++ b/vendor/github.com/gardener/gardener/pkg/client/machine/clientset/versioned/typed/machine/v1alpha1/machine_client.go @@ -36,6 +36,7 @@ type MachineV1alpha1Interface interface { MachineSetsGetter MachineTemplatesGetter OpenStackMachineClassesGetter + PacketMachineClassesGetter ScalesGetter } @@ -80,6 +81,10 @@ func (c *MachineV1alpha1Client) OpenStackMachineClasses(namespace string) OpenSt return newOpenStackMachineClasses(c, namespace) } +func (c *MachineV1alpha1Client) PacketMachineClasses(namespace string) PacketMachineClassInterface { + return newPacketMachineClasses(c, namespace) +} + func (c *MachineV1alpha1Client) Scales(namespace string) ScaleInterface { return newScales(c, namespace) } diff --git a/vendor/github.com/gardener/gardener/pkg/logger/logger.go b/vendor/github.com/gardener/gardener/pkg/logger/logger.go index 8362f87e8d..7fd12e635e 100644 --- a/vendor/github.com/gardener/gardener/pkg/logger/logger.go +++ b/vendor/github.com/gardener/gardener/pkg/logger/logger.go @@ -16,6 +16,7 @@ package logger import ( "fmt" + "io" "os" "github.com/sirupsen/logrus" @@ -54,6 +55,12 @@ func NewLogger(logLevel string) *logrus.Logger { return logger } +// AddWriter returns a logger that uses the tests writer (e.g., GingkoWriter) as output channel +func AddWriter(logger *logrus.Logger, writer io.Writer) *logrus.Logger { + logger.Out = writer + return logger +} + // NewShootLogger extends an existing logrus logger and adds an additional field containing the Shoot cluster name // and the project in the Garden cluster to the output. If an is provided it will be printed for every // log message. diff --git a/vendor/github.com/gardener/gardener/pkg/utils/kubernetes/kubernetes.go b/vendor/github.com/gardener/gardener/pkg/utils/kubernetes/kubernetes.go index 05c6db51a6..eec6b69b1b 100644 --- a/vendor/github.com/gardener/gardener/pkg/utils/kubernetes/kubernetes.go +++ b/vendor/github.com/gardener/gardener/pkg/utils/kubernetes/kubernetes.go @@ -1,6 +1,14 @@ package kubernetes -import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +import ( + "context" + "fmt" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client" +) // SetMetaDataLabel sets the key value pair in the labels section of the given ObjectMeta. // If the given ObjectMeta did not yet have labels, they are initialized. @@ -8,7 +16,6 @@ func SetMetaDataLabel(meta *metav1.ObjectMeta, key, value string) { if meta.Labels == nil { meta.Labels = make(map[string]string) } - meta.Labels[key] = value } @@ -17,3 +24,62 @@ func HasMetaDataAnnotation(meta *metav1.ObjectMeta, key, value string) bool { val, ok := meta.Annotations[key] return ok && val == value } + +// CreateOrUpdate creates or updates the object. Optionally, it executes a transformation function before the +// request is made. +func CreateOrUpdate(ctx context.Context, c client.Client, obj runtime.Object, transform func() error) error { + key, err := client.ObjectKeyFromObject(obj) + if err != nil { + return err + } + + if err := c.Get(ctx, key, obj); err != nil { + if apierrors.IsNotFound(err) { + if transform != nil && transform() != nil { + return err + } + return c.Create(ctx, obj) + } + return err + } + + if transform != nil && transform() != nil { + return err + } + return c.Update(ctx, obj) +} + +func nameAndNamespace(namespaceOrName string, nameOpt ...string) (namespace, name string) { + if len(nameOpt) > 1 { + panic(fmt.Sprintf("more than name/namespace for key specified: %s/%v", namespaceOrName, nameOpt)) + } + if len(nameOpt) == 0 { + name = namespaceOrName + return + } + namespace = namespaceOrName + name = nameOpt[0] + return +} + +// Key creates a new client.ObjectKey from the given parameters. +// There are only two ways to call this function: +// - If only namespaceOrName is set, then a client.ObjectKey with name set to namespaceOrName is returned. +// - If namespaceOrName and one nameOpt is given, then a client.ObjectKey with namespace set to namespaceOrName +// and name set to nameOpt[0] is returned. +// For all other cases, this method panics. +func Key(namespaceOrName string, nameOpt ...string) client.ObjectKey { + namespace, name := nameAndNamespace(namespaceOrName, nameOpt...) + return client.ObjectKey{Namespace: namespace, Name: name} +} + +// ObjectMeta creates a new metav1.ObjectMeta from the given parameters. +// There are only two ways to call this function: +// - If only namespaceOrName is set, then a metav1.ObjectMeta with name set to namespaceOrName is returned. +// - If namespaceOrName and one nameOpt is given, then a metav1.ObjectMeta with namespace set to namespaceOrName +// and name set to nameOpt[0] is returned. +// For all other cases, this method panics. +func ObjectMeta(namespaceOrName string, nameOpt ...string) metav1.ObjectMeta { + namespace, name := nameAndNamespace(namespaceOrName, nameOpt...) + return metav1.ObjectMeta{Namespace: namespace, Name: name} +} diff --git a/vendor/k8s.io/apimachinery/pkg/apis/config/doc.go b/vendor/k8s.io/apimachinery/pkg/apis/config/doc.go deleted file mode 100644 index d849c7aa3b..0000000000 --- a/vendor/k8s.io/apimachinery/pkg/apis/config/doc.go +++ /dev/null @@ -1,19 +0,0 @@ -/* -Copyright 2018 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. -*/ - -// +k8s:deepcopy-gen=package - -package config // import "k8s.io/apimachinery/pkg/apis/config" diff --git a/vendor/k8s.io/apimachinery/pkg/apis/config/types.go b/vendor/k8s.io/apimachinery/pkg/apis/config/types.go deleted file mode 100644 index b32fc8a281..0000000000 --- a/vendor/k8s.io/apimachinery/pkg/apis/config/types.go +++ /dev/null @@ -1,33 +0,0 @@ -/* -Copyright 2018 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 config - -// ClientConnectionConfiguration contains details for constructing a client. -type ClientConnectionConfiguration struct { - // kubeconfig is the path to a KubeConfig file. - Kubeconfig string - // acceptContentTypes defines the Accept header sent by clients when connecting to a server, overriding the - // default value of 'application/json'. This field will control all connections to the server used by a particular - // client. - AcceptContentTypes string - // contentType is the content type used when sending data to the server from this client. - ContentType string - // qps controls the number of queries per second allowed for this connection. - QPS float32 - // burst allows extra queries to accumulate when a client is exceeding its rate. - Burst int32 -} diff --git a/vendor/k8s.io/apimachinery/pkg/apis/config/zz_generated.deepcopy.go b/vendor/k8s.io/apimachinery/pkg/apis/config/zz_generated.deepcopy.go deleted file mode 100644 index f09beb0e38..0000000000 --- a/vendor/k8s.io/apimachinery/pkg/apis/config/zz_generated.deepcopy.go +++ /dev/null @@ -1,37 +0,0 @@ -// +build !ignore_autogenerated - -/* -Copyright 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. -*/ - -// Code generated by deepcopy-gen. DO NOT EDIT. - -package config - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ClientConnectionConfiguration) DeepCopyInto(out *ClientConnectionConfiguration) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClientConnectionConfiguration. -func (in *ClientConnectionConfiguration) DeepCopy() *ClientConnectionConfiguration { - if in == nil { - return nil - } - out := new(ClientConnectionConfiguration) - in.DeepCopyInto(out) - return out -}