Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add json output for status #5611

Merged
merged 4 commits into from
Oct 22, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 54 additions & 12 deletions cmd/minikube/cmd/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ limitations under the License.
package cmd

import (
"encoding/json"
"fmt"
"os"
"strings"
"text/template"

"github.com/docker/machine/libmachine/state"
Expand All @@ -35,6 +38,15 @@ import (
)

var statusFormat string
var output string

var KubeconfigStatus = struct {
Configured string
Misconfigured string
}{
Configured: `Configured`,
Misconfigured: `Misconfigured`,
}

// Status represents the status
type Status struct {
Expand All @@ -51,7 +63,7 @@ const (
defaultStatusFormat = `host: {{.Host}}
kubelet: {{.Kubelet}}
apiserver: {{.APIServer}}
kubectl: {{.Kubeconfig}}
kubeconfig: {{.Kubeconfig}}
`
)

Expand All @@ -63,6 +75,11 @@ var statusCmd = &cobra.Command{
Exit status contains the status of minikube's VM, cluster and kubernetes encoded on it's bits in this order from right to left.
Eg: 7 meaning: 1 (for minikube NOK) + 2 (for cluster NOK) + 4 (for kubernetes NOK)`,
Run: func(cmd *cobra.Command, args []string) {

if output != "text" && statusFormat != defaultStatusFormat {
exit.UsageT("Cannot use both --output and --format options")
}

var returnCode = 0
api, err := machine.NewAPIClient()
if err != nil {
Expand Down Expand Up @@ -115,10 +132,9 @@ var statusCmd = &cobra.Command{
glog.Errorln("Error kubeconfig status:", err)
}
if ks {
kubeconfigSt = "Correctly Configured: pointing to minikube-vm at " + ip.String()
kubeconfigSt = KubeconfigStatus.Configured
} else {
kubeconfigSt = "Misconfigured: pointing to stale minikube-vm." +
"\nTo fix the kubectl context, run minikube update-context"
kubeconfigSt = KubeconfigStatus.Misconfigured
returnCode |= k8sNotRunningStatusFlag
}
} else {
Expand All @@ -131,21 +147,47 @@ var statusCmd = &cobra.Command{
APIServer: apiserverSt,
Kubeconfig: kubeconfigSt,
}
tmpl, err := template.New("status").Parse(statusFormat)
if err != nil {
exit.WithError("Error creating status template", err)
}
err = tmpl.Execute(os.Stdout, status)
if err != nil {
exit.WithError("Error executing status template", err)

switch strings.ToLower(output) {
case "text":
printStatusText(status)
case "json":
printStatusJSON(status)
default:
exit.WithCodeT(exit.BadUsage, fmt.Sprintf("invalid output format: %s. Valid values: 'text', 'json'", output))
}

os.Exit(returnCode)
},
}

func init() {
statusCmd.Flags().StringVar(&statusFormat, "format", defaultStatusFormat,
statusCmd.Flags().StringVarP(&statusFormat, "format", "f", defaultStatusFormat,
`Go template format string for the status output. The format for Go templates can be found here: https://golang.org/pkg/text/template/
For the list accessible variables for the template, see the struct values here: https://godoc.org/k8s.io/minikube/cmd/minikube/cmd#Status`)
statusCmd.Flags().StringVarP(&output, "output", "o", "text",
`minikube status --output OUTPUT. json, text`)
}

var printStatusText = func(status Status) {
tmpl, err := template.New("status").Parse(statusFormat)
if err != nil {
exit.WithError("Error creating status template", err)
}
err = tmpl.Execute(os.Stdout, status)
if err != nil {
exit.WithError("Error executing status template", err)
}
if status.Kubeconfig == KubeconfigStatus.Misconfigured {
out.WarningT("Warning: Your kubectl is pointing to stale minikube-vm.\nTo fix the kubectl context, run `minikube update-context`")
}
}

var printStatusJSON = func(status Status) {

jsonString, err := json.Marshal(status)
if err != nil {
exit.WithError("Error converting status to json", err)
}
out.String(string(jsonString))
}
41 changes: 41 additions & 0 deletions test/integration/functional_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ func TestFunctional(t *testing.T) {
{"ConfigCmd", validateConfigCmd},
{"DashboardCmd", validateDashboardCmd},
{"DNS", validateDNS},
{"StatusCmd", validateStatusCmd},
{"LogsCmd", validateLogsCmd},
{"MountCmd", validateMountCmd},
{"ProfileCmd", validateProfileCmd},
Expand Down Expand Up @@ -175,6 +176,46 @@ func validateComponentHealth(ctx context.Context, t *testing.T, profile string)
}
}

func validateStatusCmd(ctx context.Context, t *testing.T, profile string) {
rr, err := Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "status"))
if err != nil {
t.Errorf("%s failed: %v", rr.Args, err)
}

// Custom format
rr, err = Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "status", "-f", "host:{{.Host}},kublet:{{.Kubelet}},apiserver:{{.APIServer}},kubeconfig:{{.Kubeconfig}}"))
if err != nil {
t.Errorf("%s failed: %v", rr.Args, err)
}
match, _ := regexp.MatchString(`host:([A-z]+),kublet:([A-z]+),apiserver:([A-z]+),kubeconfig:([A-z]+)`, rr.Stdout.String())
if !match {
t.Errorf("%s failed: %v. Output for custom format did not match", rr.Args, err)
}

// Json output
rr, err = Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "status", "-o", "json"))
if err != nil {
t.Errorf("%s failed: %v", rr.Args, err)
}
var jsonObject map[string]interface{}
err = json.Unmarshal(rr.Stdout.Bytes(), &jsonObject)
if err != nil {
t.Errorf("%s failed: %v", rr.Args, err)
}
if _, ok := jsonObject["Host"]; !ok {
t.Errorf("%s failed: %v. Missing key %s in json object", rr.Args, err, "Host")
}
if _, ok := jsonObject["Kubelet"]; !ok {
t.Errorf("%s failed: %v. Missing key %s in json object", rr.Args, err, "Kubelet")
}
if _, ok := jsonObject["APIServer"]; !ok {
t.Errorf("%s failed: %v. Missing key %s in json object", rr.Args, err, "APIServer")
}
if _, ok := jsonObject["Kubeconfig"]; !ok {
t.Errorf("%s failed: %v. Missing key %s in json object", rr.Args, err, "Kubeconfig")
}
}

// validateDashboardCmd asserts that the dashboard command works
func validateDashboardCmd(ctx context.Context, t *testing.T, profile string) {
args := []string{"dashboard", "--url", "-p", profile, "--alsologtostderr", "-v=1"}
Expand Down