diff --git a/pkg/engine/health/health.go b/pkg/engine/health/health.go index 936e7595d..6a324e862 100644 --- a/pkg/engine/health/health.go +++ b/pkg/engine/health/health.go @@ -121,6 +121,12 @@ func IsHealthy(obj runtime.Object) error { } return fmt.Errorf("pod %q is not running yet: %s", obj.Name, obj.Status.Phase) + case *corev1.Namespace: + if obj.Status.Phase == corev1.NamespaceActive { + return nil + } + return fmt.Errorf("namespace %s is not active: %s", obj.Name, obj.Status.Phase) + // unless we build logic for what a healthy object is, assume it's healthy when created. default: log.Printf("HealthUtil: Unknown type %s is marked healthy by default", reflect.TypeOf(obj)) diff --git a/pkg/kudoctl/cmd/init.go b/pkg/kudoctl/cmd/init.go index 27b1edaf6..850e563b9 100644 --- a/pkg/kudoctl/cmd/init.go +++ b/pkg/kudoctl/cmd/init.go @@ -218,7 +218,7 @@ func (initCmd *initCmd) run() error { if initCmd.wait { clog.Printf("⌛Waiting for KUDO controller to be ready in your cluster...") - err := setup.WatchKUDOUntilReady(initCmd.client.KubeClient, opts, initCmd.timeout) + err := setup.WatchKUDOUntilReady(installer, initCmd.client, initCmd.timeout) if err != nil { return errors.New("watch timed out, readiness uncertain") } @@ -287,13 +287,12 @@ func (initCmd *initCmd) runYamlOutput(installer kudoinit.Artifacter) error { // verifyExistingInstallation checks if the current installation is valid and as expected func (initCmd *initCmd) verifyExistingInstallation(v kudoinit.InstallVerifier) error { clog.V(4).Printf("verify existing installation") - result := verifier.NewResult() - if err := v.VerifyInstallation(initCmd.client, &result); err != nil { + ok, err := setup.VerifyExistingInstallation(v, initCmd.client, initCmd.out) + if err != nil { return err } - result.PrintWarnings(initCmd.out) - if !result.IsValid() { - result.PrintErrors(initCmd.out) + if !ok { + return fmt.Errorf("KUDO installation is not valid") } return nil } diff --git a/pkg/kudoctl/kudoinit/crd/crds.go b/pkg/kudoctl/kudoinit/crd/crds.go index 067a53438..b87ec80c1 100644 --- a/pkg/kudoctl/kudoinit/crd/crds.go +++ b/pkg/kudoctl/kudoinit/crd/crds.go @@ -13,6 +13,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/yaml" + "github.com/kudobuilder/kudo/pkg/engine/health" "github.com/kudobuilder/kudo/pkg/kudoctl/clog" "github.com/kudobuilder/kudo/pkg/kudoctl/kube" "github.com/kudobuilder/kudo/pkg/kudoctl/kudoinit" @@ -121,6 +122,10 @@ func (c Initializer) verifyInstallation(client v1beta1.CustomResourceDefinitions result.AddErrors(fmt.Sprintf("Installed CRD %s has invalid version %s, expected %s", crd.Name, existingCrd.Spec.Version, crd.Spec.Version)) return nil } + if err := health.IsHealthy(existingCrd); err != nil { + result.AddErrors(fmt.Sprintf("Installed CRD %s is not healthy: %v", crd.Name, err)) + return nil + } clog.V(2).Printf("CRD %s is installed with version %s", crd.Name, existingCrd.Spec.Versions[0].Name) return nil } diff --git a/pkg/kudoctl/kudoinit/prereq/namespace.go b/pkg/kudoctl/kudoinit/prereq/namespace.go index 959cf3974..ab6cd9314 100644 --- a/pkg/kudoctl/kudoinit/prereq/namespace.go +++ b/pkg/kudoctl/kudoinit/prereq/namespace.go @@ -9,6 +9,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "github.com/kudobuilder/kudo/pkg/engine/health" "github.com/kudobuilder/kudo/pkg/kudoctl/clog" "github.com/kudobuilder/kudo/pkg/kudoctl/kube" "github.com/kudobuilder/kudo/pkg/kudoctl/kudoinit" @@ -64,7 +65,7 @@ func (o KudoNamespace) PreUpgradeVerify(client *kube.Client, result *verifier.Re } func (o KudoNamespace) VerifyInstallation(client *kube.Client, result *verifier.Result) error { - _, err := client.KubeClient.CoreV1().Namespaces().Get(context.TODO(), o.opts.Namespace, metav1.GetOptions{}) + ns, err := client.KubeClient.CoreV1().Namespaces().Get(context.TODO(), o.opts.Namespace, metav1.GetOptions{}) if err != nil { if kerrors.IsNotFound(err) { result.AddErrors(fmt.Sprintf("namespace %s does not exist", o.opts.Namespace)) @@ -72,6 +73,9 @@ func (o KudoNamespace) VerifyInstallation(client *kube.Client, result *verifier. } return err } + if err := health.IsHealthy(ns); err != nil { + result.AddErrors(fmt.Sprintf("namespace %s is not healthy: %v", o.opts.Namespace, err)) + } return nil } diff --git a/pkg/kudoctl/kudoinit/setup/setup.go b/pkg/kudoctl/kudoinit/setup/setup.go index 5e99c0295..b1073841b 100644 --- a/pkg/kudoctl/kudoinit/setup/setup.go +++ b/pkg/kudoctl/kudoinit/setup/setup.go @@ -2,6 +2,7 @@ package setup import ( "fmt" + "io" "k8s.io/apimachinery/pkg/runtime" @@ -167,3 +168,22 @@ func (i *Installer) Resources() []runtime.Object { return allManifests } + +// verifyExistingInstallation checks if the current installation is valid and as expected +func VerifyExistingInstallation(v kudoinit.InstallVerifier, client *kube.Client, out io.Writer) (bool, error) { + clog.V(4).Printf("verify existing installation") + result := verifier.NewResult() + if err := v.VerifyInstallation(client, &result); err != nil { + return false, err + } + if out != nil { + result.PrintWarnings(out) + } + if !result.IsValid() { + if out != nil { + result.PrintErrors(out) + } + return false, nil + } + return true, nil +} diff --git a/pkg/kudoctl/kudoinit/setup/wait.go b/pkg/kudoctl/kudoinit/setup/wait.go index 1eb9c163d..4d4c110d8 100644 --- a/pkg/kudoctl/kudoinit/setup/wait.go +++ b/pkg/kudoctl/kudoinit/setup/wait.go @@ -1,36 +1,22 @@ package setup import ( - "context" "time" - "github.com/kudobuilder/kudo/pkg/engine/health" + "github.com/kudobuilder/kudo/pkg/kudoctl/kube" "k8s.io/apimachinery/pkg/util/wait" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - appsv1 "k8s.io/client-go/kubernetes/typed/apps/v1" - "github.com/kudobuilder/kudo/pkg/kudoctl/kudoinit" ) -// WatchKUDOUntilReady waits for the KUDO pod to become available. +// WatchKUDOUntilReady waits for the KUDO installation to become available. // // Returns no error if it exists. If the timeout was reached and it could not find the pod, it returns error. -func WatchKUDOUntilReady(client kubernetes.Interface, opts kudoinit.Options, timeout int64) error { +func WatchKUDOUntilReady(v kudoinit.InstallVerifier, client *kube.Client, timeout int64) error { return wait.PollImmediate(500*time.Millisecond, time.Duration(timeout)*time.Second, - func() (bool, error) { return verifyKudoStatefulset(client.AppsV1(), opts.Namespace) }) -} - -func verifyKudoStatefulset(client appsv1.StatefulSetsGetter, namespace string) (bool, error) { - ss, err := client.StatefulSets(namespace).Get(context.TODO(), kudoinit.DefaultManagerName, metav1.GetOptions{}) - if err != nil || ss == nil { - return false, err - } - err = health.IsHealthy(ss) - if err != nil { - return false, nil - } - return true, nil + func() (bool, error) { + return VerifyExistingInstallation(v, client, nil) + }, + ) }