2020-12-07 14:24:15 +08:00
|
|
|
// Copyright 2020 KubeSphere 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.
|
|
|
|
|
2020-11-08 02:43:58 +08:00
|
|
|
package validator
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
2020-11-20 18:57:02 +08:00
|
|
|
"github.com/pkg/errors"
|
2020-11-08 02:43:58 +08:00
|
|
|
v1 "k8s.io/api/core/v1"
|
|
|
|
conf "kubeye/pkg/config"
|
|
|
|
"kubeye/pkg/kube"
|
2020-11-25 10:20:55 +08:00
|
|
|
"os"
|
2020-11-25 20:45:05 +08:00
|
|
|
"path/filepath"
|
2020-11-20 18:57:02 +08:00
|
|
|
"strings"
|
|
|
|
"text/tabwriter"
|
2020-11-25 10:20:55 +08:00
|
|
|
"time"
|
2020-11-08 02:43:58 +08:00
|
|
|
)
|
|
|
|
|
2020-11-25 20:45:05 +08:00
|
|
|
func Cluster(configuration string, ctx context.Context) error {
|
2020-11-08 02:43:58 +08:00
|
|
|
k, err := kube.CreateResourceProvider(ctx)
|
|
|
|
if err != nil {
|
2020-11-20 18:57:02 +08:00
|
|
|
return errors.Wrap(err, "Failed to get cluster information")
|
2020-11-08 02:43:58 +08:00
|
|
|
}
|
|
|
|
|
2020-11-20 18:57:02 +08:00
|
|
|
basicComponentStatus, err := ComponentStatusResult(k.ComponentStatus)
|
2020-11-08 02:43:58 +08:00
|
|
|
if err != nil {
|
2020-11-20 18:57:02 +08:00
|
|
|
return errors.Wrap(err, "Failed to get BasicComponentStatus information")
|
2020-11-08 02:43:58 +08:00
|
|
|
}
|
|
|
|
|
2020-11-10 10:49:25 +08:00
|
|
|
clusterCheckResults, err := ProblemDetectorResult(k.ProblemDetector)
|
2020-11-08 02:43:58 +08:00
|
|
|
if err != nil {
|
2020-11-20 18:57:02 +08:00
|
|
|
return errors.Wrap(err, "Failed to get clusterCheckResults information")
|
2020-11-08 02:43:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
nodeStatus, err := NodeStatusResult(k.Nodes)
|
|
|
|
if err != nil {
|
2020-11-20 18:57:02 +08:00
|
|
|
return errors.Wrap(err, "Failed to get nodeStatus information")
|
2020-11-08 02:43:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
var config conf.Configuration
|
2020-11-25 20:45:05 +08:00
|
|
|
var goodPractice []PodResult
|
|
|
|
if len(configuration) != 0 {
|
|
|
|
fp, err := filepath.Abs(configuration)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "Failed to look up current directory")
|
|
|
|
}
|
|
|
|
config1, err := conf.ParseFile1(fp)
|
|
|
|
goodPractice1, err := ValidatePods(ctx, &config1, k)
|
|
|
|
goodPractice = append(goodPractice, goodPractice1...)
|
|
|
|
|
|
|
|
}
|
2020-11-08 02:43:58 +08:00
|
|
|
config, err = conf.ParseFile()
|
2020-11-25 20:45:05 +08:00
|
|
|
goodPractice2, err := ValidatePods(ctx, &config, k)
|
|
|
|
goodPractice = append(goodPractice, goodPractice2...)
|
2020-11-08 02:43:58 +08:00
|
|
|
if err != nil {
|
2020-11-25 10:20:55 +08:00
|
|
|
errors.Wrap(err, "Failed to get goodPractice information")
|
2020-11-08 02:43:58 +08:00
|
|
|
}
|
|
|
|
|
2020-11-20 18:57:02 +08:00
|
|
|
w := tabwriter.NewWriter(os.Stdout, 10, 4, 3, ' ', 0)
|
|
|
|
if len(nodeStatus) != 0 {
|
2020-11-27 17:20:00 +08:00
|
|
|
fmt.Fprintln(w, "NODENAME\tSEVERITY\tHEARTBEATTIME\tREASON\tMESSAGE")
|
2020-11-20 18:57:02 +08:00
|
|
|
for _, nodestatus := range nodeStatus {
|
|
|
|
s := fmt.Sprintf("%s\t%s\t%s\t%s\t%-8v",
|
|
|
|
nodestatus.Name,
|
2020-11-27 17:20:00 +08:00
|
|
|
nodestatus.Severity,
|
|
|
|
nodestatus.HeartbeatTime.Format(time.RFC3339),
|
2020-11-20 18:57:02 +08:00
|
|
|
nodestatus.Reason,
|
|
|
|
nodestatus.Message,
|
|
|
|
)
|
|
|
|
fmt.Fprintln(w, s)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
2020-11-23 10:57:32 +08:00
|
|
|
|
2020-11-20 18:57:02 +08:00
|
|
|
if len(basicComponentStatus) != 0 {
|
2020-11-27 17:20:00 +08:00
|
|
|
fmt.Fprintln(w, "\nNAME\tSEVERITY\tTIME\tMESSAGE")
|
2020-11-20 18:57:02 +08:00
|
|
|
for _, basiccomponentStatus := range basicComponentStatus {
|
2020-11-25 10:20:55 +08:00
|
|
|
s := fmt.Sprintf("%s\t%s\t%s\t%-8v",
|
2020-11-20 18:57:02 +08:00
|
|
|
basiccomponentStatus.Name,
|
|
|
|
basiccomponentStatus.Severity,
|
2020-11-27 17:20:00 +08:00
|
|
|
basiccomponentStatus.Time,
|
2020-11-20 18:57:02 +08:00
|
|
|
basiccomponentStatus.Message,
|
|
|
|
)
|
|
|
|
fmt.Fprintln(w, s)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
2020-11-23 10:57:32 +08:00
|
|
|
|
2020-11-20 18:57:02 +08:00
|
|
|
if len(clusterCheckResults) != 0 {
|
2020-11-27 17:20:00 +08:00
|
|
|
fmt.Fprintln(w, "\nNAMESPACE\tNODENAME\tEVENTTIME\tREASON\tMESSAGE")
|
2020-11-20 18:57:02 +08:00
|
|
|
for _, clusterCheckResult := range clusterCheckResults {
|
|
|
|
s := fmt.Sprintf("%s\t%s\t%s\t%s\t%-8v",
|
|
|
|
clusterCheckResult.Namespace,
|
2020-11-27 17:20:00 +08:00
|
|
|
clusterCheckResult.Name,
|
|
|
|
clusterCheckResult.EventTime.Format(time.RFC3339),
|
2020-11-20 18:57:02 +08:00
|
|
|
clusterCheckResult.Reason,
|
|
|
|
clusterCheckResult.Message,
|
|
|
|
)
|
|
|
|
fmt.Fprintln(w, s)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
2020-11-23 10:57:32 +08:00
|
|
|
|
2020-11-20 18:57:02 +08:00
|
|
|
if len(goodPractice) != 0 {
|
2020-11-27 17:20:00 +08:00
|
|
|
fmt.Fprintln(w, "\nNAMESPACE\tNAME\tKIND\tTIME\tMESSAGE")
|
2020-11-20 18:57:02 +08:00
|
|
|
for _, goodpractice := range goodPractice {
|
|
|
|
s := fmt.Sprintf("%s\t%s\t%s\t%s\t%-8v",
|
|
|
|
goodpractice.Namespace,
|
2020-11-27 17:20:00 +08:00
|
|
|
goodpractice.Name,
|
2020-11-20 18:57:02 +08:00
|
|
|
goodpractice.Kind,
|
2020-11-27 17:20:00 +08:00
|
|
|
goodpractice.CreatedTime,
|
|
|
|
goodpractice.Message,
|
2020-11-20 18:57:02 +08:00
|
|
|
)
|
|
|
|
fmt.Fprintln(w, s)
|
|
|
|
continue
|
|
|
|
}
|
2020-11-08 02:43:58 +08:00
|
|
|
}
|
2020-11-20 18:57:02 +08:00
|
|
|
w.Flush()
|
|
|
|
|
|
|
|
//auditData := AuditData{
|
|
|
|
// AuditTime: k.CreationTime.Format(time.RFC3339),
|
|
|
|
// AuditAddress: k.AuditAddress,
|
|
|
|
//BasicComponentStatus: basicComponentStatus,
|
|
|
|
//BasicClusterInformation: BasicClusterInformation{
|
|
|
|
// K8sVersion: k.ServerVersion,
|
|
|
|
// PodNum: len(k.Pods),
|
|
|
|
// NodeNum: len(k.Nodes),
|
|
|
|
// NamespaceNum: len(k.Namespaces),
|
|
|
|
//},
|
2020-11-08 02:43:58 +08:00
|
|
|
|
2020-11-20 18:57:02 +08:00
|
|
|
//ClusterConfigurationResults: goodPractice,
|
|
|
|
//AllNodeStatusResults: nodeStatus,
|
|
|
|
//ClusterCheckResults: clusterCheckResults,
|
|
|
|
//}
|
|
|
|
|
|
|
|
//jsonBytes, err := json.Marshal(auditData)
|
|
|
|
//outputBytes, err := yaml.JSONToYAML(jsonBytes)
|
|
|
|
//os.Stdout.Write(outputBytes)
|
|
|
|
return nil
|
2020-11-08 02:43:58 +08:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-11-20 18:57:02 +08:00
|
|
|
func ComponentStatusResult(cs []v1.ComponentStatus) ([]BasicComponentStatus, error) {
|
|
|
|
var crs []BasicComponentStatus
|
2020-11-08 02:43:58 +08:00
|
|
|
for i := 0; i < len(cs); i++ {
|
2020-11-20 18:57:02 +08:00
|
|
|
if strings.Contains(cs[i].Conditions[0].Message, "ok") == true || strings.Contains(cs[i].Conditions[0].Message, "true") == true {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
cr := BasicComponentStatus{
|
2020-11-25 10:20:55 +08:00
|
|
|
Time: time.Now().Format(time.RFC3339),
|
2020-11-20 18:57:02 +08:00
|
|
|
Name: cs[i].ObjectMeta.Name,
|
|
|
|
Message: cs[i].Conditions[0].Message,
|
|
|
|
Severity: "danger",
|
|
|
|
}
|
|
|
|
crs = append(crs, cr)
|
2020-11-08 02:43:58 +08:00
|
|
|
}
|
2020-11-20 18:57:02 +08:00
|
|
|
return crs, nil
|
2020-11-08 02:43:58 +08:00
|
|
|
}
|
2020-11-10 10:49:25 +08:00
|
|
|
func ProblemDetectorResult(event []v1.Event) ([]ClusterCheckResults, error) {
|
|
|
|
var pdrs []ClusterCheckResults
|
|
|
|
for j := 0; j < len(event); j++ {
|
|
|
|
if event[j].Type == "Warning" {
|
|
|
|
pdr := ClusterCheckResults{
|
2020-11-08 02:43:58 +08:00
|
|
|
Namespace: event[j].ObjectMeta.Namespace,
|
2020-11-10 10:49:25 +08:00
|
|
|
Name: event[j].ObjectMeta.Name,
|
2020-11-08 02:43:58 +08:00
|
|
|
EventTime: event[j].LastTimestamp.Time,
|
2020-11-10 10:49:25 +08:00
|
|
|
Reason: event[j].Reason,
|
|
|
|
Message: event[j].Message,
|
2020-11-08 02:43:58 +08:00
|
|
|
}
|
|
|
|
pdrs = append(pdrs, pdr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return pdrs, nil
|
|
|
|
}
|
2020-11-10 10:49:25 +08:00
|
|
|
func NodeStatusResult(nodes []v1.Node) ([]AllNodeStatusResults, error) {
|
|
|
|
var nodestatus []AllNodeStatusResults
|
|
|
|
for k := 0; k < len(nodes); k++ {
|
2020-11-20 18:57:02 +08:00
|
|
|
if nodes[k].Status.Conditions[len(nodes[k].Status.Conditions)-1].Status == "True" {
|
|
|
|
continue
|
|
|
|
}
|
2020-11-10 10:49:25 +08:00
|
|
|
nodestate := AllNodeStatusResults{
|
|
|
|
Name: nodes[k].ObjectMeta.Name,
|
2020-11-08 02:43:58 +08:00
|
|
|
HeartbeatTime: nodes[k].Status.Conditions[len(nodes[k].Status.Conditions)-1].LastHeartbeatTime.Time,
|
2020-11-10 10:49:25 +08:00
|
|
|
Status: nodes[k].Status.Conditions[len(nodes[k].Status.Conditions)-1].Status,
|
|
|
|
Reason: nodes[k].Status.Conditions[len(nodes[k].Status.Conditions)-1].Reason,
|
|
|
|
Message: nodes[k].Status.Conditions[len(nodes[k].Status.Conditions)-1].Message,
|
2020-11-20 18:57:02 +08:00
|
|
|
Severity: "danger",
|
2020-11-08 02:43:58 +08:00
|
|
|
}
|
2020-11-20 18:57:02 +08:00
|
|
|
|
2020-11-08 02:43:58 +08:00
|
|
|
nodestatus = append(nodestatus, nodestate)
|
|
|
|
}
|
|
|
|
return nodestatus, nil
|
2020-11-10 10:49:25 +08:00
|
|
|
}
|