Add support for storing/retrieving transient status

pull/8868/head
Thomas Stromberg 2020-07-27 21:34:52 -07:00
parent f3ef3f3918
commit 448ec75c8c
16 changed files with 201 additions and 24 deletions

View File

@ -44,6 +44,7 @@ import (
"k8s.io/minikube/pkg/minikube/localpath"
"k8s.io/minikube/pkg/minikube/machine"
"k8s.io/minikube/pkg/minikube/out"
"k8s.io/minikube/pkg/minikube/out/register"
)
var deleteAll bool
@ -125,6 +126,7 @@ func runDelete(cmd *cobra.Command, args []string) {
if len(args) > 0 {
exit.UsageT("Usage: minikube delete")
}
register.SetEventLogPath(localpath.EventLog(ClusterFlagValue()))
validProfiles, invalidProfiles, err := config.ListProfiles()
if err != nil {

View File

@ -28,9 +28,11 @@ import (
"k8s.io/minikube/pkg/minikube/cruntime"
"k8s.io/minikube/pkg/minikube/driver"
"k8s.io/minikube/pkg/minikube/exit"
"k8s.io/minikube/pkg/minikube/localpath"
"k8s.io/minikube/pkg/minikube/machine"
"k8s.io/minikube/pkg/minikube/mustload"
"k8s.io/minikube/pkg/minikube/out"
"k8s.io/minikube/pkg/minikube/out/register"
)
var (
@ -47,6 +49,7 @@ var pauseCmd = &cobra.Command{
func runPause(cmd *cobra.Command, args []string) {
co := mustload.Running(ClusterFlagValue())
register.SetEventLogPath(localpath.EventLog(ClusterFlagValue()))
for _, n := range co.Config.Nodes {
host, err := machine.LoadHost(co.API, driver.MachineName(*co.Config, n))

View File

@ -124,6 +124,8 @@ func platform() string {
// runStart handles the executes the flow of "minikube start"
func runStart(cmd *cobra.Command, args []string) {
register.SetEventLogPath(localpath.EventLog(ClusterFlagValue()))
out.SetJSON(viper.GetString(startOutput) == "json")
displayVersion(version.GetVersion())

View File

@ -17,6 +17,7 @@ limitations under the License.
package cmd
import (
"bufio"
"encoding/json"
"fmt"
"io"
@ -24,17 +25,21 @@ import (
"strings"
"text/template"
cloudevents "github.com/cloudevents/sdk-go/v2"
"github.com/docker/machine/libmachine"
"github.com/docker/machine/libmachine/state"
"github.com/golang/glog"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"go.etcd.io/etcd/version"
"k8s.io/minikube/pkg/minikube/bootstrapper/bsutil/kverify"
"k8s.io/minikube/pkg/minikube/cluster"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/driver"
"k8s.io/minikube/pkg/minikube/exit"
"k8s.io/minikube/pkg/minikube/kubeconfig"
"k8s.io/minikube/pkg/minikube/localpath"
"k8s.io/minikube/pkg/minikube/machine"
"k8s.io/minikube/pkg/minikube/mustload"
"k8s.io/minikube/pkg/minikube/node"
@ -59,14 +64,34 @@ const (
Irrelevant = "Irrelevant"
)
type ExperimentalComponent struct {
Name string
Kind string
Condition string
ConditionDetail []string
Step string
}
type ExperimentalCluster struct {
ExperimentalComponent
Components map[string]ExperimentalComponent
}
// Status holds string representations of component states
type Status struct {
Version string
Name string
Host string
Kubelet string
APIServer string
Kubeconfig string
Worker bool
// Prototyping for the future
ExperimentalCluster ExperimentalCluster
}
const (
@ -135,6 +160,8 @@ var statusCmd = &cobra.Command{
}
}
addExperimentalFields(statuses[0])
switch strings.ToLower(output) {
case "text":
for _, st := range statuses {
@ -154,6 +181,46 @@ var statusCmd = &cobra.Command{
},
}
func readEventLog(name string) ([]cloudevents.Event, error) {
path := localpath.EventLog(name)
f, err := os.Open(path)
if err != nil {
return nil, errors.Wrap(err, "open")
}
var events []cloudevents.Event
scanner := bufio.NewScanner(f)
for scanner.Scan() {
var ev cloudevents.Event
if err = json.Unmarshal(scanner.Bytes(), &ev); err != nil {
return events, err
}
events = append(events, ev)
}
return events, nil
}
func addExperimentalFields(st *Status) {
st.ExperimentalCluster.Condition = st.APIServer
evs, err := readEventLog(st.Name)
if err != nil {
glog.Errorf("unable to read event log: %v", err)
return
}
for _, ev := range evs {
glog.Infof("read event: %+v", ev)
/* if ev.Type() == "io.k8s.sigs.minikube.step" {
st.ExperimentalCluster.Step = ev.Data.Name
}
*/
}
}
func exitCode(statuses []*Status) int {
c := 0
for _, st := range statuses {
@ -176,6 +243,7 @@ func status(api libmachine.API, cc config.ClusterConfig, n config.Node) (*Status
name := driver.MachineName(cc, n)
st := &Status{
Version: version.Version,
Name: name,
Host: Nonexistent,
APIServer: Nonexistent,

View File

@ -33,6 +33,7 @@ import (
"k8s.io/minikube/pkg/minikube/machine"
"k8s.io/minikube/pkg/minikube/mustload"
"k8s.io/minikube/pkg/minikube/out"
"k8s.io/minikube/pkg/minikube/out/register"
"k8s.io/minikube/pkg/util/retry"
)
@ -60,6 +61,8 @@ func init() {
// runStop handles the executes the flow of "minikube stop"
func runStop(cmd *cobra.Command, args []string) {
register.SetEventLogPath(localpath.EventLog(ClusterFlagValue()))
// new code
var profilesToStop []string
if stopAll {

View File

@ -28,9 +28,11 @@ import (
"k8s.io/minikube/pkg/minikube/cruntime"
"k8s.io/minikube/pkg/minikube/driver"
"k8s.io/minikube/pkg/minikube/exit"
"k8s.io/minikube/pkg/minikube/localpath"
"k8s.io/minikube/pkg/minikube/machine"
"k8s.io/minikube/pkg/minikube/mustload"
"k8s.io/minikube/pkg/minikube/out"
"k8s.io/minikube/pkg/minikube/out/register"
)
// unpauseCmd represents the docker-pause command
@ -39,6 +41,8 @@ var unpauseCmd = &cobra.Command{
Short: "unpause Kubernetes",
Run: func(cmd *cobra.Command, args []string) {
cname := ClusterFlagValue()
register.SetEventLogPath(localpath.EventLog(cname))
co := mustload.Running(cname)
for _, n := range co.Config.Nodes {

2
go.mod
View File

@ -70,6 +70,7 @@ require (
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f
github.com/zchee/go-vmnet v0.0.0-20161021174912-97ebf9174097
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738
golang.org/x/build v0.0.0-20190927031335-2835ba2e683f
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
@ -83,6 +84,7 @@ require (
k8s.io/api v0.17.4
k8s.io/apimachinery v0.17.4
k8s.io/client-go v0.17.4
k8s.io/klog v1.0.0
k8s.io/kubectl v0.0.0
k8s.io/kubernetes v1.17.3
k8s.io/utils v0.0.0-20200229041039-0a110f9eb7ab // indirect

2
go.sum
View File

@ -244,6 +244,7 @@ github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
@ -1030,6 +1031,7 @@ github.com/zchee/go-vmnet v0.0.0-20161021174912-97ebf9174097 h1:Ucx5I1l1+TWXvqFm
github.com/zchee/go-vmnet v0.0.0-20161021174912-97ebf9174097/go.mod h1:lFZSWRIpCfE/pt91hHBBpV6+x87YlCjsp+aIR2qCPPU=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738 h1:VcrIfasaLFkyjk6KNlXQSzO+B0fZcnECiDrKJsfxka0=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=

View File

@ -61,6 +61,11 @@ func Profile(name string) string {
return filepath.Join(MiniPath(), "profiles", name)
}
// EventLog returns the path to a CloudEvents log
func EventLog(name string) string {
return filepath.Join(Profile(name), "events.json")
}
// ClientCert returns client certificate path, used by kubeconfig
func ClientCert(name string) string {
new := filepath.Join(Profile(name), "client.crt")

View File

@ -78,6 +78,7 @@ func T(style StyleEnum, format string, a ...V) {
register.PrintStep(outStyled)
return
}
register.RecordStep(outStyled)
String(outStyled)
}
@ -137,6 +138,8 @@ func Err(format string, a ...interface{}) {
register.PrintError(format)
return
}
register.RecordError(format)
if errFile == nil {
glog.Errorf("[unset errFile]: %s", fmt.Sprintf(format, a...))
return

View File

@ -20,6 +20,7 @@ import (
"fmt"
"io"
"os"
"path/filepath"
cloudevents "github.com/cloudevents/sdk-go/v2"
"github.com/golang/glog"
@ -31,11 +32,33 @@ const (
)
var (
OutputFile io.Writer = os.Stdout
outputFile io.Writer = os.Stdout
GetUUID = randomID
eventFile *os.File
)
func printAsCloudEvent(log Log, data map[string]string) {
func SetOutputFile(w io.Writer) {
outputFile = w
}
func SetEventLogPath(path string) {
if _, err := os.Stat(filepath.Dir(path)); err != nil {
if err := os.MkdirAll(filepath.Dir(path), 0777); err != nil {
glog.Errorf("Error creating profile directory", err)
return
}
}
f, err := os.Create(path)
if err != nil {
glog.Errorf("unable to write to %s: %v", path, err)
return
}
eventFile = f
}
func cloudEvent(log Log, data map[string]string) cloudevents.Event {
event := cloudevents.NewEvent()
event.SetSource("https://minikube.sigs.k8s.io/")
event.SetType(log.Type())
@ -44,11 +67,57 @@ func printAsCloudEvent(log Log, data map[string]string) {
glog.Warningf("error setting data: %v", err)
}
event.SetID(GetUUID())
json, err := event.MarshalJSON()
return event
}
func printAsCloudEvent(log Log, data map[string]string) {
event := cloudEvent(log, data)
bs, err := event.MarshalJSON()
if err != nil {
glog.Warningf("error marashalling event: %v", err)
glog.Errorf("error marashalling event: %v", err)
return
}
fmt.Fprintln(OutputFile, string(json))
fmt.Fprintln(outputFile, string(bs))
}
func printAndRecordCloudEvent(log Log, data map[string]string) {
event := cloudEvent(log, data)
bs, err := event.MarshalJSON()
if err != nil {
glog.Errorf("error marashalling event: %v", err)
return
}
fmt.Fprintln(outputFile, string(bs))
if eventFile != nil {
go storeEvent(bs)
}
}
func storeEvent(bs []byte) {
glog.Errorf("writing to eventfile: %s", string(bs))
fmt.Fprintln(eventFile, string(bs))
if err := eventFile.Sync(); err != nil {
glog.Warningf("even file flush failed: %v", err)
}
}
func recordCloudEvent(log Log, data map[string]string) {
if eventFile == nil {
return
}
go func() {
event := cloudEvent(log, data)
bs, err := event.MarshalJSON()
if err != nil {
glog.Errorf("error marashalling event: %v", err)
return
}
storeEvent(bs)
}()
}
func randomID() string {

View File

@ -19,7 +19,13 @@ package register
// PrintStep prints a Step type in JSON format
func PrintStep(message string) {
s := NewStep(message)
printAsCloudEvent(s, s.data)
printAndRecordCloudEvent(s, s.data)
}
// RecordStep records a Step type in JSON format
func RecordStep(message string) {
s := NewStep(message)
recordCloudEvent(s, s.data)
}
// PrintInfo prints an Info type in JSON format
@ -31,7 +37,7 @@ func PrintInfo(message string) {
// PrintDownload prints a Download type in JSON format
func PrintDownload(artifact string) {
s := NewDownload(artifact)
printAsCloudEvent(s, s.data)
printAndRecordCloudEvent(s, s.data)
}
// PrintDownloadProgress prints a DownloadProgress type in JSON format
@ -43,17 +49,23 @@ func PrintDownloadProgress(artifact, progress string) {
// PrintError prints an Error type in JSON format
func PrintError(err string) {
e := NewError(err)
printAsCloudEvent(e, e.data)
printAndRecordCloudEvent(e, e.data)
}
// RecordError records a Record type in JSON format
func RecordError(err string) {
e := NewError(err)
recordCloudEvent(e, e.data)
}
// PrintErrorExitCode prints an error in JSON format and includes an exit code
func PrintErrorExitCode(err string, exitcode int, additionalArgs ...map[string]string) {
e := NewErrorExitCode(err, exitcode, additionalArgs...)
printAsCloudEvent(e, e.data)
printAndRecordCloudEvent(e, e.data)
}
// PrintWarning prints a Warning type in JSON format
func PrintWarning(warning string) {
w := NewWarning(warning)
printAsCloudEvent(w, w.data)
printAndRecordCloudEvent(w, w.data)
}

View File

@ -29,8 +29,8 @@ func TestPrintStep(t *testing.T) {
expected += "\n"
buf := bytes.NewBuffer([]byte{})
OutputFile = buf
defer func() { OutputFile = os.Stdout }()
SetOutputFile(buf)
defer func() { SetOutputFile(os.Stdout) }()
GetUUID = func() string {
return "random-id"
@ -49,8 +49,8 @@ func TestPrintInfo(t *testing.T) {
expected += "\n"
buf := bytes.NewBuffer([]byte{})
OutputFile = buf
defer func() { OutputFile = os.Stdout }()
SetOutputFile(buf)
defer func() { SetOutputFile(os.Stdout) }()
GetUUID = func() string {
return "random-id"
@ -69,8 +69,8 @@ func TestError(t *testing.T) {
expected += "\n"
buf := bytes.NewBuffer([]byte{})
OutputFile = buf
defer func() { OutputFile = os.Stdout }()
SetOutputFile(buf)
defer func() { SetOutputFile(os.Stdout) }()
GetUUID = func() string {
return "random-id"
@ -89,8 +89,8 @@ func TestErrorExitCode(t *testing.T) {
expected += "\n"
buf := bytes.NewBuffer([]byte{})
OutputFile = buf
defer func() { OutputFile = os.Stdout }()
SetOutputFile(buf)
defer func() { SetOutputFile(os.Stdout) }()
GetUUID = func() string {
return "random-id"
@ -107,8 +107,8 @@ func TestWarning(t *testing.T) {
expected += "\n"
buf := bytes.NewBuffer([]byte{})
OutputFile = buf
defer func() { OutputFile = os.Stdout }()
SetOutputFile(buf)
defer func() { SetOutputFile(os.Stdout) }()
GetUUID = func() string {
return "random-id"

View File

@ -92,3 +92,5 @@ func (r *Register) currentStep() string {
func (r *Register) SetStep(s RegStep) {
r.current = s
}
// recordStep records the current step

View File

@ -32,8 +32,8 @@ func TestSetCurrentStep(t *testing.T) {
expected += "\n"
buf := bytes.NewBuffer([]byte{})
OutputFile = buf
defer func() { OutputFile = os.Stdout }()
SetOutputFile(buf)
defer func() { SetOutputFile(os.Stdout) }()
GetUUID = func() string {
return "random-id"

View File

@ -121,8 +121,8 @@ func TestDisplayJSON(t *testing.T) {
for _, tc := range tcs {
t.Run(tc.p.ID, func(t *testing.T) {
buf := bytes.NewBuffer([]byte{})
register.OutputFile = buf
defer func() { register.OutputFile = os.Stdout }()
register.SetOutputFile(buf)
defer func() { register.SetOutputFile(os.Stdout) }()
register.GetUUID = func() string {
return "random-id"