Feat: System diagnose (#4662)

* Feat: System Info & Diagnose

Signed-off-by: foursevenlove <foursevenlove@gmail.com>

* Fix:1.misspelling 2.license

Signed-off-by: foursevenlove <foursevenlove@gmail.com>

* Fix: pattern of imported package

Signed-off-by: foursevenlove <foursevenlove@gmail.com>

* Fix: pattern of imported package

Signed-off-by: foursevenlove <foursevenlove@gmail.com>

* Fix:1.return error instead of panic 2.get deployment by label instead of by namespace 3.when getting a single deployment, the result is displayed in multi rows. Feat: 1.the system info command displays the cpu and memory metrics 2.the system info command displays the numbers of ready pods and desired pods.

* Feat: 1.the system info command displays the environment variables

* Fix: Making syntax simple

* Feat(system info):1.ARGS多行展示2.指定名称时无须指定namespace3.优化界面展示,支持原始打印或者以wide/yaml形式打印4.指定名称时,打印更可读信息

Signed-off-by: foursevenlove <foursevenlove@gmail.com>

* Feat:add comment

Signed-off-by: foursevenlove <foursevenlove@gmail.com>

* Fix:syntactic redundancy

Signed-off-by: foursevenlove <foursevenlove@gmail.com>

* Feat:Display all ARGS

Signed-off-by: foursevenlove <foursevenlove@gmail.com>

* Feat:Display all ARGS

Signed-off-by: foursevenlove <foursevenlove@gmail.com>

Add signoff

* Fix:1.return error instead of panic 2.get deployment by label instead of by namespace 3.when getting a single deployment, the result is displayed in multi rows. Feat: 1.the system info command displays the cpu and memory metrics 2.the system info command displays the numbers of ready pods and desired pods.

Signed-off-by: foursevenlove <foursevenlove@gmail.com>

* Feat:System diagnose

Signed-off-by: foursevenlove <foursevenlove@gmail.com>

* Feat:Diagnose cluster-gateway pod's status

Signed-off-by: foursevenlove <foursevenlove@gmail.com>

Signed-off-by: foursevenlove <foursevenlove@gmail.com>
This commit is contained in:
47
2022-08-29 14:00:15 +08:00
committed by GitHub
parent 3531249e1b
commit 4e08ece053

View File

@@ -29,7 +29,11 @@ import (
v1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
apiregistrationV1beta "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1beta1"
apiregistration "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/typed/apiregistration/v1beta1"
"k8s.io/metrics/pkg/apis/metrics/v1beta1"
metrics "k8s.io/metrics/pkg/client/clientset/versioned"
"sigs.k8s.io/yaml"
@@ -44,6 +48,8 @@ const (
FlagSpecify = "specify"
// FlagOutputFormat specifies the output format. One of: (wide | yaml)
FlagOutputFormat = "output"
// APIServiceName is the name of APIService
APIServiceName = "v1alpha1.cluster.core.oam.dev"
)
// NewSystemCommand print system detail info
@@ -96,6 +102,16 @@ func NewSystemInfoCommand(c common.Args) *cobra.Command {
}
}
// Get kube config
if outputFormat != "" {
outputFormatOptions := map[string]struct{}{
"wide": {},
"yaml": {},
}
if _, exist := outputFormatOptions[outputFormat]; !exist {
return errors.Errorf("Outputformat must in wide | yaml !")
}
}
// Get kube config
config, err := c.GetConfig()
if err != nil {
return err
@@ -311,26 +327,18 @@ func NewSystemDiagnoseCommand(c common.Args) *cobra.Command {
Short: "Diagnoses system problems.",
Long: "Diagnoses system problems.",
RunE: func(cmd *cobra.Command, args []string) error {
// Diagnoses APIService of cluster-gateway
// Diagnose clusters' health
fmt.Println("------------------------------------------------------")
fmt.Println("Diagnosing APIService of cluster-gateway...")
fmt.Println("Diagnosing health of clusters...")
k8sClient, err := c.GetClient()
if err != nil {
return errors.Wrapf(err, "failed to get k8s client")
}
_, err = multicluster.GetClusterGatewayService(context.Background(), k8sClient)
if err != nil {
return errors.Wrapf(err, "failed to get cluster secret namespace, please ensure cluster gateway is correctly deployed")
}
fmt.Println("Result: APIService of cluster-gateway is fine~")
fmt.Println("------------------------------------------------------")
// Diagnose clusters' health
fmt.Println("------------------------------------------------------")
fmt.Println("Diagnosing health of clusters...")
clusters, err := multicluster.ListVirtualClusters(context.Background(), k8sClient)
if err != nil {
return errors.Wrap(err, "fail to get registered cluster")
}
// Get kube config
config, err := c.GetConfig()
if err != nil {
return err
@@ -348,6 +356,31 @@ func NewSystemDiagnoseCommand(c common.Args) *cobra.Command {
}
fmt.Println("Result: Clusters are fine~")
fmt.Println("------------------------------------------------------")
// Diagnoses the link of hub APIServer to cluster-gateway
fmt.Println("------------------------------------------------------")
fmt.Println("Diagnosing the link of hub APIServer to cluster-gateway...")
// Get clientset
clientset, err := apiregistration.NewForConfig(config)
if err != nil {
return err
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
apiService, err := clientset.APIServices().Get(ctx, APIServiceName, metav1.GetOptions{})
if err != nil {
return err
}
for _, condition := range apiService.Status.Conditions {
if condition.Type == "Available" {
if condition.Status != "True" {
cmd.Printf("APIService \"%s\" is not available! \nMessage: %s\n", APIServiceName, condition.Message)
return CheckAPIService(ctx, config, apiService)
}
cmd.Printf("APIService \"%s\" is available!\n", APIServiceName)
}
}
fmt.Println("Result: The link of hub APIServer to cluster-gateway is fine~")
fmt.Println("------------------------------------------------------")
// Todo: Diagnose others
return nil
},
@@ -357,3 +390,39 @@ func NewSystemDiagnoseCommand(c common.Args) *cobra.Command {
}
return cmd
}
// CheckAPIService checks the APIService
func CheckAPIService(ctx context.Context, config *rest.Config, apiService *apiregistrationV1beta.APIService) error {
svcName := apiService.Spec.Service.Name
svcNamespace := apiService.Spec.Service.Namespace
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
return err
}
svc, err := clientset.CoreV1().Services(svcNamespace).Get(ctx, svcName, metav1.GetOptions{})
if err != nil {
return err
}
set := labels.Set(svc.Spec.Selector)
listOptions := metav1.ListOptions{LabelSelector: set.AsSelector().String()}
pods, err := clientset.CoreV1().Pods(svcNamespace).List(ctx, listOptions)
if err != nil {
return err
}
if len(pods.Items) == 0 {
return errors.Errorf("No available pods in %s namespace with label %s.", svcNamespace, set.AsSelector().String())
}
for _, pod := range pods.Items {
for _, status := range pod.Status.ContainerStatuses {
if !status.Ready {
for _, condition := range pod.Status.Conditions {
if condition.Status != "True" {
return errors.Errorf("Pod %s is not ready. Condition \"%s\" status: %s.", pod.Name, condition.Type, condition.Status)
}
}
return errors.Errorf("Pod %s is not ready.", pod.Name)
}
}
}
return nil
}