Skip to content

Commit ce09f28

Browse files
authored
Add "config edit" and "config status" for managing dynamic config (#315)
* Adds "k0sctl config edit" and "k0sctl config status" The subcommands are used to manage k0s dynamic config
1 parent 44fb878 commit ce09f28

File tree

3 files changed

+187
-0
lines changed

3 files changed

+187
-0
lines changed

cmd/config_edit.go

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
"github.com/k0sproject/k0sctl/analytics"
8+
"github.com/k0sproject/k0sctl/pkg/apis/k0sctl.k0sproject.io/v1beta1"
9+
"github.com/k0sproject/rig/exec"
10+
11+
osexec "os/exec"
12+
13+
"github.com/mattn/go-isatty"
14+
"github.com/urfave/cli/v2"
15+
)
16+
17+
func shellEditor() (string, error) {
18+
if v := os.Getenv("VISUAL"); v != "" {
19+
return v, nil
20+
}
21+
if v := os.Getenv("EDITOR"); v != "" {
22+
return v, nil
23+
}
24+
if path, err := osexec.LookPath("vi"); err == nil {
25+
return path, nil
26+
}
27+
28+
return "", fmt.Errorf("could not detect shell editor ($VISUAL, $EDITOR)")
29+
}
30+
31+
var configEditCommand = &cli.Command{
32+
Name: "edit",
33+
Usage: "Edit k0s dynamic config in SHELL's default editor",
34+
Flags: []cli.Flag{
35+
configFlag,
36+
debugFlag,
37+
traceFlag,
38+
redactFlag,
39+
analyticsFlag,
40+
upgradeCheckFlag,
41+
},
42+
Before: actions(initLogging, startCheckUpgrade, initConfig, initAnalytics),
43+
After: actions(reportCheckUpgrade, closeAnalytics),
44+
Action: func(ctx *cli.Context) error {
45+
if !isatty.IsTerminal(os.Stdout.Fd()) {
46+
return fmt.Errorf("output is not a terminal")
47+
}
48+
49+
if err := analytics.Client.Publish("config-edit-start", map[string]interface{}{}); err != nil {
50+
return err
51+
}
52+
53+
editor, err := shellEditor()
54+
if err != nil {
55+
return err
56+
}
57+
58+
c := ctx.Context.Value(ctxConfigKey{}).(*v1beta1.Cluster)
59+
h := c.Spec.K0sLeader()
60+
61+
if err := h.Connect(); err != nil {
62+
return fmt.Errorf("failed to connect: %w", err)
63+
}
64+
defer h.Disconnect()
65+
66+
if err := h.ResolveConfigurer(); err != nil {
67+
return err
68+
}
69+
70+
oldCfg, err := h.ExecOutput(h.Configurer.K0sCmdf("kubectl -n kube-system get clusterconfig k0s -o yaml"), exec.Sudo(h))
71+
if err != nil {
72+
return fmt.Errorf("%s: %w", h, err)
73+
}
74+
75+
tmpFile, err := os.CreateTemp("", "k0s-config.*.yaml")
76+
if err != nil {
77+
return err
78+
}
79+
defer func() { _ = os.Remove(tmpFile.Name()) }()
80+
81+
if _, err := tmpFile.WriteString(oldCfg); err != nil {
82+
return err
83+
}
84+
85+
if err := tmpFile.Close(); err != nil {
86+
return err
87+
}
88+
89+
cmd := osexec.Command(editor, tmpFile.Name())
90+
cmd.Stdin = os.Stdin
91+
cmd.Stdout = os.Stdout
92+
cmd.Stderr = os.Stderr
93+
if err := cmd.Run(); err != nil {
94+
return fmt.Errorf("failed to start editor (%s): %w", cmd.String(), err)
95+
}
96+
97+
newCfgBytes, err := os.ReadFile(tmpFile.Name())
98+
if err != nil {
99+
return err
100+
}
101+
newCfg := string(newCfgBytes)
102+
103+
if newCfg == oldCfg {
104+
return fmt.Errorf("configuration was not changed, aborting")
105+
}
106+
107+
if err := h.Exec(h.Configurer.K0sCmdf("kubectl apply -n kube-system -f -"), exec.Stdin(newCfg), exec.Sudo(h)); err != nil {
108+
return err
109+
}
110+
111+
return nil
112+
},
113+
}

cmd/config_status.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
"github.com/k0sproject/k0sctl/analytics"
8+
"github.com/k0sproject/k0sctl/pkg/apis/k0sctl.k0sproject.io/v1beta1"
9+
"github.com/k0sproject/rig/exec"
10+
11+
"github.com/mattn/go-isatty"
12+
"github.com/urfave/cli/v2"
13+
)
14+
15+
var configStatusCommand = &cli.Command{
16+
Name: "status",
17+
Usage: "Show k0s dynamic config reconciliation events",
18+
Flags: []cli.Flag{
19+
configFlag,
20+
debugFlag,
21+
traceFlag,
22+
redactFlag,
23+
analyticsFlag,
24+
upgradeCheckFlag,
25+
&cli.StringFlag{
26+
Name: "output",
27+
Usage: "kubectl output formatting",
28+
Aliases: []string{"o"},
29+
},
30+
},
31+
Before: actions(initLogging, startCheckUpgrade, initConfig, initAnalytics),
32+
After: actions(reportCheckUpgrade, closeAnalytics),
33+
Action: func(ctx *cli.Context) error {
34+
if !isatty.IsTerminal(os.Stdout.Fd()) {
35+
return fmt.Errorf("output is not a terminal")
36+
}
37+
38+
if err := analytics.Client.Publish("config-status-start", map[string]interface{}{}); err != nil {
39+
return err
40+
}
41+
42+
c := ctx.Context.Value(ctxConfigKey{}).(*v1beta1.Cluster)
43+
h := c.Spec.K0sLeader()
44+
45+
if err := h.Connect(); err != nil {
46+
return fmt.Errorf("failed to connect: %w", err)
47+
}
48+
defer h.Disconnect()
49+
50+
if err := h.ResolveConfigurer(); err != nil {
51+
return err
52+
}
53+
format := ctx.String("output")
54+
if format != "" {
55+
format = "-o " + format
56+
}
57+
58+
output, err := h.ExecOutput(h.Configurer.K0sCmdf("kubectl -n kube-system get event --field-selector involvedObject.name=k0s %s", format), exec.Sudo(h))
59+
if err != nil {
60+
return fmt.Errorf("%s: %w", h, err)
61+
}
62+
fmt.Println(output)
63+
64+
return nil
65+
},
66+
}

cmd/root.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ var App = &cli.App{
2020
initCommand,
2121
resetCommand,
2222
backupCommand,
23+
{
24+
Name: "config",
25+
Usage: "Configuration related sub-commands",
26+
Subcommands: []*cli.Command{
27+
configEditCommand,
28+
configStatusCommand,
29+
},
30+
},
2331
completionCommand,
2432
},
2533
EnableBashCompletion: true,

0 commit comments

Comments
 (0)