diff --git a/cmd/kops/rollingupdatecluster.go b/cmd/kops/rollingupdatecluster.go index a7b39a1eac..218412d365 100644 --- a/cmd/kops/rollingupdatecluster.go +++ b/cmd/kops/rollingupdatecluster.go @@ -393,7 +393,7 @@ func RunRollingUpdateCluster(f *util.Factory, out io.Writer, options *RollingUpd if featureflag.DrainAndValidateRollingUpdate.Enabled() { klog.V(2).Infof("Rolling update with drain and validate enabled.") if !options.CloudOnly { - clusterValidator, err = validation.NewClusterValidator(cluster, list, k8sClient) + clusterValidator, err = validation.NewClusterValidator(cluster, cloud, list, k8sClient) if err != nil { return fmt.Errorf("cannot create cluster validator: %v", err) } diff --git a/cmd/kops/validate_cluster.go b/cmd/kops/validate_cluster.go index ca679b0286..b65c1c75f6 100644 --- a/cmd/kops/validate_cluster.go +++ b/cmd/kops/validate_cluster.go @@ -25,6 +25,8 @@ import ( "strings" "time" + "k8s.io/kops/upup/pkg/fi/cloudup" + "github.com/ghodss/yaml" "github.com/spf13/cobra" v1 "k8s.io/api/core/v1" @@ -93,6 +95,11 @@ func RunValidateCluster(f *util.Factory, cmd *cobra.Command, args []string, out return nil, err } + cloud, err := cloudup.BuildCloud(cluster) + if err != nil { + return nil, err + } + clientSet, err := f.Clientset() if err != nil { return nil, err @@ -134,7 +141,7 @@ func RunValidateCluster(f *util.Factory, cmd *cobra.Command, args []string, out timeout := time.Now().Add(options.wait) pollInterval := 10 * time.Second - validator, err := validation.NewClusterValidator(cluster, list, k8sClient) + validator, err := validation.NewClusterValidator(cluster, cloud, list, k8sClient) if err != nil { return nil, fmt.Errorf("unexpected error creating validatior: %v", err) } diff --git a/pkg/validation/BUILD.bazel b/pkg/validation/BUILD.bazel index 75df4b49e4..e4684d743a 100644 --- a/pkg/validation/BUILD.bazel +++ b/pkg/validation/BUILD.bazel @@ -13,7 +13,7 @@ go_library( "//pkg/apis/kops/util:go_default_library", "//pkg/cloudinstances:go_default_library", "//pkg/dns:go_default_library", - "//upup/pkg/fi/cloudup:go_default_library", + "//upup/pkg/fi:go_default_library", "//vendor/k8s.io/api/core/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/client-go/kubernetes:go_default_library", diff --git a/pkg/validation/validate_cluster.go b/pkg/validation/validate_cluster.go index a6c195ce57..1c2b7b7954 100644 --- a/pkg/validation/validate_cluster.go +++ b/pkg/validation/validate_cluster.go @@ -22,6 +22,8 @@ import ( "net/url" "strings" + "k8s.io/kops/upup/pkg/fi" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" @@ -31,7 +33,6 @@ import ( "k8s.io/kops/pkg/apis/kops/util" "k8s.io/kops/pkg/cloudinstances" "k8s.io/kops/pkg/dns" - "k8s.io/kops/upup/pkg/fi/cloudup" ) // ValidationCluster uses a cluster to validate. @@ -54,9 +55,10 @@ type ClusterValidator interface { } type clusterValidatorImpl struct { - cluster *kops.Cluster - instanceGroupList *kops.InstanceGroupList - k8sClient kubernetes.Interface + cluster *kops.Cluster + cloud fi.Cloud + instanceGroups []*kops.InstanceGroup + k8sClient kubernetes.Interface } func (v *ValidationCluster) addError(failure *ValidationError) { @@ -100,23 +102,30 @@ func hasPlaceHolderIP(clusterName string) (bool, error) { return false, nil } -func NewClusterValidator(cluster *kops.Cluster, instanceGroupList *kops.InstanceGroupList, k8sClient kubernetes.Interface) (ClusterValidator, error) { +func NewClusterValidator(cluster *kops.Cluster, cloud fi.Cloud, instanceGroupList *kops.InstanceGroupList, k8sClient kubernetes.Interface) (ClusterValidator, error) { + var instanceGroups []*kops.InstanceGroup + + for i := range instanceGroupList.Items { + ig := &instanceGroupList.Items[i] + instanceGroups = append(instanceGroups, ig) + } + + if len(instanceGroups) == 0 { + return nil, fmt.Errorf("no InstanceGroup objects found") + } + return &clusterValidatorImpl{ - cluster: cluster, - instanceGroupList: instanceGroupList, - k8sClient: k8sClient, + cluster: cluster, + cloud: cloud, + instanceGroups: instanceGroups, + k8sClient: k8sClient, }, nil } func (v *clusterValidatorImpl) Validate() (*ValidationCluster, error) { - return validateCluster(v.cluster, v.instanceGroupList, v.k8sClient) -} + clusterName := v.cluster.Name -// validateCluster validates a k8s cluster with a provided instance group list -func validateCluster(cluster *kops.Cluster, instanceGroupList *kops.InstanceGroupList, k8sClient kubernetes.Interface) (*ValidationCluster, error) { - clusterName := cluster.Name - - v := &ValidationCluster{} + validation := &ValidationCluster{} // Do not use if we are running gossip if !dns.IsGossipHostname(clusterName) { @@ -134,52 +143,36 @@ func validateCluster(cluster *kops.Cluster, instanceGroupList *kops.InstanceGrou " Please wait about 5-10 minutes for a master to start, dns-controller to launch, and DNS to propagate." + " The protokube container and dns-controller deployment logs may contain more diagnostic information." + " Etcd and the API DNS entries must be updated for a kops Kubernetes cluster to start." - v.addError(&ValidationError{ + validation.addError(&ValidationError{ Kind: "dns", Name: "apiserver", Message: message, }) - return v, nil + return validation, nil } } - var instanceGroups []*kops.InstanceGroup - - for i := range instanceGroupList.Items { - ig := &instanceGroupList.Items[i] - instanceGroups = append(instanceGroups, ig) - } - - if len(instanceGroups) == 0 { - return nil, fmt.Errorf("no InstanceGroup objects found") - } - - cloud, err := cloudup.BuildCloud(cluster) - if err != nil { - return nil, err - } - - nodeList, err := k8sClient.CoreV1().Nodes().List(metav1.ListOptions{}) + nodeList, err := v.k8sClient.CoreV1().Nodes().List(metav1.ListOptions{}) if err != nil { return nil, fmt.Errorf("error listing nodes: %v", err) } warnUnmatched := false - cloudGroups, err := cloud.GetCloudGroups(cluster, instanceGroups, warnUnmatched, nodeList.Items) + cloudGroups, err := v.cloud.GetCloudGroups(v.cluster, v.instanceGroups, warnUnmatched, nodeList.Items) if err != nil { return nil, err } - v.validateNodes(cloudGroups) + validation.validateNodes(cloudGroups) - if err := v.collectComponentFailures(k8sClient); err != nil { + if err := validation.collectComponentFailures(v.k8sClient); err != nil { return nil, fmt.Errorf("cannot get component status for %q: %v", clusterName, err) } - if err = v.collectPodFailures(k8sClient); err != nil { + if err = validation.collectPodFailures(v.k8sClient); err != nil { return nil, fmt.Errorf("cannot get pod health for %q: %v", clusterName, err) } - return v, nil + return validation, nil } func (v *ValidationCluster) collectComponentFailures(client kubernetes.Interface) error {