Add HTTP-like status codes, remove unused fields
parent
649b3789d9
commit
59d0d7335a
|
@ -52,30 +52,56 @@ var output string
|
||||||
var layout string
|
var layout string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// # Additional states used by kubeconfig:
|
// Additional legacy states:
|
||||||
|
|
||||||
// Configured means configured
|
// Configured means configured
|
||||||
Configured = "Configured" // ~state.Saved
|
Configured = "Configured" // ~state.Saved
|
||||||
// Misconfigured means misconfigured
|
// Misconfigured means misconfigured
|
||||||
Misconfigured = "Misconfigured" // ~state.Error
|
Misconfigured = "Misconfigured" // ~state.Error
|
||||||
|
// Nonexistent means the resource does not exist
|
||||||
// # Additional states used for clarity:
|
|
||||||
|
|
||||||
// Nonexistent means nonexistent
|
|
||||||
Nonexistent = "Nonexistent" // ~state.None
|
Nonexistent = "Nonexistent" // ~state.None
|
||||||
// Irrelevant is used for statuses that aren't meaningful for worker nodes
|
// Irrelevant is used for statuses that aren't meaningful for worker nodes
|
||||||
Irrelevant = "Irrelevant"
|
Irrelevant = "Irrelevant"
|
||||||
|
|
||||||
// New status modes
|
// New status modes, based roughly on HTTP/SMTP standards
|
||||||
OK = "OK" // running + passes health checks
|
// 1xx signifies a transitional state. If retried, it will soon return a 2xx, 4xx, or 5xx
|
||||||
Error = "Error" // running but has an error
|
Starting = 100
|
||||||
Warning = "Warning" // running but has warnings
|
Pausing = 101
|
||||||
|
Unpausing = 102
|
||||||
|
Stopping = 110
|
||||||
|
Deleting = 120
|
||||||
|
|
||||||
Starting = "Starting"
|
// 2xx signifies that the API Server is able to service requests
|
||||||
Pausing = "Pausing"
|
OK = 200
|
||||||
Unpausing = "Unpausing"
|
Warning = 203
|
||||||
Stopping = "Stopping"
|
|
||||||
Deleting = "Deleting"
|
// 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
|
// 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"
|
// BaseState holds a component state representation, such as "apiserver" or "kubeconfig"
|
||||||
type BaseState struct {
|
type BaseState struct {
|
||||||
|
// Name is the name of the object
|
||||||
Name string
|
Name string
|
||||||
Kind string `json:",omitempty"`
|
|
||||||
|
|
||||||
Condition string
|
// StatusCode is an HTTP-like status code for this object
|
||||||
ConditionDetail string `json:",omitempty"` // Not yet implemented
|
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"`
|
StepDetail string `json:",omitempty"`
|
||||||
|
|
||||||
Errors []string `json:",omitempty"` // Not yet implemented
|
|
||||||
Warnings []string `json:",omitempty"` // Not yet implemented
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -162,7 +191,7 @@ var statusCmd = &cobra.Command{
|
||||||
exit.WithError("retrieving node", err)
|
exit.WithError("retrieving node", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
st, err := status(api, *cc, *n)
|
st, err := nodeStatus(api, *cc, *n)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("status error: %v", err)
|
glog.Errorf("status error: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -171,7 +200,7 @@ var statusCmd = &cobra.Command{
|
||||||
for _, n := range cc.Nodes {
|
for _, n := range cc.Nodes {
|
||||||
machineName := driver.MachineName(*cc, n)
|
machineName := driver.MachineName(*cc, n)
|
||||||
glog.Infof("checking status of %s ...", machineName)
|
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)
|
glog.Infof("%s status: %+v", machineName, st)
|
||||||
|
|
||||||
if err != nil {
|
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 {
|
func exitCode(statuses []*Status) int {
|
||||||
c := 0
|
c := 0
|
||||||
for _, st := range statuses {
|
for _, st := range statuses {
|
||||||
|
@ -226,7 +256,8 @@ func exitCode(statuses []*Status) int {
|
||||||
return c
|
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
|
controlPlane := n.ControlPlane
|
||||||
name := driver.MachineName(cc, n)
|
name := driver.MachineName(cc, n)
|
||||||
|
@ -363,6 +394,7 @@ func statusJSON(st []*Status, w io.Writer) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// readEventLog reads cloudevent logs from $MINIKUBE_HOME/profiles/<name>/events.json
|
||||||
func readEventLog(name string) ([]cloudevents.Event, time.Time, error) {
|
func readEventLog(name string) ([]cloudevents.Event, time.Time, error) {
|
||||||
path := localpath.EventLog(name)
|
path := localpath.EventLog(name)
|
||||||
|
|
||||||
|
@ -389,38 +421,43 @@ func readEventLog(name string) ([]cloudevents.Event, time.Time, error) {
|
||||||
return events, st.ModTime(), nil
|
return events, st.ModTime(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clusterState converts Status structs into a ClusterState struct
|
||||||
func clusterState(sts []*Status) ClusterState {
|
func clusterState(sts []*Status) ClusterState {
|
||||||
cs := ClusterState{
|
cs := ClusterState{
|
||||||
BinaryVersion: version.GetVersion(),
|
BinaryVersion: version.GetVersion(),
|
||||||
|
|
||||||
BaseState: BaseState{
|
BaseState: BaseState{
|
||||||
Name: ClusterFlagValue(),
|
Name: ClusterFlagValue(),
|
||||||
Kind: "cluster",
|
StatusCode: statusCode(sts[0].APIServer),
|
||||||
Condition: sts[0].APIServer,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
Components: map[string]BaseState{
|
Components: map[string]BaseState{
|
||||||
"kubeconfig": {Name: "kubeconfig", Condition: newCondition(sts[0].Kubeconfig)},
|
"kubeconfig": {Name: "kubeconfig", StatusCode: statusCode(sts[0].Kubeconfig)},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, st := range sts {
|
for _, st := range sts {
|
||||||
ns := NodeState{
|
ns := NodeState{
|
||||||
BaseState: BaseState{
|
BaseState: BaseState{
|
||||||
Name: st.Name,
|
Name: st.Name,
|
||||||
Condition: newCondition(st.Host),
|
StatusCode: statusCode(st.Host),
|
||||||
},
|
},
|
||||||
Components: map[string]BaseState{
|
Components: map[string]BaseState{
|
||||||
"kubelet": {Name: "kubelet", Kind: "service", Condition: newCondition(st.Kubelet)},
|
"kubelet": {Name: "kubelet", StatusCode: statusCode(st.Kubelet)},
|
||||||
"apiserver": {Name: "apiserver", Kind: "service", Condition: newCondition(st.APIServer)},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if st.Worker {
|
if st.APIServer != Irrelevant {
|
||||||
ns.Kind = "worker"
|
ns.Components["apiserver"] = BaseState{Name: "apiserver", StatusCode: statusCode(st.APIServer)}
|
||||||
} else {
|
|
||||||
ns.Kind = "control-plane"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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)
|
cs.Nodes = append(cs.Nodes, ns)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -430,7 +467,7 @@ func clusterState(sts []*Status) ClusterState {
|
||||||
return cs
|
return cs
|
||||||
}
|
}
|
||||||
|
|
||||||
var transientCondition string
|
transientCode := 0
|
||||||
var finalStep map[string]string
|
var finalStep map[string]string
|
||||||
|
|
||||||
for _, ev := range evs {
|
for _, ev := range evs {
|
||||||
|
@ -445,21 +482,22 @@ func clusterState(sts []*Status) ClusterState {
|
||||||
|
|
||||||
switch data["name"] {
|
switch data["name"] {
|
||||||
case string(register.InitialSetup):
|
case string(register.InitialSetup):
|
||||||
transientCondition = Starting
|
transientCode = Starting
|
||||||
case string(register.Done):
|
case string(register.Done):
|
||||||
transientCondition = ""
|
transientCode = 0
|
||||||
case string(register.Stopping):
|
case string(register.Stopping):
|
||||||
transientCondition = Stopping
|
glog.Infof("%q == %q", data["name"], register.Stopping)
|
||||||
|
transientCode = Stopping
|
||||||
case string(register.Deleting):
|
case string(register.Deleting):
|
||||||
transientCondition = Deleting
|
transientCode = Deleting
|
||||||
case string(register.Pausing):
|
case string(register.Pausing):
|
||||||
transientCondition = Pausing
|
transientCode = Pausing
|
||||||
case string(register.Unpausing):
|
case string(register.Unpausing):
|
||||||
transientCondition = Unpausing
|
transientCode = Unpausing
|
||||||
}
|
}
|
||||||
|
|
||||||
finalStep = data
|
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 {
|
} else {
|
||||||
cs.Step = strings.TrimSpace(finalStep["name"])
|
cs.Step = strings.TrimSpace(finalStep["name"])
|
||||||
cs.StepDetail = strings.TrimSpace(finalStep["message"])
|
cs.StepDetail = strings.TrimSpace(finalStep["message"])
|
||||||
if transientCondition != "" {
|
if transientCode != 0 {
|
||||||
cs.Condition = transientCondition
|
cs.StatusCode = transientCode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cs.StatusName = codeNames[cs.StatusCode]
|
||||||
return cs
|
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 {
|
switch st {
|
||||||
case "Running", "Configured":
|
case "Running", "Configured":
|
||||||
return OK
|
return OK
|
||||||
case "Misconfigured":
|
case "Misconfigured":
|
||||||
return Error
|
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 {
|
func clusterStatusJSON(statuses []*Status, w io.Writer) error {
|
||||||
|
|
|
@ -60,6 +60,7 @@ func SetEventLogPath(path string) {
|
||||||
eventFile = f
|
eventFile = f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cloudEvent creates a CloudEvent from a log object & associated data
|
||||||
func cloudEvent(log Log, data map[string]string) cloudevents.Event {
|
func cloudEvent(log Log, data map[string]string) cloudevents.Event {
|
||||||
event := cloudevents.NewEvent()
|
event := cloudevents.NewEvent()
|
||||||
event.SetSource("https://minikube.sigs.k8s.io/")
|
event.SetSource("https://minikube.sigs.k8s.io/")
|
||||||
|
@ -72,6 +73,7 @@ func cloudEvent(log Log, data map[string]string) cloudevents.Event {
|
||||||
return event
|
return event
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// print JSON output to configured writer
|
||||||
func printAsCloudEvent(log Log, data map[string]string) {
|
func printAsCloudEvent(log Log, data map[string]string) {
|
||||||
event := cloudEvent(log, data)
|
event := cloudEvent(log, data)
|
||||||
|
|
||||||
|
@ -83,6 +85,7 @@ func printAsCloudEvent(log Log, data map[string]string) {
|
||||||
fmt.Fprintln(outputFile, string(bs))
|
fmt.Fprintln(outputFile, string(bs))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// print JSON output to configured writer, and record it to disk
|
||||||
func printAndRecordCloudEvent(log Log, data map[string]string) {
|
func printAndRecordCloudEvent(log Log, data map[string]string) {
|
||||||
event := cloudEvent(log, data)
|
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) {
|
func recordCloudEvent(log Log, data map[string]string) {
|
||||||
if eventFile == nil {
|
if eventFile == nil {
|
||||||
return
|
return
|
||||||
|
|
Loading…
Reference in New Issue