Merge pull request #524 from joscha-alisch/readonly-mode

Add readonly mode
mine
Fernand Galiana 2020-02-05 21:27:14 -08:00 committed by GitHub
commit ae648ddce5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 66 additions and 9 deletions

View File

@ -115,6 +115,8 @@ k9s info
k9s -n mycoolns
# Start K9s in an existing KubeConfig context
k9s --context coolCtx
# Start K9s in readonly mode - with all modification commands disabled
k9s --readonly
```
## Key Bindings
@ -150,6 +152,8 @@ K9s uses aliases to navigate most K8s resources.
k9s:
# Indicates api-server poll intervals.
refreshRate: 2
# Indicates whether modification commands like delete/kill/edit are disabled. Default is false
readOnly: false
# Indicates log view maximum buffer size. Default 1k lines.
logBufferSize: 200
# Indicates how many lines of logs to retrieve from the api-server. Default 200 lines.

View File

@ -113,6 +113,10 @@ func loadConfiguration() *config.Config {
k9sCfg.K9s.OverrideHeadless(*k9sFlags.Headless)
}
if k9sFlags.ReadOnly != nil {
k9sCfg.K9s.OverrideReadOnly(*k9sFlags.ReadOnly)
}
if k9sFlags.Command != nil {
k9sCfg.K9s.OverrideCommand(*k9sFlags.Command)
}
@ -189,6 +193,12 @@ func initK9sFlags() {
config.DefaultCommand,
"Specify the default command to view when the application launches",
)
rootCmd.Flags().BoolVar(
k9sFlags.ReadOnly,
"readonly",
false,
"Disable all commands that modify the cluster",
)
}
func initK8sFlags() {

View File

@ -205,6 +205,7 @@ func TestConfigSaveFile(t *testing.T) {
cfg.SetConnection(mc)
assert.Nil(t, cfg.Load("test_assets/k9s.yml"))
cfg.K9s.RefreshRate = 100
cfg.K9s.ReadOnly = true
cfg.K9s.LogBufferSize = 500
cfg.K9s.LogRequestSize = 100
cfg.K9s.CurrentContext = "blee"
@ -260,6 +261,7 @@ func TestSetup(t *testing.T) {
var expectedConfig = `k9s:
refreshRate: 100
headless: false
readOnly: true
logBufferSize: 500
logRequestSize: 100
currentContext: blee
@ -300,6 +302,7 @@ var expectedConfig = `k9s:
var resetConfig = `k9s:
refreshRate: 2
headless: false
readOnly: false
logBufferSize: 200
logRequestSize: 200
currentContext: blee

View File

@ -18,6 +18,7 @@ type Flags struct {
Headless *bool
Command *string
AllNamespaces *bool
ReadOnly *bool
}
// NewFlags returns new configuration flags.
@ -28,6 +29,7 @@ func NewFlags() *Flags {
Headless: boolPtr(false),
Command: strPtr(DefaultCommand),
AllNamespaces: boolPtr(false),
ReadOnly: boolPtr(false),
}
}

View File

@ -6,12 +6,14 @@ const (
defaultRefreshRate = 2
defaultLogRequestSize = 200
defaultLogBufferSize = 1000
defaultReadOnly = false
)
// K9s tracks K9s configuration options.
type K9s struct {
RefreshRate int `yaml:"refreshRate"`
Headless bool `yaml:"headless"`
ReadOnly bool `yaml:"readOnly"`
LogBufferSize int `yaml:"logBufferSize"`
LogRequestSize int `yaml:"logRequestSize"`
CurrentContext string `yaml:"currentContext"`
@ -20,6 +22,7 @@ type K9s struct {
Clusters map[string]*Cluster `yaml:"clusters,omitempty"`
manualRefreshRate int
manualHeadless *bool
manualReadOnly *bool
manualCommand *string
}
@ -27,6 +30,7 @@ type K9s struct {
func NewK9s() *K9s {
return &K9s{
RefreshRate: defaultRefreshRate,
ReadOnly: defaultReadOnly,
LogBufferSize: defaultLogBufferSize,
LogRequestSize: defaultLogRequestSize,
Clusters: make(map[string]*Cluster),
@ -43,6 +47,11 @@ func (k *K9s) OverrideHeadless(b bool) {
k.manualHeadless = &b
}
// OverrideReadOnly set the readonly mode manually.
func (k *K9s) OverrideReadOnly(b bool) {
k.manualReadOnly = &b
}
// OverrideCommand set the command manually.
func (k *K9s) OverrideCommand(cmd string) {
k.manualCommand = &cmd
@ -68,6 +77,15 @@ func (k *K9s) GetRefreshRate() int {
return rate
}
// GetReadOnly returns the readonly setting.
func (k *K9s) GetReadOnly() bool {
readOnly := k.ReadOnly
if k.manualReadOnly != nil && *k.manualReadOnly {
readOnly = *k.manualReadOnly
}
return readOnly
}
// ActiveCluster returns the currently active cluster.
func (k *K9s) ActiveCluster() *Cluster {
if k.Clusters == nil {

View File

@ -355,7 +355,7 @@ func (b *Browser) defaultContext() context.Context {
ctx = context.WithValue(ctx, internal.KeyLabels, ui.TrimLabelSelector(b.SearchBuff().String()))
}
ctx = context.WithValue(ctx, internal.KeyFields, "")
ctx = context.WithValue(ctx, internal.KeyNamespace, client.CleanseNamespace((b.App().Config.ActiveNamespace())))
ctx = context.WithValue(ctx, internal.KeyNamespace, client.CleanseNamespace(b.App().Config.ActiveNamespace()))
return ctx
}
@ -370,6 +370,7 @@ func (b *Browser) refreshActions() {
if b.app.ConOK() {
b.namespaceActions(aa)
if !b.app.Config.K9s.GetReadOnly() {
if client.Can(b.meta.Verbs, "edit") {
aa[ui.KeyE] = ui.NewKeyAction("Edit", b.editCmd, true)
}
@ -377,6 +378,7 @@ func (b *Browser) refreshActions() {
aa[tcell.KeyCtrlD] = ui.NewKeyAction("Delete", b.deleteCmd, true)
}
}
}
if !dao.IsK9sMeta(b.meta) {
aa[ui.KeyY] = ui.NewKeyAction("YAML", b.viewCmd, true)

View File

@ -40,11 +40,21 @@ func NewContainer(gvr client.GVR) ResourceViewer {
// Name returns the component name.
func (c *Container) Name() string { return containerTitle }
func (c *Container) bindDangerousKeys(aa ui.KeyActions) {
aa.Add(ui.KeyActions{
ui.KeyS: ui.NewKeyAction("Shell", c.shellCmd, true),
})
}
func (c *Container) bindKeys(aa ui.KeyActions) {
aa.Delete(tcell.KeyCtrlSpace, ui.KeySpace)
if !c.App().Config.K9s.GetReadOnly() {
c.bindDangerousKeys(aa)
}
aa.Add(ui.KeyActions{
ui.KeyShiftF: ui.NewKeyAction("PortForward", c.portFwdCmd, true),
ui.KeyS: ui.NewKeyAction("Shell", c.shellCmd, true),
ui.KeyShiftC: ui.NewKeyAction("Sort CPU", c.GetTable().SortColCmd(6, false), false),
ui.KeyShiftM: ui.NewKeyAction("Sort MEM", c.GetTable().SortColCmd(7, false), false),
ui.KeyShiftX: ui.NewKeyAction("Sort %CPU (REQ)", c.GetTable().SortColCmd(8, false), false),

View File

@ -4,7 +4,6 @@ import (
"context"
"errors"
"fmt"
"github.com/derailed/k9s/internal"
"github.com/derailed/k9s/internal/client"
"github.com/derailed/k9s/internal/dao"
@ -36,10 +35,19 @@ func NewPod(gvr client.GVR) ResourceViewer {
return &p
}
func (p *Pod) bindKeys(aa ui.KeyActions) {
func (p *Pod) bindDangerousKeys(aa ui.KeyActions) {
aa.Add(ui.KeyActions{
tcell.KeyCtrlK: ui.NewKeyAction("Kill", p.killCmd, true),
ui.KeyS: ui.NewKeyAction("Shell", p.shellCmd, true),
})
}
func (p *Pod) bindKeys(aa ui.KeyActions) {
if !p.App().Config.K9s.GetReadOnly() {
p.bindDangerousKeys(aa)
}
aa.Add(ui.KeyActions{
ui.KeyShiftR: ui.NewKeyAction("Sort Ready", p.GetTable().SortColCmd(1, true), false),
ui.KeyShiftS: ui.NewKeyAction("Sort Status", p.GetTable().SortColCmd(2, true), false),
ui.KeyShiftT: ui.NewKeyAction("Sort Restart", p.GetTable().SortColCmd(3, false), false),