Merge branch 'master' of github.com-derailed:derailed/k9s
commit
2fdd848dce
|
|
@ -115,6 +115,8 @@ k9s info
|
||||||
k9s -n mycoolns
|
k9s -n mycoolns
|
||||||
# Start K9s in an existing KubeConfig context
|
# Start K9s in an existing KubeConfig context
|
||||||
k9s --context coolCtx
|
k9s --context coolCtx
|
||||||
|
# Start K9s in readonly mode - with all modification commands disabled
|
||||||
|
k9s --readonly
|
||||||
```
|
```
|
||||||
|
|
||||||
## Key Bindings
|
## Key Bindings
|
||||||
|
|
@ -150,6 +152,8 @@ K9s uses aliases to navigate most K8s resources.
|
||||||
k9s:
|
k9s:
|
||||||
# Indicates api-server poll intervals.
|
# Indicates api-server poll intervals.
|
||||||
refreshRate: 2
|
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.
|
# Indicates log view maximum buffer size. Default 1k lines.
|
||||||
logBufferSize: 200
|
logBufferSize: 200
|
||||||
# Indicates how many lines of logs to retrieve from the api-server. Default 200 lines.
|
# Indicates how many lines of logs to retrieve from the api-server. Default 200 lines.
|
||||||
|
|
|
||||||
10
cmd/root.go
10
cmd/root.go
|
|
@ -113,6 +113,10 @@ func loadConfiguration() *config.Config {
|
||||||
k9sCfg.K9s.OverrideHeadless(*k9sFlags.Headless)
|
k9sCfg.K9s.OverrideHeadless(*k9sFlags.Headless)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if k9sFlags.ReadOnly != nil {
|
||||||
|
k9sCfg.K9s.OverrideReadOnly(*k9sFlags.ReadOnly)
|
||||||
|
}
|
||||||
|
|
||||||
if k9sFlags.Command != nil {
|
if k9sFlags.Command != nil {
|
||||||
k9sCfg.K9s.OverrideCommand(*k9sFlags.Command)
|
k9sCfg.K9s.OverrideCommand(*k9sFlags.Command)
|
||||||
}
|
}
|
||||||
|
|
@ -189,6 +193,12 @@ func initK9sFlags() {
|
||||||
config.DefaultCommand,
|
config.DefaultCommand,
|
||||||
"Specify the default command to view when the application launches",
|
"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() {
|
func initK8sFlags() {
|
||||||
|
|
|
||||||
|
|
@ -205,6 +205,7 @@ func TestConfigSaveFile(t *testing.T) {
|
||||||
cfg.SetConnection(mc)
|
cfg.SetConnection(mc)
|
||||||
assert.Nil(t, cfg.Load("test_assets/k9s.yml"))
|
assert.Nil(t, cfg.Load("test_assets/k9s.yml"))
|
||||||
cfg.K9s.RefreshRate = 100
|
cfg.K9s.RefreshRate = 100
|
||||||
|
cfg.K9s.ReadOnly = true
|
||||||
cfg.K9s.LogBufferSize = 500
|
cfg.K9s.LogBufferSize = 500
|
||||||
cfg.K9s.LogRequestSize = 100
|
cfg.K9s.LogRequestSize = 100
|
||||||
cfg.K9s.CurrentContext = "blee"
|
cfg.K9s.CurrentContext = "blee"
|
||||||
|
|
@ -260,6 +261,7 @@ func TestSetup(t *testing.T) {
|
||||||
var expectedConfig = `k9s:
|
var expectedConfig = `k9s:
|
||||||
refreshRate: 100
|
refreshRate: 100
|
||||||
headless: false
|
headless: false
|
||||||
|
readOnly: true
|
||||||
logBufferSize: 500
|
logBufferSize: 500
|
||||||
logRequestSize: 100
|
logRequestSize: 100
|
||||||
currentContext: blee
|
currentContext: blee
|
||||||
|
|
@ -300,6 +302,7 @@ var expectedConfig = `k9s:
|
||||||
var resetConfig = `k9s:
|
var resetConfig = `k9s:
|
||||||
refreshRate: 2
|
refreshRate: 2
|
||||||
headless: false
|
headless: false
|
||||||
|
readOnly: false
|
||||||
logBufferSize: 200
|
logBufferSize: 200
|
||||||
logRequestSize: 200
|
logRequestSize: 200
|
||||||
currentContext: blee
|
currentContext: blee
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ type Flags struct {
|
||||||
Headless *bool
|
Headless *bool
|
||||||
Command *string
|
Command *string
|
||||||
AllNamespaces *bool
|
AllNamespaces *bool
|
||||||
|
ReadOnly *bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFlags returns new configuration flags.
|
// NewFlags returns new configuration flags.
|
||||||
|
|
@ -28,6 +29,7 @@ func NewFlags() *Flags {
|
||||||
Headless: boolPtr(false),
|
Headless: boolPtr(false),
|
||||||
Command: strPtr(DefaultCommand),
|
Command: strPtr(DefaultCommand),
|
||||||
AllNamespaces: boolPtr(false),
|
AllNamespaces: boolPtr(false),
|
||||||
|
ReadOnly: boolPtr(false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,14 @@ const (
|
||||||
defaultRefreshRate = 2
|
defaultRefreshRate = 2
|
||||||
defaultLogRequestSize = 200
|
defaultLogRequestSize = 200
|
||||||
defaultLogBufferSize = 1000
|
defaultLogBufferSize = 1000
|
||||||
|
defaultReadOnly = false
|
||||||
)
|
)
|
||||||
|
|
||||||
// K9s tracks K9s configuration options.
|
// K9s tracks K9s configuration options.
|
||||||
type K9s struct {
|
type K9s struct {
|
||||||
RefreshRate int `yaml:"refreshRate"`
|
RefreshRate int `yaml:"refreshRate"`
|
||||||
Headless bool `yaml:"headless"`
|
Headless bool `yaml:"headless"`
|
||||||
|
ReadOnly bool `yaml:"readOnly"`
|
||||||
LogBufferSize int `yaml:"logBufferSize"`
|
LogBufferSize int `yaml:"logBufferSize"`
|
||||||
LogRequestSize int `yaml:"logRequestSize"`
|
LogRequestSize int `yaml:"logRequestSize"`
|
||||||
CurrentContext string `yaml:"currentContext"`
|
CurrentContext string `yaml:"currentContext"`
|
||||||
|
|
@ -20,6 +22,7 @@ type K9s struct {
|
||||||
Clusters map[string]*Cluster `yaml:"clusters,omitempty"`
|
Clusters map[string]*Cluster `yaml:"clusters,omitempty"`
|
||||||
manualRefreshRate int
|
manualRefreshRate int
|
||||||
manualHeadless *bool
|
manualHeadless *bool
|
||||||
|
manualReadOnly *bool
|
||||||
manualCommand *string
|
manualCommand *string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -27,6 +30,7 @@ type K9s struct {
|
||||||
func NewK9s() *K9s {
|
func NewK9s() *K9s {
|
||||||
return &K9s{
|
return &K9s{
|
||||||
RefreshRate: defaultRefreshRate,
|
RefreshRate: defaultRefreshRate,
|
||||||
|
ReadOnly: defaultReadOnly,
|
||||||
LogBufferSize: defaultLogBufferSize,
|
LogBufferSize: defaultLogBufferSize,
|
||||||
LogRequestSize: defaultLogRequestSize,
|
LogRequestSize: defaultLogRequestSize,
|
||||||
Clusters: make(map[string]*Cluster),
|
Clusters: make(map[string]*Cluster),
|
||||||
|
|
@ -43,6 +47,11 @@ func (k *K9s) OverrideHeadless(b bool) {
|
||||||
k.manualHeadless = &b
|
k.manualHeadless = &b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OverrideReadOnly set the readonly mode manually.
|
||||||
|
func (k *K9s) OverrideReadOnly(b bool) {
|
||||||
|
k.manualReadOnly = &b
|
||||||
|
}
|
||||||
|
|
||||||
// OverrideCommand set the command manually.
|
// OverrideCommand set the command manually.
|
||||||
func (k *K9s) OverrideCommand(cmd string) {
|
func (k *K9s) OverrideCommand(cmd string) {
|
||||||
k.manualCommand = &cmd
|
k.manualCommand = &cmd
|
||||||
|
|
@ -68,6 +77,15 @@ func (k *K9s) GetRefreshRate() int {
|
||||||
return rate
|
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.
|
// ActiveCluster returns the currently active cluster.
|
||||||
func (k *K9s) ActiveCluster() *Cluster {
|
func (k *K9s) ActiveCluster() *Cluster {
|
||||||
if k.Clusters == nil {
|
if k.Clusters == nil {
|
||||||
|
|
|
||||||
|
|
@ -356,7 +356,7 @@ func (b *Browser) defaultContext() context.Context {
|
||||||
ctx = context.WithValue(ctx, internal.KeyLabels, ui.TrimLabelSelector(b.SearchBuff().String()))
|
ctx = context.WithValue(ctx, internal.KeyLabels, ui.TrimLabelSelector(b.SearchBuff().String()))
|
||||||
}
|
}
|
||||||
ctx = context.WithValue(ctx, internal.KeyFields, "")
|
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
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
@ -371,11 +371,13 @@ func (b *Browser) refreshActions() {
|
||||||
if b.app.ConOK() {
|
if b.app.ConOK() {
|
||||||
b.namespaceActions(aa)
|
b.namespaceActions(aa)
|
||||||
|
|
||||||
if client.Can(b.meta.Verbs, "edit") {
|
if !b.app.Config.K9s.GetReadOnly() {
|
||||||
aa[ui.KeyE] = ui.NewKeyAction("Edit", b.editCmd, true)
|
if client.Can(b.meta.Verbs, "edit") {
|
||||||
}
|
aa[ui.KeyE] = ui.NewKeyAction("Edit", b.editCmd, true)
|
||||||
if client.Can(b.meta.Verbs, "delete") {
|
}
|
||||||
aa[tcell.KeyCtrlD] = ui.NewKeyAction("Delete", b.deleteCmd, true)
|
if client.Can(b.meta.Verbs, "delete") {
|
||||||
|
aa[tcell.KeyCtrlD] = ui.NewKeyAction("Delete", b.deleteCmd, true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,11 +40,21 @@ func NewContainer(gvr client.GVR) ResourceViewer {
|
||||||
// Name returns the component name.
|
// Name returns the component name.
|
||||||
func (c *Container) Name() string { return containerTitle }
|
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) {
|
func (c *Container) bindKeys(aa ui.KeyActions) {
|
||||||
aa.Delete(tcell.KeyCtrlSpace, ui.KeySpace)
|
aa.Delete(tcell.KeyCtrlSpace, ui.KeySpace)
|
||||||
|
|
||||||
|
if !c.App().Config.K9s.GetReadOnly() {
|
||||||
|
c.bindDangerousKeys(aa)
|
||||||
|
}
|
||||||
|
|
||||||
aa.Add(ui.KeyActions{
|
aa.Add(ui.KeyActions{
|
||||||
ui.KeyShiftF: ui.NewKeyAction("PortForward", c.portFwdCmd, true),
|
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.KeyShiftC: ui.NewKeyAction("Sort CPU", c.GetTable().SortColCmd(6, false), false),
|
||||||
ui.KeyShiftM: ui.NewKeyAction("Sort MEM", c.GetTable().SortColCmd(7, 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),
|
ui.KeyShiftX: ui.NewKeyAction("Sort %CPU (REQ)", c.GetTable().SortColCmd(8, false), false),
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/derailed/k9s/internal"
|
"github.com/derailed/k9s/internal"
|
||||||
"github.com/derailed/k9s/internal/client"
|
"github.com/derailed/k9s/internal/client"
|
||||||
"github.com/derailed/k9s/internal/dao"
|
"github.com/derailed/k9s/internal/dao"
|
||||||
|
|
@ -36,10 +35,19 @@ func NewPod(gvr client.GVR) ResourceViewer {
|
||||||
return &p
|
return &p
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Pod) bindKeys(aa ui.KeyActions) {
|
func (p *Pod) bindDangerousKeys(aa ui.KeyActions) {
|
||||||
aa.Add(ui.KeyActions{
|
aa.Add(ui.KeyActions{
|
||||||
tcell.KeyCtrlK: ui.NewKeyAction("Kill", p.killCmd, true),
|
tcell.KeyCtrlK: ui.NewKeyAction("Kill", p.killCmd, true),
|
||||||
ui.KeyS: ui.NewKeyAction("Shell", p.shellCmd, 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.KeyShiftR: ui.NewKeyAction("Sort Ready", p.GetTable().SortColCmd(1, true), false),
|
||||||
ui.KeyShiftS: ui.NewKeyAction("Sort Status", p.GetTable().SortColCmd(2, 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),
|
ui.KeyShiftT: ui.NewKeyAction("Sort Restart", p.GetTable().SortColCmd(3, false), false),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue