Skip to content

Commit

Permalink
Add "config edit" and "config status" for managing dynamic config (#315)
Browse files Browse the repository at this point in the history
* Adds "k0sctl config edit" and "k0sctl config status"

The subcommands are used to manage k0s dynamic config
  • Loading branch information
kke committed Feb 3, 2022
1 parent 44fb878 commit ce09f28
Show file tree
Hide file tree
Showing 3 changed files with 187 additions and 0 deletions.
113 changes: 113 additions & 0 deletions cmd/config_edit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package cmd

import (
"fmt"
"os"

"github.com/k0sproject/k0sctl/analytics"
"github.com/k0sproject/k0sctl/pkg/apis/k0sctl.k0sproject.io/v1beta1"
"github.com/k0sproject/rig/exec"

osexec "os/exec"

"github.com/mattn/go-isatty"
"github.com/urfave/cli/v2"
)

func shellEditor() (string, error) {
if v := os.Getenv("VISUAL"); v != "" {
return v, nil
}
if v := os.Getenv("EDITOR"); v != "" {
return v, nil
}
if path, err := osexec.LookPath("vi"); err == nil {
return path, nil
}

return "", fmt.Errorf("could not detect shell editor ($VISUAL, $EDITOR)")
}

var configEditCommand = &cli.Command{
Name: "edit",
Usage: "Edit k0s dynamic config in SHELL's default editor",
Flags: []cli.Flag{
configFlag,
debugFlag,
traceFlag,
redactFlag,
analyticsFlag,
upgradeCheckFlag,
},
Before: actions(initLogging, startCheckUpgrade, initConfig, initAnalytics),
After: actions(reportCheckUpgrade, closeAnalytics),
Action: func(ctx *cli.Context) error {
if !isatty.IsTerminal(os.Stdout.Fd()) {
return fmt.Errorf("output is not a terminal")
}

if err := analytics.Client.Publish("config-edit-start", map[string]interface{}{}); err != nil {
return err
}

editor, err := shellEditor()
if err != nil {
return err
}

c := ctx.Context.Value(ctxConfigKey{}).(*v1beta1.Cluster)
h := c.Spec.K0sLeader()

if err := h.Connect(); err != nil {
return fmt.Errorf("failed to connect: %w", err)
}
defer h.Disconnect()

if err := h.ResolveConfigurer(); err != nil {
return err
}

oldCfg, err := h.ExecOutput(h.Configurer.K0sCmdf("kubectl -n kube-system get clusterconfig k0s -o yaml"), exec.Sudo(h))
if err != nil {
return fmt.Errorf("%s: %w", h, err)
}

tmpFile, err := os.CreateTemp("", "k0s-config.*.yaml")
if err != nil {
return err
}
defer func() { _ = os.Remove(tmpFile.Name()) }()

if _, err := tmpFile.WriteString(oldCfg); err != nil {
return err
}

if err := tmpFile.Close(); err != nil {
return err
}

cmd := osexec.Command(editor, tmpFile.Name())
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return fmt.Errorf("failed to start editor (%s): %w", cmd.String(), err)
}

newCfgBytes, err := os.ReadFile(tmpFile.Name())
if err != nil {
return err
}
newCfg := string(newCfgBytes)

if newCfg == oldCfg {
return fmt.Errorf("configuration was not changed, aborting")
}

if err := h.Exec(h.Configurer.K0sCmdf("kubectl apply -n kube-system -f -"), exec.Stdin(newCfg), exec.Sudo(h)); err != nil {
return err
}

return nil
},
}
66 changes: 66 additions & 0 deletions cmd/config_status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package cmd

import (
"fmt"
"os"

"github.com/k0sproject/k0sctl/analytics"
"github.com/k0sproject/k0sctl/pkg/apis/k0sctl.k0sproject.io/v1beta1"
"github.com/k0sproject/rig/exec"

"github.com/mattn/go-isatty"
"github.com/urfave/cli/v2"
)

var configStatusCommand = &cli.Command{
Name: "status",
Usage: "Show k0s dynamic config reconciliation events",
Flags: []cli.Flag{
configFlag,
debugFlag,
traceFlag,
redactFlag,
analyticsFlag,
upgradeCheckFlag,
&cli.StringFlag{
Name: "output",
Usage: "kubectl output formatting",
Aliases: []string{"o"},
},
},
Before: actions(initLogging, startCheckUpgrade, initConfig, initAnalytics),
After: actions(reportCheckUpgrade, closeAnalytics),
Action: func(ctx *cli.Context) error {
if !isatty.IsTerminal(os.Stdout.Fd()) {
return fmt.Errorf("output is not a terminal")
}

if err := analytics.Client.Publish("config-status-start", map[string]interface{}{}); err != nil {
return err
}

c := ctx.Context.Value(ctxConfigKey{}).(*v1beta1.Cluster)
h := c.Spec.K0sLeader()

if err := h.Connect(); err != nil {
return fmt.Errorf("failed to connect: %w", err)
}
defer h.Disconnect()

if err := h.ResolveConfigurer(); err != nil {
return err
}
format := ctx.String("output")
if format != "" {
format = "-o " + format
}

output, err := h.ExecOutput(h.Configurer.K0sCmdf("kubectl -n kube-system get event --field-selector involvedObject.name=k0s %s", format), exec.Sudo(h))
if err != nil {
return fmt.Errorf("%s: %w", h, err)
}
fmt.Println(output)

return nil
},
}
8 changes: 8 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ var App = &cli.App{
initCommand,
resetCommand,
backupCommand,
{
Name: "config",
Usage: "Configuration related sub-commands",
Subcommands: []*cli.Command{
configEditCommand,
configStatusCommand,
},
},
completionCommand,
},
EnableBashCompletion: true,
Expand Down

0 comments on commit ce09f28

Please sign in to comment.