From b5e9618ed95e84f92889bf066f71e66dc1187b2b Mon Sep 17 00:00:00 2001 From: Andreas Neumann Date: Wed, 27 Nov 2019 13:55:22 +0100 Subject: [PATCH 01/12] Start validation of KUDO installation when creating client --- pkg/kudoctl/cmd/init/crds.go | 33 ++++++++++++++++++++++++++++++--- pkg/kudoctl/cmd/init/manager.go | 17 +++++++++++++++++ pkg/kudoctl/util/kudo/kudo.go | 31 +++++++++++++++---------------- 3 files changed, 62 insertions(+), 19 deletions(-) diff --git a/pkg/kudoctl/cmd/init/crds.go b/pkg/kudoctl/cmd/init/crds.go index 09121c889..1950e5e48 100644 --- a/pkg/kudoctl/cmd/init/crds.go +++ b/pkg/kudoctl/cmd/init/crds.go @@ -1,8 +1,11 @@ package init import ( + "fmt" "strings" + "github.com/kudobuilder/kudo/pkg/kudoctl/kube" + "github.com/kudobuilder/kudo/pkg/kudoctl/clog" apiextv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" @@ -31,6 +34,17 @@ func installCrds(client apiextensionsclient.Interface) error { return nil } +func validateCrd(client v1beta1.CustomResourceDefinitionsGetter, crd *apiextv1beta1.CustomResourceDefinition) error { + existingCrd, err := client.CustomResourceDefinitions().Get(crd.Name, v1.GetOptions{}) + if err != nil { + return fmt.Errorf("failed to retrieve CRD %s", crd.Name) + } + if existingCrd.ResourceVersion != crd.ResourceVersion { + return fmt.Errorf("installed CRD %s has invalid version %s, expected %s", crd.Name, existingCrd.Spec.Version, crd.Spec.Version) + } + return nil +} + func install(client v1beta1.CustomResourceDefinitionsGetter, crd *apiextv1beta1.CustomResourceDefinition) error { _, err := client.CustomResourceDefinitions().Create(crd) if kerrors.IsAlreadyExists(err) { @@ -211,9 +225,9 @@ func generateCrd(kind string, plural string) *apiextv1beta1.CustomResourceDefini // KudoCrds represents custom resource definitions needed to run KUDO type KudoCrds struct { - Operator runtime.Object - OperatorVersion runtime.Object - Instance runtime.Object + Operator *apiextv1beta1.CustomResourceDefinition + OperatorVersion *apiextv1beta1.CustomResourceDefinition + Instance *apiextv1beta1.CustomResourceDefinition } // AsArray returns all CRDs as array of runtime objects @@ -236,6 +250,19 @@ func (c KudoCrds) AsYaml() ([]string, error) { return manifests, nil } +func (c KudoCrds) Validate(client *kube.Client) error { + if err := validateCrd(client.ExtClient.ApiextensionsV1beta1(), c.Operator); err != nil { + return err + } + if err := validateCrd(client.ExtClient.ApiextensionsV1beta1(), c.OperatorVersion); err != nil { + return err + } + if err := validateCrd(client.ExtClient.ApiextensionsV1beta1(), c.Instance); err != nil { + return err + } + return nil +} + // CRDs returns the runtime.Object representation of all the CRDs KUDO requires func CRDs() KudoCrds { return KudoCrds{ diff --git a/pkg/kudoctl/cmd/init/manager.go b/pkg/kudoctl/cmd/init/manager.go index 1312ab1a4..4e588aff8 100644 --- a/pkg/kudoctl/cmd/init/manager.go +++ b/pkg/kudoctl/cmd/init/manager.go @@ -82,6 +82,23 @@ func Install(client *kube.Client, opts Options, crdOnly bool) error { return nil } +func ValidateManager(client *kube.Client, opts Options) error { + s := generateDeployment(opts) + set, err := client.KubeClient.AppsV1().StatefulSets(opts.Namespace).Get(s.Name, metav1.GetOptions{}) + + if err != nil { + return fmt.Errorf("failed to retrieve KUDO manager %v", err) + } + expectedImage := s.Spec.Template.Spec.Containers[0].Image + actualImage := set.Spec.Template.Spec.Containers[0].Image + if actualImage != expectedImage { + return fmt.Errorf("deployed KUDO manager image %s differes from expected image %s", actualImage, expectedImage) + } + + clog.V(0).Printf("Installed StatefulSet: %v", set) + return nil +} + // Install uses Kubernetes client to install KUDO. func installManager(client kubernetes.Interface, opts Options) error { if err := installStatefulSet(client.AppsV1(), opts); err != nil { diff --git a/pkg/kudoctl/util/kudo/kudo.go b/pkg/kudoctl/util/kudo/kudo.go index fd50f1f42..33ca07f75 100644 --- a/pkg/kudoctl/util/kudo/kudo.go +++ b/pkg/kudoctl/util/kudo/kudo.go @@ -6,6 +6,10 @@ import ( "strings" "time" + "github.com/kudobuilder/kudo/pkg/kudoctl/kube" + + kudoinit "github.com/kudobuilder/kudo/pkg/kudoctl/cmd/init" + "github.com/kudobuilder/kudo/pkg/apis/kudo/v1beta1" "github.com/kudobuilder/kudo/pkg/client/clientset/versioned" "github.com/kudobuilder/kudo/pkg/kudoctl/clog" @@ -14,7 +18,6 @@ import ( "github.com/pkg/errors" v1core "k8s.io/api/core/v1" - extensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1beta1" apierrors "k8s.io/apimachinery/pkg/api/errors" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" @@ -42,31 +45,27 @@ func NewClient(kubeConfigPath string, requestTimeout int64) (*Client, error) { // set default configs config.Timeout = time.Duration(requestTimeout) * time.Second - // create the clientset - kudoClientset, err := versioned.NewForConfig(config) - if err != nil { - return nil, err - } - - // use the apiextensions clientset to check for the existence of KUDO CRDs in the cluster - extensionsClientset, err := extensionsclient.NewForConfig(config) + kubeClient, err := kube.GetKubeClient(kubeConfigPath) if err != nil { - return nil, err + return nil, clog.Errorf("could not get Kubernetes client: %s", err) } - _, err = extensionsClientset.CustomResourceDefinitions().Get("operators.kudo.dev", v1.GetOptions{}) + err = kudoinit.ValidateManager(kubeClient, kudoinit.NewOptions("", "")) if err != nil { - return nil, errors.WithMessage(err, "operators") + clog.V(0).Printf("KUDO manager not correctly installed. Do you need to run kudo init?") + return nil, fmt.Errorf("KUDO manager invalid: %v", err) } - _, err = extensionsClientset.CustomResourceDefinitions().Get("operatorversions.kudo.dev", v1.GetOptions{}) + err = kudoinit.CRDs().Validate(kubeClient) if err != nil { - return nil, errors.WithMessage(err, "operatorversions") + clog.V(0).Printf("Cluster CRDS are not set up correctly. Do you need to run kudo init?") + return nil, fmt.Errorf("CRDs invalid: %v", err) } - _, err = extensionsClientset.CustomResourceDefinitions().Get("instances.kudo.dev", v1.GetOptions{}) + //// create the clientset + kudoClientset, err := versioned.NewForConfig(config) if err != nil { - return nil, errors.WithMessage(err, "instances") + return nil, err } return &Client{ From f0e782f63f9c41196157968d6ae86877cac8324c Mon Sep 17 00:00:00 2001 From: Andreas Neumann Date: Wed, 27 Nov 2019 14:57:51 +0100 Subject: [PATCH 02/12] Cleanup and fixed bug in CRD validation --- pkg/kudoctl/cmd/init/crds.go | 2 +- pkg/kudoctl/cmd/init/manager.go | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/kudoctl/cmd/init/crds.go b/pkg/kudoctl/cmd/init/crds.go index 1950e5e48..ac75332f2 100644 --- a/pkg/kudoctl/cmd/init/crds.go +++ b/pkg/kudoctl/cmd/init/crds.go @@ -39,7 +39,7 @@ func validateCrd(client v1beta1.CustomResourceDefinitionsGetter, crd *apiextv1be if err != nil { return fmt.Errorf("failed to retrieve CRD %s", crd.Name) } - if existingCrd.ResourceVersion != crd.ResourceVersion { + if existingCrd.Spec.Version != crd.Spec.Version { return fmt.Errorf("installed CRD %s has invalid version %s, expected %s", crd.Name, existingCrd.Spec.Version, crd.Spec.Version) } return nil diff --git a/pkg/kudoctl/cmd/init/manager.go b/pkg/kudoctl/cmd/init/manager.go index 4e588aff8..8829e02b2 100644 --- a/pkg/kudoctl/cmd/init/manager.go +++ b/pkg/kudoctl/cmd/init/manager.go @@ -95,7 +95,6 @@ func ValidateManager(client *kube.Client, opts Options) error { return fmt.Errorf("deployed KUDO manager image %s differes from expected image %s", actualImage, expectedImage) } - clog.V(0).Printf("Installed StatefulSet: %v", set) return nil } From 9ef742a722ccecf671db6f206664ab70858750e3 Mon Sep 17 00:00:00 2001 From: Andreas Neumann Date: Thu, 28 Nov 2019 10:28:15 +0100 Subject: [PATCH 03/12] Added parameter to skip KUDO installation validation --- pkg/kudoctl/clog/log.go | 2 +- pkg/kudoctl/env/environment.go | 12 ++++++++---- pkg/kudoctl/util/kudo/kudo.go | 12 ++++++++---- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/pkg/kudoctl/clog/log.go b/pkg/kudoctl/clog/log.go index 0b740d51e..5f7212335 100644 --- a/pkg/kudoctl/clog/log.go +++ b/pkg/kudoctl/clog/log.go @@ -112,7 +112,7 @@ func (v Verbose) Printf(format string, args ...interface{}) { func InitWithFlags(f *pflag.FlagSet, out io.Writer) { // allows for initialization of writer in testing without CLI flags if f != nil { - f.VarP(&logging.verbosity, "v", "v", "log level for V logs") + f.VarP(&logging.verbosity, "v", "v", "Log level for V logs") } logging.out = out } diff --git a/pkg/kudoctl/env/environment.go b/pkg/kudoctl/env/environment.go index c5ac304cf..f57fbbbc3 100644 --- a/pkg/kudoctl/env/environment.go +++ b/pkg/kudoctl/env/environment.go @@ -41,20 +41,24 @@ type Settings struct { Namespace string // RequestTimeout is the timeout value (in seconds) when making API calls via the KUDO client RequestTimeout int64 + // Validate KUDO installation before creating a KUDO client + ValidateInstallation bool } // DefaultSettings initializes the settings to its defaults var DefaultSettings = &Settings{ - Namespace: "default", - RequestTimeout: 0, + Namespace: "default", + RequestTimeout: 0, + ValidateInstallation: true, } // AddFlags binds flags to the given flagset. func (s *Settings) AddFlags(fs *pflag.FlagSet) { - fs.StringVar((*string)(&s.Home), "home", kudoHome(), "location of your KUDO config.") + fs.StringVar((*string)(&s.Home), "home", kudoHome(), "Location of your KUDO config.") fs.StringVar(&s.KubeConfig, "kubeconfig", kubeConfigHome(), "Path to your Kubernetes configuration file.") fs.StringVarP(&s.Namespace, "namespace", "n", "default", "Target namespace for the object.") fs.Int64Var(&s.RequestTimeout, "request-timeout", 0, "Request timeout value, in seconds. Defaults to 0 (unlimited)") + fs.BoolVar(&s.ValidateInstallation, "validate-install", true, "Validate KUDO installation before running.") } // OverrideDefault used for deviations from global defaults @@ -68,5 +72,5 @@ func (s *Settings) OverrideDefault(fs *pflag.FlagSet, name, value string) string // GetClient is a helper function that takes the Settings struct and returns a new KUDO Client func GetClient(s *Settings) (*kudo.Client, error) { - return kudo.NewClient(s.KubeConfig, s.RequestTimeout) + return kudo.NewClient(s.KubeConfig, s.RequestTimeout, s.ValidateInstallation) } diff --git a/pkg/kudoctl/util/kudo/kudo.go b/pkg/kudoctl/util/kudo/kudo.go index 33ca07f75..209800981 100644 --- a/pkg/kudoctl/util/kudo/kudo.go +++ b/pkg/kudoctl/util/kudo/kudo.go @@ -34,7 +34,7 @@ type Client struct { } // NewClient creates new KUDO Client -func NewClient(kubeConfigPath string, requestTimeout int64) (*Client, error) { +func NewClient(kubeConfigPath string, requestTimeout int64, validateInstall bool) (*Client, error) { // use the current context in kubeconfig config, err := clientcmd.BuildConfigFromFlags("", kubeConfigPath) @@ -53,16 +53,20 @@ func NewClient(kubeConfigPath string, requestTimeout int64) (*Client, error) { err = kudoinit.ValidateManager(kubeClient, kudoinit.NewOptions("", "")) if err != nil { clog.V(0).Printf("KUDO manager not correctly installed. Do you need to run kudo init?") - return nil, fmt.Errorf("KUDO manager invalid: %v", err) + if validateInstall { + return nil, fmt.Errorf("KUDO manager invalid: %v", err) + } } err = kudoinit.CRDs().Validate(kubeClient) if err != nil { clog.V(0).Printf("Cluster CRDS are not set up correctly. Do you need to run kudo init?") - return nil, fmt.Errorf("CRDs invalid: %v", err) + if validateInstall { + return nil, fmt.Errorf("CRDs invalid: %v", err) + } } - //// create the clientset + // create the clientset kudoClientset, err := versioned.NewForConfig(config) if err != nil { return nil, err From a378544e62a2b265536e8c2bf9e68c591019c9f9 Mon Sep 17 00:00:00 2001 From: Andreas Neumann Date: Thu, 28 Nov 2019 10:39:19 +0100 Subject: [PATCH 04/12] Special timeout handling --- pkg/kudoctl/cmd/init/crds.go | 5 +++++ pkg/kudoctl/cmd/init/manager.go | 4 ++++ pkg/kudoctl/util/kudo/kudo.go | 9 +++++++++ 3 files changed, 18 insertions(+) diff --git a/pkg/kudoctl/cmd/init/crds.go b/pkg/kudoctl/cmd/init/crds.go index ac75332f2..e2d7dc5ed 100644 --- a/pkg/kudoctl/cmd/init/crds.go +++ b/pkg/kudoctl/cmd/init/crds.go @@ -2,6 +2,7 @@ package init import ( "fmt" + "os" "strings" "github.com/kudobuilder/kudo/pkg/kudoctl/kube" @@ -37,6 +38,9 @@ func installCrds(client apiextensionsclient.Interface) error { func validateCrd(client v1beta1.CustomResourceDefinitionsGetter, crd *apiextv1beta1.CustomResourceDefinition) error { existingCrd, err := client.CustomResourceDefinitions().Get(crd.Name, v1.GetOptions{}) if err != nil { + if os.IsTimeout(err) { + return err + } return fmt.Errorf("failed to retrieve CRD %s", crd.Name) } if existingCrd.Spec.Version != crd.Spec.Version { @@ -255,6 +259,7 @@ func (c KudoCrds) Validate(client *kube.Client) error { return err } if err := validateCrd(client.ExtClient.ApiextensionsV1beta1(), c.OperatorVersion); err != nil { + return err } if err := validateCrd(client.ExtClient.ApiextensionsV1beta1(), c.Instance); err != nil { diff --git a/pkg/kudoctl/cmd/init/manager.go b/pkg/kudoctl/cmd/init/manager.go index 8829e02b2..0f0758f08 100644 --- a/pkg/kudoctl/cmd/init/manager.go +++ b/pkg/kudoctl/cmd/init/manager.go @@ -2,6 +2,7 @@ package init import ( "fmt" + "os" "github.com/kudobuilder/kudo/pkg/kudoctl/clog" "github.com/kudobuilder/kudo/pkg/kudoctl/kube" @@ -87,6 +88,9 @@ func ValidateManager(client *kube.Client, opts Options) error { set, err := client.KubeClient.AppsV1().StatefulSets(opts.Namespace).Get(s.Name, metav1.GetOptions{}) if err != nil { + if os.IsTimeout(err) { + return err + } return fmt.Errorf("failed to retrieve KUDO manager %v", err) } expectedImage := s.Spec.Template.Spec.Containers[0].Image diff --git a/pkg/kudoctl/util/kudo/kudo.go b/pkg/kudoctl/util/kudo/kudo.go index 0f116236b..bfc31b963 100644 --- a/pkg/kudoctl/util/kudo/kudo.go +++ b/pkg/kudoctl/util/kudo/kudo.go @@ -52,6 +52,11 @@ func NewClient(kubeConfigPath string, requestTimeout int64, validateInstall bool err = kudoinit.ValidateManager(kubeClient, kudoinit.NewOptions("", "")) if err != nil { + // timeout is not a wrappable error, timeout is an underlying issue that is NOT validation specific, + // there is no value in wrapping or converting as well. best to provide the actual error for proper reporting. + if os.IsTimeout(err) { + return nil, err + } clog.V(0).Printf("KUDO manager not correctly installed. Do you need to run kudo init?") if validateInstall { return nil, fmt.Errorf("KUDO manager invalid: %v", err) @@ -60,6 +65,10 @@ func NewClient(kubeConfigPath string, requestTimeout int64, validateInstall bool err = kudoinit.CRDs().Validate(kubeClient) if err != nil { + // see above + if os.IsTimeout(err) { + return nil, err + } clog.V(0).Printf("Cluster CRDS are not set up correctly. Do you need to run kudo init?") if validateInstall { return nil, fmt.Errorf("CRDs invalid: %v", err) From 63b98da09c052f208abb49e156472d14955e7e1b Mon Sep 17 00:00:00 2001 From: Andreas Neumann Date: Thu, 28 Nov 2019 13:18:58 +0100 Subject: [PATCH 05/12] Fixed nits --- pkg/kudoctl/cmd/init/crds.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pkg/kudoctl/cmd/init/crds.go b/pkg/kudoctl/cmd/init/crds.go index e2d7dc5ed..df852ff65 100644 --- a/pkg/kudoctl/cmd/init/crds.go +++ b/pkg/kudoctl/cmd/init/crds.go @@ -5,9 +5,8 @@ import ( "os" "strings" - "github.com/kudobuilder/kudo/pkg/kudoctl/kube" - "github.com/kudobuilder/kudo/pkg/kudoctl/clog" + "github.com/kudobuilder/kudo/pkg/kudoctl/kube" apiextv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" @@ -41,7 +40,7 @@ func validateCrd(client v1beta1.CustomResourceDefinitionsGetter, crd *apiextv1be if os.IsTimeout(err) { return err } - return fmt.Errorf("failed to retrieve CRD %s", crd.Name) + return fmt.Errorf("failed to retrieve CRD %s: %v", crd.Name, err) } if existingCrd.Spec.Version != crd.Spec.Version { return fmt.Errorf("installed CRD %s has invalid version %s, expected %s", crd.Name, existingCrd.Spec.Version, crd.Spec.Version) @@ -259,7 +258,6 @@ func (c KudoCrds) Validate(client *kube.Client) error { return err } if err := validateCrd(client.ExtClient.ApiextensionsV1beta1(), c.OperatorVersion); err != nil { - return err } if err := validateCrd(client.ExtClient.ApiextensionsV1beta1(), c.Instance); err != nil { From 63d1999778a4cd932a20f4ef341d2a2d25392828 Mon Sep 17 00:00:00 2001 From: Andreas Neumann Date: Thu, 28 Nov 2019 13:21:12 +0100 Subject: [PATCH 06/12] Fixed nits --- pkg/kudoctl/cmd/init/crds.go | 10 +++++----- pkg/kudoctl/cmd/init/manager.go | 2 +- pkg/kudoctl/env/environment.go | 2 +- pkg/kudoctl/util/kudo/kudo.go | 8 +++----- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/pkg/kudoctl/cmd/init/crds.go b/pkg/kudoctl/cmd/init/crds.go index df852ff65..613ff40bd 100644 --- a/pkg/kudoctl/cmd/init/crds.go +++ b/pkg/kudoctl/cmd/init/crds.go @@ -34,7 +34,7 @@ func installCrds(client apiextensionsclient.Interface) error { return nil } -func validateCrd(client v1beta1.CustomResourceDefinitionsGetter, crd *apiextv1beta1.CustomResourceDefinition) error { +func validateInstallation(client v1beta1.CustomResourceDefinitionsGetter, crd *apiextv1beta1.CustomResourceDefinition) error { existingCrd, err := client.CustomResourceDefinitions().Get(crd.Name, v1.GetOptions{}) if err != nil { if os.IsTimeout(err) { @@ -253,14 +253,14 @@ func (c KudoCrds) AsYaml() ([]string, error) { return manifests, nil } -func (c KudoCrds) Validate(client *kube.Client) error { - if err := validateCrd(client.ExtClient.ApiextensionsV1beta1(), c.Operator); err != nil { +func (c KudoCrds) ValidateInstallation(client *kube.Client) error { + if err := validateInstallation(client.ExtClient.ApiextensionsV1beta1(), c.Operator); err != nil { return err } - if err := validateCrd(client.ExtClient.ApiextensionsV1beta1(), c.OperatorVersion); err != nil { + if err := validateInstallation(client.ExtClient.ApiextensionsV1beta1(), c.OperatorVersion); err != nil { return err } - if err := validateCrd(client.ExtClient.ApiextensionsV1beta1(), c.Instance); err != nil { + if err := validateInstallation(client.ExtClient.ApiextensionsV1beta1(), c.Instance); err != nil { return err } return nil diff --git a/pkg/kudoctl/cmd/init/manager.go b/pkg/kudoctl/cmd/init/manager.go index 0f0758f08..369431218 100644 --- a/pkg/kudoctl/cmd/init/manager.go +++ b/pkg/kudoctl/cmd/init/manager.go @@ -91,7 +91,7 @@ func ValidateManager(client *kube.Client, opts Options) error { if os.IsTimeout(err) { return err } - return fmt.Errorf("failed to retrieve KUDO manager %v", err) + return fmt.Errorf("failed to retrieve KUDO manager: %v", err) } expectedImage := s.Spec.Template.Spec.Containers[0].Image actualImage := set.Spec.Template.Spec.Containers[0].Image diff --git a/pkg/kudoctl/env/environment.go b/pkg/kudoctl/env/environment.go index f57fbbbc3..49989338f 100644 --- a/pkg/kudoctl/env/environment.go +++ b/pkg/kudoctl/env/environment.go @@ -58,7 +58,7 @@ func (s *Settings) AddFlags(fs *pflag.FlagSet) { fs.StringVar(&s.KubeConfig, "kubeconfig", kubeConfigHome(), "Path to your Kubernetes configuration file.") fs.StringVarP(&s.Namespace, "namespace", "n", "default", "Target namespace for the object.") fs.Int64Var(&s.RequestTimeout, "request-timeout", 0, "Request timeout value, in seconds. Defaults to 0 (unlimited)") - fs.BoolVar(&s.ValidateInstallation, "validate-install", true, "Validate KUDO installation before running.") + fs.BoolVar(&s.ValidateInstallation, "validate-install", true, "ValidateInstallation KUDO installation before running.") } // OverrideDefault used for deviations from global defaults diff --git a/pkg/kudoctl/util/kudo/kudo.go b/pkg/kudoctl/util/kudo/kudo.go index bfc31b963..682bffecb 100644 --- a/pkg/kudoctl/util/kudo/kudo.go +++ b/pkg/kudoctl/util/kudo/kudo.go @@ -7,13 +7,11 @@ import ( "strings" "time" - "github.com/kudobuilder/kudo/pkg/kudoctl/kube" - - kudoinit "github.com/kudobuilder/kudo/pkg/kudoctl/cmd/init" - "github.com/kudobuilder/kudo/pkg/apis/kudo/v1beta1" "github.com/kudobuilder/kudo/pkg/client/clientset/versioned" "github.com/kudobuilder/kudo/pkg/kudoctl/clog" + kudoinit "github.com/kudobuilder/kudo/pkg/kudoctl/cmd/init" + "github.com/kudobuilder/kudo/pkg/kudoctl/kube" "github.com/kudobuilder/kudo/pkg/util/kudo" "github.com/kudobuilder/kudo/pkg/version" @@ -63,7 +61,7 @@ func NewClient(kubeConfigPath string, requestTimeout int64, validateInstall bool } } - err = kudoinit.CRDs().Validate(kubeClient) + err = kudoinit.CRDs().ValidateInstallation(kubeClient) if err != nil { // see above if os.IsTimeout(err) { From 07214f9bda6a235069259fa2dde1fa7b68eafd1b Mon Sep 17 00:00:00 2001 From: Andreas Neumann Date: Thu, 28 Nov 2019 14:19:53 +0100 Subject: [PATCH 07/12] Fixed test --- pkg/kudoctl/util/kudo/kudo_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/kudoctl/util/kudo/kudo_test.go b/pkg/kudoctl/util/kudo/kudo_test.go index 8299b3158..284e097b3 100644 --- a/pkg/kudoctl/util/kudo/kudo_test.go +++ b/pkg/kudoctl/util/kudo/kudo_test.go @@ -28,7 +28,7 @@ func TestNewK2oClient(t *testing.T) { for _, tt := range tests { // Just interested in errors - _, err := NewClient("", 0) + _, err := NewClient("", 0, false) assert.ErrorContains(t, err, tt.err) } } From f0079e10fc5821b4aa8c97dc8d8e9c7e8f0da272 Mon Sep 17 00:00:00 2001 From: Andreas Neumann Date: Thu, 28 Nov 2019 14:45:15 +0100 Subject: [PATCH 08/12] Fixed typo Start KUDO controller for IT --- pkg/kudoctl/cmd/init/manager.go | 2 +- pkg/test/harness_integration_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/kudoctl/cmd/init/manager.go b/pkg/kudoctl/cmd/init/manager.go index 369431218..0e0c43502 100644 --- a/pkg/kudoctl/cmd/init/manager.go +++ b/pkg/kudoctl/cmd/init/manager.go @@ -96,7 +96,7 @@ func ValidateManager(client *kube.Client, opts Options) error { expectedImage := s.Spec.Template.Spec.Containers[0].Image actualImage := set.Spec.Template.Spec.Containers[0].Image if actualImage != expectedImage { - return fmt.Errorf("deployed KUDO manager image %s differes from expected image %s", actualImage, expectedImage) + return fmt.Errorf("deployed KUDO manager image %s differs from expected image %s", actualImage, expectedImage) } return nil diff --git a/pkg/test/harness_integration_test.go b/pkg/test/harness_integration_test.go index 366e4bd2c..051fe8482 100644 --- a/pkg/test/harness_integration_test.go +++ b/pkg/test/harness_integration_test.go @@ -15,7 +15,7 @@ func TestHarnessRunIntegration(t *testing.T) { TestDirs: []string{ "./test_data/", }, - StartKUDO: false, + StartKUDO: true, StartControlPlane: true, }, T: t, From dc16b78bfccaa0d87e639bca5efea6d3d332b652 Mon Sep 17 00:00:00 2001 From: Andreas Neumann Date: Thu, 28 Nov 2019 15:29:17 +0100 Subject: [PATCH 09/12] Don't validate the manager on command execution --- pkg/kudoctl/util/kudo/kudo.go | 13 ------------- pkg/test/harness_integration_test.go | 2 +- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/pkg/kudoctl/util/kudo/kudo.go b/pkg/kudoctl/util/kudo/kudo.go index 682bffecb..fc3b0c525 100644 --- a/pkg/kudoctl/util/kudo/kudo.go +++ b/pkg/kudoctl/util/kudo/kudo.go @@ -48,19 +48,6 @@ func NewClient(kubeConfigPath string, requestTimeout int64, validateInstall bool return nil, clog.Errorf("could not get Kubernetes client: %s", err) } - err = kudoinit.ValidateManager(kubeClient, kudoinit.NewOptions("", "")) - if err != nil { - // timeout is not a wrappable error, timeout is an underlying issue that is NOT validation specific, - // there is no value in wrapping or converting as well. best to provide the actual error for proper reporting. - if os.IsTimeout(err) { - return nil, err - } - clog.V(0).Printf("KUDO manager not correctly installed. Do you need to run kudo init?") - if validateInstall { - return nil, fmt.Errorf("KUDO manager invalid: %v", err) - } - } - err = kudoinit.CRDs().ValidateInstallation(kubeClient) if err != nil { // see above diff --git a/pkg/test/harness_integration_test.go b/pkg/test/harness_integration_test.go index 051fe8482..366e4bd2c 100644 --- a/pkg/test/harness_integration_test.go +++ b/pkg/test/harness_integration_test.go @@ -15,7 +15,7 @@ func TestHarnessRunIntegration(t *testing.T) { TestDirs: []string{ "./test_data/", }, - StartKUDO: true, + StartKUDO: false, StartControlPlane: true, }, T: t, From 9b31410161530cff549b7211e1e574543b04c620 Mon Sep 17 00:00:00 2001 From: Andreas Neumann Date: Fri, 29 Nov 2019 10:35:25 +0100 Subject: [PATCH 10/12] Cleanup and integration of review requests --- pkg/kudoctl/cmd/init/manager.go | 20 -------------------- pkg/kudoctl/env/environment.go | 12 ++++++------ pkg/kudoctl/util/kudo/kudo.go | 2 +- 3 files changed, 7 insertions(+), 27 deletions(-) diff --git a/pkg/kudoctl/cmd/init/manager.go b/pkg/kudoctl/cmd/init/manager.go index 0e0c43502..1312ab1a4 100644 --- a/pkg/kudoctl/cmd/init/manager.go +++ b/pkg/kudoctl/cmd/init/manager.go @@ -2,7 +2,6 @@ package init import ( "fmt" - "os" "github.com/kudobuilder/kudo/pkg/kudoctl/clog" "github.com/kudobuilder/kudo/pkg/kudoctl/kube" @@ -83,25 +82,6 @@ func Install(client *kube.Client, opts Options, crdOnly bool) error { return nil } -func ValidateManager(client *kube.Client, opts Options) error { - s := generateDeployment(opts) - set, err := client.KubeClient.AppsV1().StatefulSets(opts.Namespace).Get(s.Name, metav1.GetOptions{}) - - if err != nil { - if os.IsTimeout(err) { - return err - } - return fmt.Errorf("failed to retrieve KUDO manager: %v", err) - } - expectedImage := s.Spec.Template.Spec.Containers[0].Image - actualImage := set.Spec.Template.Spec.Containers[0].Image - if actualImage != expectedImage { - return fmt.Errorf("deployed KUDO manager image %s differs from expected image %s", actualImage, expectedImage) - } - - return nil -} - // Install uses Kubernetes client to install KUDO. func installManager(client kubernetes.Interface, opts Options) error { if err := installStatefulSet(client.AppsV1(), opts); err != nil { diff --git a/pkg/kudoctl/env/environment.go b/pkg/kudoctl/env/environment.go index 49989338f..8ba03d6ca 100644 --- a/pkg/kudoctl/env/environment.go +++ b/pkg/kudoctl/env/environment.go @@ -42,14 +42,14 @@ type Settings struct { // RequestTimeout is the timeout value (in seconds) when making API calls via the KUDO client RequestTimeout int64 // Validate KUDO installation before creating a KUDO client - ValidateInstallation bool + Validate bool } // DefaultSettings initializes the settings to its defaults var DefaultSettings = &Settings{ - Namespace: "default", - RequestTimeout: 0, - ValidateInstallation: true, + Namespace: "default", + RequestTimeout: 0, + Validate: true, } // AddFlags binds flags to the given flagset. @@ -58,7 +58,7 @@ func (s *Settings) AddFlags(fs *pflag.FlagSet) { fs.StringVar(&s.KubeConfig, "kubeconfig", kubeConfigHome(), "Path to your Kubernetes configuration file.") fs.StringVarP(&s.Namespace, "namespace", "n", "default", "Target namespace for the object.") fs.Int64Var(&s.RequestTimeout, "request-timeout", 0, "Request timeout value, in seconds. Defaults to 0 (unlimited)") - fs.BoolVar(&s.ValidateInstallation, "validate-install", true, "ValidateInstallation KUDO installation before running.") + fs.BoolVar(&s.Validate, "validate-install", true, "Validate KUDO installation before running.") } // OverrideDefault used for deviations from global defaults @@ -72,5 +72,5 @@ func (s *Settings) OverrideDefault(fs *pflag.FlagSet, name, value string) string // GetClient is a helper function that takes the Settings struct and returns a new KUDO Client func GetClient(s *Settings) (*kudo.Client, error) { - return kudo.NewClient(s.KubeConfig, s.RequestTimeout, s.ValidateInstallation) + return kudo.NewClient(s.KubeConfig, s.RequestTimeout, s.Validate) } diff --git a/pkg/kudoctl/util/kudo/kudo.go b/pkg/kudoctl/util/kudo/kudo.go index fc3b0c525..16a1d2744 100644 --- a/pkg/kudoctl/util/kudo/kudo.go +++ b/pkg/kudoctl/util/kudo/kudo.go @@ -54,7 +54,7 @@ func NewClient(kubeConfigPath string, requestTimeout int64, validateInstall bool if os.IsTimeout(err) { return nil, err } - clog.V(0).Printf("Cluster CRDS are not set up correctly. Do you need to run kudo init?") + clog.V(0).Printf("KUDO CRDs are not set up correctly. Do you need to run kudo init?") if validateInstall { return nil, fmt.Errorf("CRDs invalid: %v", err) } From 6f1836fe458fb60ffaa972990680ff7ff58119e3 Mon Sep 17 00:00:00 2001 From: Andreas Neumann Date: Fri, 29 Nov 2019 15:10:15 +0100 Subject: [PATCH 11/12] Add unit test that checks validate parameter of kudo.NewClient --- pkg/kudoctl/util/kudo/kudo_test.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/pkg/kudoctl/util/kudo/kudo_test.go b/pkg/kudoctl/util/kudo/kudo_test.go index 284e097b3..f01ce3fb8 100644 --- a/pkg/kudoctl/util/kudo/kudo_test.go +++ b/pkg/kudoctl/util/kudo/kudo_test.go @@ -19,6 +19,19 @@ func newTestSimpleK2o() *Client { return NewClientFromK8s(fake.NewSimpleClientset()) } +func TestKudoClientValidate(t *testing.T) { + tests := []struct { + err string + }{ + {"CRDs invalid: failed to retrieve CRD"}, // verify that NewClient tries to validate CRDs + } + + for _, tt := range tests { + _, err := NewClient("testdata/kubeconfig", 0, true) + assert.ErrorContains(t, err, tt.err) + } +} + func TestNewK2oClient(t *testing.T) { tests := []struct { err string From aa0edf757756480abb7976373ff1ff32060b3271 Mon Sep 17 00:00:00 2001 From: Andreas Neumann Date: Fri, 29 Nov 2019 15:12:58 +0100 Subject: [PATCH 12/12] Fixed test --- pkg/kudoctl/util/kudo/kudo_test.go | 2 +- pkg/kudoctl/util/kudo/testdata/test-config | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 pkg/kudoctl/util/kudo/testdata/test-config diff --git a/pkg/kudoctl/util/kudo/kudo_test.go b/pkg/kudoctl/util/kudo/kudo_test.go index f01ce3fb8..9c447b62f 100644 --- a/pkg/kudoctl/util/kudo/kudo_test.go +++ b/pkg/kudoctl/util/kudo/kudo_test.go @@ -27,7 +27,7 @@ func TestKudoClientValidate(t *testing.T) { } for _, tt := range tests { - _, err := NewClient("testdata/kubeconfig", 0, true) + _, err := NewClient("testdata/test-config", 0, true) assert.ErrorContains(t, err, tt.err) } } diff --git a/pkg/kudoctl/util/kudo/testdata/test-config b/pkg/kudoctl/util/kudo/testdata/test-config new file mode 100644 index 000000000..f0664c6d7 --- /dev/null +++ b/pkg/kudoctl/util/kudo/testdata/test-config @@ -0,0 +1,14 @@ +clusters: +- cluster: + server: 127.0.0.1:1 + name: cluster +contexts: +- context: + cluster: cluster + user: user + name: cluster +current-context: cluster +preferences: {} +users: +- name: user + user: {}