Add paused state to apiserver status

pull/5962/head
Thomas Stromberg 2020-01-22 09:48:16 -08:00
parent 09b2780fb2
commit e6999caea3
2 changed files with 108 additions and 80 deletions

View File

@ -23,8 +23,10 @@ import (
"strings"
"text/template"
"github.com/docker/machine/libmachine"
"github.com/docker/machine/libmachine/state"
"github.com/golang/glog"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
cmdcfg "k8s.io/minikube/cmd/minikube/cmd/config"
@ -40,16 +42,13 @@ import (
var statusFormat string
var output string
// KubeconfigStatus represents the kubeconfig status
var KubeconfigStatus = struct {
Configured string
Misconfigured string
}{
Configured: `Configured`,
Misconfigured: `Misconfigured`,
}
const (
// Additional states used by kubeconfig
Configured = "Configured" // analagous to state.Saved
Misconfigured = "Misconfigured" // analagous to state.Error
)
// Status represents the status
// Status holds string representations of libmachine.state.State
type Status struct {
Host string
Kubelet string
@ -81,7 +80,6 @@ var statusCmd = &cobra.Command{
exit.UsageT("Cannot use both --output and --format options")
}
var returnCode = 0
api, err := machine.NewAPIClient()
if err != nil {
exit.WithCodeT(exit.Unavailable, "Error getting client: {{.error}}", out.V{"error": err})
@ -89,81 +87,91 @@ var statusCmd = &cobra.Command{
defer api.Close()
machineName := viper.GetString(config.MachineProfile)
hostSt, err := cluster.GetHostStatus(api, machineName)
st, err := status(api, machineName)
if err != nil {
exit.WithError("Error getting host status", err)
}
kubeletSt := state.None.String()
kubeconfigSt := state.None.String()
apiserverSt := state.None.String()
if hostSt == state.Running.String() {
clusterBootstrapper, err := getClusterBootstrapper(api, viper.GetString(cmdcfg.Bootstrapper))
if err != nil {
exit.WithError("Error getting bootstrapper", err)
}
kubeletSt, err = clusterBootstrapper.GetKubeletStatus()
if err != nil {
glog.Warningf("kubelet err: %v", err)
returnCode |= clusterNotRunningStatusFlag
} else if kubeletSt != state.Running.String() {
returnCode |= clusterNotRunningStatusFlag
}
ip, err := cluster.GetHostDriverIP(api, machineName)
if err != nil {
glog.Errorln("Error host driver ip status:", err)
}
apiserverPort, err := kubeconfig.Port(machineName)
if err != nil {
// Fallback to presuming default apiserver port
apiserverPort = constants.APIServerPort
}
apiserverSt, err = clusterBootstrapper.GetAPIServerStatus(ip, apiserverPort)
if err != nil {
glog.Errorln("Error apiserver status:", err)
} else if apiserverSt != state.Running.String() {
returnCode |= clusterNotRunningStatusFlag
}
ks, err := kubeconfig.IsClusterInConfig(ip, machineName)
if err != nil {
glog.Errorln("Error kubeconfig status:", err)
}
if ks {
kubeconfigSt = KubeconfigStatus.Configured
} else {
kubeconfigSt = KubeconfigStatus.Misconfigured
returnCode |= k8sNotRunningStatusFlag
}
} else {
returnCode |= minikubeNotRunningStatusFlag
}
status := Status{
Host: hostSt,
Kubelet: kubeletSt,
APIServer: apiserverSt,
Kubeconfig: kubeconfigSt,
glog.Errorf("status error: %v", err)
}
switch strings.ToLower(output) {
case "text":
printStatusText(status)
printStatusText(st)
case "json":
printStatusJSON(status)
printStatusJSON(st)
default:
exit.WithCodeT(exit.BadUsage, fmt.Sprintf("invalid output format: %s. Valid values: 'text', 'json'", output))
}
os.Exit(returnCode)
os.Exit(exitCode(st))
},
}
func exitCode(st *Status) int {
c := 0
if st.Host != state.Running.String() {
c |= minikubeNotRunningStatusFlag
}
if st.APIServer != state.Running.String() || st.Kubelet != state.Running.String() {
c |= clusterNotRunningStatusFlag
}
if st.Kubeconfig != Configured {
c |= k8sNotRunningStatusFlag
}
return c
}
func status(api libmachine.API, name string) (*Status, error) {
st := &Status{}
hs, err := cluster.GetHostStatus(api, name)
if err != nil {
return st, errors.Wrap(err, "host")
}
st.Host = hs
if st.Host != state.Running.String() {
return st, nil
}
bs, err := getClusterBootstrapper(api, viper.GetString(cmdcfg.Bootstrapper))
if err != nil {
return st, errors.Wrap(err, "bootstrapper")
}
st.Kubelet, err = bs.GetKubeletStatus()
if err != nil {
glog.Warningf("kubelet err: %v", err)
st.Kubelet = state.Error.String()
}
ip, err := cluster.GetHostDriverIP(api, name)
if err != nil {
glog.Errorln("Error host driver ip status:", err)
st.APIServer = state.Error.String()
return st, err
}
port, err := kubeconfig.Port(name)
if err != nil {
glog.Warningf("unable to get port: %v", err)
port = constants.APIServerPort
}
st.APIServer, err = bs.GetAPIServerStatus(ip, port)
if err != nil {
glog.Errorln("Error apiserver status:", err)
st.APIServer = state.Error.String()
}
ks, err := kubeconfig.IsClusterInConfig(ip, name)
if err != nil {
glog.Errorln("Error kubeconfig status:", err)
}
if ks {
st.Kubeconfig = Configured
} else {
st.Kubeconfig = Misconfigured
}
return st, nil
}
func init() {
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/
@ -172,25 +180,24 @@ For the list accessible variables for the template, see the struct values here:
`minikube status --output OUTPUT. json, text`)
}
var printStatusText = func(status Status) {
var printStatusText = func(st *Status) {
tmpl, err := template.New("status").Parse(statusFormat)
if err != nil {
exit.WithError("Error creating status template", err)
}
err = tmpl.Execute(os.Stdout, status)
err = tmpl.Execute(os.Stdout, st)
if err != nil {
exit.WithError("Error executing status template", err)
}
if status.Kubeconfig == KubeconfigStatus.Misconfigured {
if st.Kubeconfig == 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)
var printStatusJSON = func(st *Status) {
js, err := json.Marshal(st)
if err != nil {
exit.WithError("Error converting status to json", err)
}
out.String(string(jsonString))
out.String(string(js))
}

View File

@ -18,6 +18,7 @@ package kubeadm
import (
"os/exec"
"path"
"fmt"
"net"
@ -77,9 +78,11 @@ func NewBootstrapper(api libmachine.API) (*Bootstrapper, error) {
func (k *Bootstrapper) GetKubeletStatus() (string, error) {
rr, err := k.c.RunCmd(exec.Command("sudo", "systemctl", "is-active", "kubelet"))
if err != nil {
return "", errors.Wrapf(err, "getting kublet status. command: %q", rr.Command())
// Do not return now, as we still have parsing to do!
glog.Warningf("%s returned error: %v", rr.Command(), err)
}
s := strings.TrimSpace(rr.Stdout.String())
glog.Infof("kubelet is-active: %s", s)
switch s {
case "active":
return state.Running.String(), nil
@ -93,6 +96,24 @@ func (k *Bootstrapper) GetKubeletStatus() (string, error) {
// GetAPIServerStatus returns the api-server status
func (k *Bootstrapper) GetAPIServerStatus(ip net.IP, apiserverPort int) (string, error) {
// sudo, in case hidepid is set
rr, err := k.c.RunCmd(exec.Command("sudo", "pgrep", "kube-apiserver"))
if err != nil {
return state.Stopped.String(), nil
}
pid := strings.TrimSpace(rr.Stdout.String())
// Check if apiserver is in an uninteruptible sleep
rr, err = k.c.RunCmd(exec.Command("sudo", "cut", "-d", " ", "-f3", path.Join("/proc", pid, "stat")))
if err != nil {
return state.Error.String(), err
}
st := strings.TrimSpace(rr.Stdout.String())
glog.Infof("apiserver process state: %s", st)
if st == "S" {
return state.Paused.String(), nil
}
return kverify.APIServerStatus(ip, apiserverPort)
}