From 59d0d7335afa40fc7540969d7f080d4cd52969a8 Mon Sep 17 00:00:00 2001 From: Thomas Stromberg Date: Wed, 29 Jul 2020 13:57:06 -0700 Subject: [PATCH] Add HTTP-like status codes, remove unused fields --- cmd/minikube/cmd/status.go | 148 ++++++++++++++-------- pkg/minikube/out/register/cloud_events.go | 4 + 2 files changed, 102 insertions(+), 50 deletions(-) diff --git a/cmd/minikube/cmd/status.go b/cmd/minikube/cmd/status.go index dd1861e34e..fb7747b34a 100644 --- a/cmd/minikube/cmd/status.go +++ b/cmd/minikube/cmd/status.go @@ -52,30 +52,56 @@ var output string var layout string const ( - // # Additional states used by kubeconfig: - + // Additional legacy states: // Configured means configured Configured = "Configured" // ~state.Saved // Misconfigured means misconfigured Misconfigured = "Misconfigured" // ~state.Error - - // # Additional states used for clarity: - - // Nonexistent means nonexistent + // Nonexistent means the resource does not exist Nonexistent = "Nonexistent" // ~state.None // Irrelevant is used for statuses that aren't meaningful for worker nodes Irrelevant = "Irrelevant" - // New status modes - OK = "OK" // running + passes health checks - Error = "Error" // running but has an error - Warning = "Warning" // running but has warnings + // New status modes, based roughly on HTTP/SMTP standards + // 1xx signifies a transitional state. If retried, it will soon return a 2xx, 4xx, or 5xx + Starting = 100 + Pausing = 101 + Unpausing = 102 + Stopping = 110 + Deleting = 120 - Starting = "Starting" - Pausing = "Pausing" - Unpausing = "Unpausing" - Stopping = "Stopping" - Deleting = "Deleting" + // 2xx signifies that the API Server is able to service requests + OK = 200 + Warning = 203 + + // 4xx signifies an error that requires help from the client to resolve + NotFound = 404 + Stopped = 405 + Paused = 418 // I'm a teapot! + + // 5xx signifies a server-side error (that may be retryable) + Error = 500 + Unknown = 520 +) + +var ( + codeNames = map[int]string{ + 100: "Starting", + 101: "Pausing", + 102: "Unpausing", + 110: "Stopping", + 103: "Deleting", + + 200: "OK", + 203: "Warning", + + 404: "NotFound", + 405: "Stopped", + 418: "Paused", + + 500: "Error", + 520: "Unknown", + } ) // Status holds string representations of component states @@ -105,17 +131,20 @@ type NodeState struct { // BaseState holds a component state representation, such as "apiserver" or "kubeconfig" type BaseState struct { + // Name is the name of the object Name string - Kind string `json:",omitempty"` - Condition string - ConditionDetail string `json:",omitempty"` // Not yet implemented + // StatusCode is an HTTP-like status code for this object + StatusCode int + // Name is a human-readable name for the status code + StatusName string + // StatusDetail is long human-readable string describing why this particular status code was chosen + StatusDetail string `json:",omitempty"` // Not yet implemented - Step string `json:",omitempty"` + // Step is which workflow step the object is at. + Step string `json:",omitempty"` + // StepDetail is a long human-readable string describing the step StepDetail string `json:",omitempty"` - - Errors []string `json:",omitempty"` // Not yet implemented - Warnings []string `json:",omitempty"` // Not yet implemented } const ( @@ -162,7 +191,7 @@ var statusCmd = &cobra.Command{ exit.WithError("retrieving node", err) } - st, err := status(api, *cc, *n) + st, err := nodeStatus(api, *cc, *n) if err != nil { glog.Errorf("status error: %v", err) } @@ -171,7 +200,7 @@ var statusCmd = &cobra.Command{ for _, n := range cc.Nodes { machineName := driver.MachineName(*cc, n) glog.Infof("checking status of %s ...", machineName) - st, err := status(api, *cc, n) + st, err := nodeStatus(api, *cc, n) glog.Infof("%s status: %+v", machineName, st) if err != nil { @@ -210,6 +239,7 @@ var statusCmd = &cobra.Command{ }, } +// exitCode calcluates the appropriate exit code given a set of status messages func exitCode(statuses []*Status) int { c := 0 for _, st := range statuses { @@ -226,7 +256,8 @@ func exitCode(statuses []*Status) int { return c } -func status(api libmachine.API, cc config.ClusterConfig, n config.Node) (*Status, error) { +// nodeStatus looks up the status of a node +func nodeStatus(api libmachine.API, cc config.ClusterConfig, n config.Node) (*Status, error) { controlPlane := n.ControlPlane name := driver.MachineName(cc, n) @@ -363,6 +394,7 @@ func statusJSON(st []*Status, w io.Writer) error { return err } +// readEventLog reads cloudevent logs from $MINIKUBE_HOME/profiles//events.json func readEventLog(name string) ([]cloudevents.Event, time.Time, error) { path := localpath.EventLog(name) @@ -389,38 +421,43 @@ func readEventLog(name string) ([]cloudevents.Event, time.Time, error) { return events, st.ModTime(), nil } +// clusterState converts Status structs into a ClusterState struct func clusterState(sts []*Status) ClusterState { cs := ClusterState{ BinaryVersion: version.GetVersion(), BaseState: BaseState{ - Name: ClusterFlagValue(), - Kind: "cluster", - Condition: sts[0].APIServer, + Name: ClusterFlagValue(), + StatusCode: statusCode(sts[0].APIServer), }, Components: map[string]BaseState{ - "kubeconfig": {Name: "kubeconfig", Condition: newCondition(sts[0].Kubeconfig)}, + "kubeconfig": {Name: "kubeconfig", StatusCode: statusCode(sts[0].Kubeconfig)}, }, } for _, st := range sts { ns := NodeState{ BaseState: BaseState{ - Name: st.Name, - Condition: newCondition(st.Host), + Name: st.Name, + StatusCode: statusCode(st.Host), }, Components: map[string]BaseState{ - "kubelet": {Name: "kubelet", Kind: "service", Condition: newCondition(st.Kubelet)}, - "apiserver": {Name: "apiserver", Kind: "service", Condition: newCondition(st.APIServer)}, + "kubelet": {Name: "kubelet", StatusCode: statusCode(st.Kubelet)}, }, } - if st.Worker { - ns.Kind = "worker" - } else { - ns.Kind = "control-plane" + if st.APIServer != Irrelevant { + ns.Components["apiserver"] = BaseState{Name: "apiserver", StatusCode: statusCode(st.APIServer)} } + + // Convert status codes to status names + ns.StatusName = codeNames[ns.StatusCode] + for k, v := range ns.Components { + v.StatusName = codeNames[v.StatusCode] + ns.Components[k] = v + } + cs.Nodes = append(cs.Nodes, ns) } @@ -430,7 +467,7 @@ func clusterState(sts []*Status) ClusterState { return cs } - var transientCondition string + transientCode := 0 var finalStep map[string]string for _, ev := range evs { @@ -445,21 +482,22 @@ func clusterState(sts []*Status) ClusterState { switch data["name"] { case string(register.InitialSetup): - transientCondition = Starting + transientCode = Starting case string(register.Done): - transientCondition = "" + transientCode = 0 case string(register.Stopping): - transientCondition = Stopping + glog.Infof("%q == %q", data["name"], register.Stopping) + transientCode = Stopping case string(register.Deleting): - transientCondition = Deleting + transientCode = Deleting case string(register.Pausing): - transientCondition = Pausing + transientCode = Pausing case string(register.Unpausing): - transientCondition = Unpausing + transientCode = Unpausing } finalStep = data - glog.Infof("transient condition %q for step: %+v", transientCondition, data) + glog.Infof("transient code %d (%q) for step: %+v", transientCode, codeNames[transientCode], data) } } @@ -469,24 +507,34 @@ func clusterState(sts []*Status) ClusterState { } else { cs.Step = strings.TrimSpace(finalStep["name"]) cs.StepDetail = strings.TrimSpace(finalStep["message"]) - if transientCondition != "" { - cs.Condition = transientCondition + if transientCode != 0 { + cs.StatusCode = transientCode } } } + cs.StatusName = codeNames[cs.StatusCode] return cs } -func newCondition(st string) string { +// statusCode returns a status code number given a name +func statusCode(st string) int { + // legacy names switch st { case "Running", "Configured": return OK case "Misconfigured": return Error - default: - return st } + + // new names + for code, name := range codeNames { + if name == st { + return code + } + } + + return Unknown } func clusterStatusJSON(statuses []*Status, w io.Writer) error { diff --git a/pkg/minikube/out/register/cloud_events.go b/pkg/minikube/out/register/cloud_events.go index 5bdba6c24b..55d6a64827 100644 --- a/pkg/minikube/out/register/cloud_events.go +++ b/pkg/minikube/out/register/cloud_events.go @@ -60,6 +60,7 @@ func SetEventLogPath(path string) { eventFile = f } +// cloudEvent creates a CloudEvent from a log object & associated data func cloudEvent(log Log, data map[string]string) cloudevents.Event { event := cloudevents.NewEvent() event.SetSource("https://minikube.sigs.k8s.io/") @@ -72,6 +73,7 @@ func cloudEvent(log Log, data map[string]string) cloudevents.Event { return event } +// print JSON output to configured writer func printAsCloudEvent(log Log, data map[string]string) { event := cloudEvent(log, data) @@ -83,6 +85,7 @@ func printAsCloudEvent(log Log, data map[string]string) { fmt.Fprintln(outputFile, string(bs)) } +// print JSON output to configured writer, and record it to disk func printAndRecordCloudEvent(log Log, data map[string]string) { event := cloudEvent(log, data) @@ -105,6 +108,7 @@ func storeEvent(bs []byte) { } } +// record cloud event to disk func recordCloudEvent(log Log, data map[string]string) { if eventFile == nil { return