Skip to content

Commit

Permalink
Validate cluster and machine objects
Browse files Browse the repository at this point in the history
  • Loading branch information
wangzhen127 committed Jun 20, 2018
1 parent cbc610d commit eb250f5
Show file tree
Hide file tree
Showing 5 changed files with 434 additions and 35 deletions.
49 changes: 45 additions & 4 deletions clusterctl/cmd/validate_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,67 @@ limitations under the License.
package cmd

import (
"github.com/golang/glog"
"fmt"
"os"

"github.com/spf13/cobra"
"sigs.k8s.io/cluster-api/pkg/errors"
"k8s.io/api/core/v1"
"sigs.k8s.io/cluster-api/clusterctl/validation"
"sigs.k8s.io/cluster-api/pkg/clientcmd"
"sigs.k8s.io/cluster-api/pkg/util"
)

type ValidateClusterOptions struct {
ClusterName string
Namespace string
Kubeconfig string
}

var vco = &ValidateClusterOptions{}

var validateClusterCmd = &cobra.Command{
Use: "cluster",
Short: "Validate a cluster created by cluster API.",
Long: `Validate a cluster created by cluster API.`,
Run: func(cmd *cobra.Command, args []string) {
if err := RunValidateCluster(); err != nil {
glog.Exit(err)
os.Stdout.Sync()
fmt.Fprintf(os.Stderr, "ERROR: %v\n", err)
os.Exit(1)
}
},
}

func init() {
validateClusterCmd.Flags().StringVarP(
&vco.ClusterName, "cluster-name", "", "",
"The name of the cluster to be validated. This can be omitted if there is only one cluster being managed in the given namespace.")
validateClusterCmd.Flags().StringVarP(
&vco.Namespace, "namespace", "n", v1.NamespaceDefault,
"If present, validate the cluster in the specified namespace.")
validateClusterCmd.Flags().StringVarP(
&vco.Kubeconfig, "kubeconfig", "", "",
"The file path of the kubeconfig file for Cluster API management stack. If not specified, $KUBECONFIG environment variable or ${HOME}/.kube/config is used.")
validateCmd.AddCommand(validateClusterCmd)
}

func RunValidateCluster() error {
return errors.NotImplementedError
kubeconfig := vco.Kubeconfig
if kubeconfig == "" {
kubeconfig = os.Getenv("KUBECONFIG")
if kubeconfig == "" {
kubeconfig = util.GetDefaultKubeConfigPath()
}
}
client, err := clientcmd.NewClusterApiClientForDefaultSearchPath(kubeconfig)
if err != nil {
return fmt.Errorf("Failed to create client for talking to the apiserver: %v", err)
}

if err = validation.ValidateClusterAPIObjects(client, vco.ClusterName, vco.Namespace); err != nil {
return err
}

// TODO(wangzhen127): Also validate the cluster in addition to the cluster API objects.
return nil
}
30 changes: 0 additions & 30 deletions clusterctl/cmd/validate_cluster_test.go

This file was deleted.

112 changes: 112 additions & 0 deletions clusterctl/validation/validate_cluster_api_objects.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*
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 validation

import (
"fmt"

meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/cluster-api/pkg/apis/cluster/common"
"sigs.k8s.io/cluster-api/pkg/apis/cluster/v1alpha1"
"sigs.k8s.io/cluster-api/pkg/client/clientset_generated/clientset"
)

func ValidateClusterAPIObjects(client *clientset.Clientset, clusterName string, namespace string) error {
fmt.Printf("Validating cluster API objects in namespace %q.\n", namespace)

cluster, err := getClusterObject(client, clusterName, namespace)
if err != nil {
return err
}
if err := validateClusterObject(cluster); err != nil {
return err
}

machines, err := client.ClusterV1alpha1().Machines(namespace).List(meta_v1.ListOptions{})
if err != nil {
return fmt.Errorf("Failed to get the machines from the apiserver in namespace %q: %v", namespace, err)
}
if err = validateMachineObjects(machines); err != nil {
return err
}

return nil
}

func getClusterObject(client *clientset.Clientset, clusterName string, namespace string) (*v1alpha1.Cluster, error) {
if clusterName != "" {
cluster, err := client.ClusterV1alpha1().Clusters(namespace).Get(clusterName, meta_v1.GetOptions{})
if err != nil {
return nil, fmt.Errorf("Failed to get the cluster %q from the apiserver in namespace %q: %v", clusterName, namespace, err)
}
return cluster, nil
}

clusters, err := client.ClusterV1alpha1().Clusters(namespace).List(meta_v1.ListOptions{})
if err != nil {
return nil, fmt.Errorf("Failed to get the clusters from the apiserver in namespace %q: %v", namespace, err)
}
if numOfClusters := len(clusters.Items); numOfClusters == 0 {
return nil, fmt.Errorf("Fail: No cluster exists in namespace %q.", namespace)
} else if numOfClusters > 1 {
return nil, fmt.Errorf("Fail: There are more than one cluster in namespace %q. Please specify --cluster-name.", namespace)
}
return &clusters.Items[0], nil
}

func validateClusterObject(cluster *v1alpha1.Cluster) error {
fmt.Printf("Checking cluster object %q... ", cluster.Name)
if cluster.Status.ErrorReason != "" || cluster.Status.ErrorMessage != "" {
fmt.Printf("FAIL\n")
fmt.Printf("\t[%v]: %s\n", cluster.Status.ErrorReason, cluster.Status.ErrorMessage)
return fmt.Errorf("Failed to validate the cluster %q.", cluster.Name)
}
fmt.Printf("PASS\n")
return nil
}

func validateMachineObjects(machines *v1alpha1.MachineList) error {
pass := true
for _, machine := range machines.Items {
fmt.Printf("Checking machine object %q... ", machine.Name)
if machine.Status.ErrorReason != nil || machine.Status.ErrorMessage != nil {
var reason common.MachineStatusError = ""
if machine.Status.ErrorReason != nil {
reason = *machine.Status.ErrorReason
}
var message string = ""
if machine.Status.ErrorMessage != nil {
message = *machine.Status.ErrorMessage
}
fmt.Printf("FAIL\n")
fmt.Printf("\t[%v]: %s\n", reason, message)
pass = false
continue
}
if machine.Status.NodeRef == nil {
fmt.Printf("FAIL\n")
fmt.Printf("\tThe corresponding node does not exist.\n")
pass = false
continue
}
fmt.Printf("PASS\n")
}
if !pass {
return fmt.Errorf("Failed to validate machine objects.")
}
return nil
}
Loading

0 comments on commit eb250f5

Please sign in to comment.