diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 9a97f852..7e1f9437 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -289,6 +289,8 @@ var expectedConfig = `k9s: nodeShell: false shellPod: image: busybox:1.31 + command: [] + args: [] namespace: default limits: cpu: 100m @@ -309,6 +311,8 @@ var expectedConfig = `k9s: nodeShell: false shellPod: image: busybox:1.31 + command: [] + args: [] namespace: default limits: cpu: 100m @@ -329,6 +333,8 @@ var expectedConfig = `k9s: nodeShell: false shellPod: image: busybox:1.31 + command: [] + args: [] namespace: default limits: cpu: 100m @@ -373,6 +379,8 @@ var resetConfig = `k9s: nodeShell: false shellPod: image: busybox:1.31 + command: [] + args: [] namespace: default limits: cpu: 100m diff --git a/internal/config/shell_pod.go b/internal/config/shell_pod.go index 52555c36..1fc89a43 100644 --- a/internal/config/shell_pod.go +++ b/internal/config/shell_pod.go @@ -12,9 +12,11 @@ type Limits map[v1.ResourceName]string // ShellPod represents k9s shell configuration. type ShellPod struct { - Image string `json:"Image"` - Namespace string `json:"namespace"` - Limits Limits `json:"resources,omitempty"` + Image string `json:"image"` + Command []string `json:"command,omitempty"` + Args []string `json:"args,omitempty"` + Namespace string `json:"namespace"` + Limits Limits `json:"resources,omitempty"` } // NewShellPod returns a new instance. diff --git a/internal/config/styles.go b/internal/config/styles.go index ad824198..58c425bb 100644 --- a/internal/config/styles.go +++ b/internal/config/styles.go @@ -221,7 +221,7 @@ func (c Color) Color() tcell.Color { return tcell.ColorDefault } - return tcell.GetColor(string(c)) + return tcell.GetColor(string(c)).TrueColor() } // Colors converts series string colors to colors. diff --git a/internal/config/styles_test.go b/internal/config/styles_test.go index b7e9cf06..ec8938d7 100644 --- a/internal/config/styles_test.go +++ b/internal/config/styles_test.go @@ -1,7 +1,6 @@ package config_test import ( - "fmt" "testing" "github.com/derailed/k9s/internal/config" @@ -13,7 +12,7 @@ import ( func TestColor(t *testing.T) { uu := map[string]tcell.Color{ "blah": tcell.ColorDefault, - "blue": tcell.ColorBlue, + "blue": tcell.ColorBlue.TrueColor(), "#ffffff": tcell.NewHexColor(16777215), "#ff0000": tcell.NewHexColor(16711680), } @@ -21,7 +20,6 @@ func TestColor(t *testing.T) { for k := range uu { c, u := k, uu[k] t.Run(k, func(t *testing.T) { - fmt.Printf("%#v\n", config.NewColor(c).Color().Hex()) assert.Equal(t, u, config.NewColor(c).Color()) }) } @@ -32,12 +30,12 @@ func TestSkinNone(t *testing.T) { assert.Nil(t, s.Load("testdata/empty_skin.yml")) s.Update() - assert.Equal(t, "cadetblue", s.Body().FgColor.String()) - assert.Equal(t, "black", s.Body().BgColor.String()) - assert.Equal(t, "black", s.Table().BgColor.String()) - assert.Equal(t, tcell.ColorCadetBlue, s.FgColor()) - assert.Equal(t, tcell.ColorBlack, s.BgColor()) - assert.Equal(t, tcell.ColorBlack, tview.Styles.PrimitiveBackgroundColor) + assert.Equal(t, "#5f9ea0", s.Body().FgColor.String()) + assert.Equal(t, "#000000", s.Body().BgColor.String()) + assert.Equal(t, "#000000", s.Table().BgColor.String()) + assert.Equal(t, tcell.ColorCadetBlue.TrueColor(), s.FgColor()) + assert.Equal(t, tcell.ColorBlack.TrueColor(), s.BgColor()) + assert.Equal(t, tcell.ColorBlack.TrueColor(), tview.Styles.PrimitiveBackgroundColor) } func TestSkin(t *testing.T) { @@ -45,12 +43,12 @@ func TestSkin(t *testing.T) { assert.Nil(t, s.Load("testdata/black_and_wtf.yml")) s.Update() - assert.Equal(t, "white", s.Body().FgColor.String()) - assert.Equal(t, "black", s.Body().BgColor.String()) - assert.Equal(t, "black", s.Table().BgColor.String()) - assert.Equal(t, tcell.ColorWhite, s.FgColor()) - assert.Equal(t, tcell.ColorBlack, s.BgColor()) - assert.Equal(t, tcell.ColorBlack, tview.Styles.PrimitiveBackgroundColor) + assert.Equal(t, "#ffffff", s.Body().FgColor.String()) + assert.Equal(t, "#000000", s.Body().BgColor.String()) + assert.Equal(t, "#000000", s.Table().BgColor.String()) + assert.Equal(t, tcell.ColorWhite.TrueColor(), s.FgColor()) + assert.Equal(t, tcell.ColorBlack.TrueColor(), s.BgColor()) + assert.Equal(t, tcell.ColorBlack.TrueColor(), tview.Styles.PrimitiveBackgroundColor) } func TestSkinNotExits(t *testing.T) { diff --git a/internal/config/threshold.go b/internal/config/threshold.go index cf5f9e47..856e3ed6 100644 --- a/internal/config/threshold.go +++ b/internal/config/threshold.go @@ -91,6 +91,7 @@ func (t Threshold) LevelFor(k string, v int) SeverityLevel { // SeverityColor returns an defcon level associated level. func (t *Threshold) SeverityColor(k string, v int) string { + // nolint:exhaustive switch t.LevelFor(k, v) { case SeverityHigh: return "red" diff --git a/internal/dao/generic.go b/internal/dao/generic.go index 74959355..4de67aa1 100644 --- a/internal/dao/generic.go +++ b/internal/dao/generic.go @@ -85,7 +85,7 @@ func (g *Generic) ToYAML(path string, showManaged bool) (string, error) { raw, err := ToYAML(o, showManaged) if err != nil { - return "", fmt.Errorf("unable to marshal resource %s", err) + return "", fmt.Errorf("unable to marshal resource %w", err) } return raw, nil } diff --git a/internal/dao/ofaas.go b/internal/dao/ofaas.go index 832213ad..450c986a 100644 --- a/internal/dao/ofaas.go +++ b/internal/dao/ofaas.go @@ -204,7 +204,7 @@ func createSystemEndpoint(gateway, namespace string) (string, error) { gatewayURL, err := url.Parse(gateway) if err != nil { - return "", fmt.Errorf("invalid gateway URL: %s", err.Error()) + return "", fmt.Errorf("invalid gateway URL: %w", err) } gatewayURL.Path = path.Join(gatewayURL.Path, systemPath) if len(namespace) > 0 { diff --git a/internal/dao/resource.go b/internal/dao/resource.go index fbd6b549..400df09c 100644 --- a/internal/dao/resource.go +++ b/internal/dao/resource.go @@ -47,7 +47,7 @@ func (r *Resource) ToYAML(path string, showManaged bool) (string, error) { raw, err := ToYAML(o, showManaged) if err != nil { - return "", fmt.Errorf("unable to marshal resource %s", err) + return "", fmt.Errorf("unable to marshal resource %w", err) } return raw, nil } diff --git a/internal/model/pulse_health.go b/internal/model/pulse_health.go index 759fe2e0..fcc548fb 100644 --- a/internal/model/pulse_health.go +++ b/internal/model/pulse_health.go @@ -48,7 +48,7 @@ func (h *PulseHealth) List(ctx context.Context, ns string) ([]runtime.Object, er mm, err := h.checkMetrics(ctx) if err != nil { - return hh, nil + return hh, err } for _, m := range mm { hh = append(hh, m) diff --git a/internal/render/color.go b/internal/render/color.go index fc808060..e7fc49ff 100644 --- a/internal/render/color.go +++ b/internal/render/color.go @@ -39,6 +39,7 @@ func DefaultColorer(ns string, h Header, re RowEvent) tcell.Color { return ErrColor } + // nolint:exhaustive switch re.Kind { case EventAdd: return AddColor diff --git a/internal/render/hpa.go b/internal/render/hpa.go index 9444e2d5..3ff09480 100644 --- a/internal/render/hpa.go +++ b/internal/render/hpa.go @@ -175,6 +175,7 @@ func toMetricsV2b2(specs []autoscalingv2beta2.MetricSpec, statuses []autoscaling for i, spec := range specs { current := "" + // nolint:exhaustive switch spec.Type { case autoscalingv2beta2.ExternalMetricSourceType: list = append(list, externalMetricsV2b2(i, spec, statuses)) @@ -211,6 +212,7 @@ func toMetricsV2b2(specs []autoscalingv2beta2.MetricSpec, statuses []autoscaling func checkHPAType(i int, spec autoscalingv2beta1.MetricSpec, statuses []autoscalingv2beta1.MetricStatus) string { current := "" + // nolint:exhaustive switch spec.Type { case autoscalingv2beta1.ExternalMetricSourceType: return externalMetricsV2b1(i, spec, statuses) @@ -235,7 +237,7 @@ func externalMetricsV2b2(i int, spec autoscalingv2beta2.MetricSpec, statuses []a current := "" if spec.External.Target.AverageValue != nil { - if len(statuses) > i && statuses[i].External != nil && &statuses[i].External.Current.AverageValue != nil { + if len(statuses) > i && statuses[i].External != nil && statuses[i].External.Current.AverageValue != nil { current = statuses[i].External.Current.AverageValue.String() } return current + "/" + spec.External.Target.AverageValue.String() + " (avg)" @@ -272,7 +274,7 @@ func resourceMetricsV2b2(i int, spec autoscalingv2beta2.MetricSpec, statuses []a func externalMetricsV2b1(i int, spec autoscalingv2beta1.MetricSpec, statuses []autoscalingv2beta1.MetricStatus) string { current := "" if spec.External.TargetAverageValue != nil { - if len(statuses) > i && statuses[i].External != nil && &statuses[i].External.CurrentAverageValue != nil { + if len(statuses) > i && statuses[i].External != nil && statuses[i].External.CurrentAverageValue != nil { current = statuses[i].External.CurrentAverageValue.String() } return current + "/" + spec.External.TargetAverageValue.String() + " (avg)" diff --git a/internal/render/node.go b/internal/render/node.go index a4670055..266ebce1 100644 --- a/internal/render/node.go +++ b/internal/render/node.go @@ -188,6 +188,7 @@ func nodeRoles(node *v1.Node, res []string) { func getIPs(addrs []v1.NodeAddress) (iIP, eIP string) { for _, a := range addrs { + // nolint:exhaustive switch a.Type { case v1.NodeExternalIP: eIP = a.Address diff --git a/internal/render/pod.go b/internal/render/pod.go index f95e2f69..5ac012d3 100644 --- a/internal/render/pod.go +++ b/internal/render/pod.go @@ -257,6 +257,7 @@ func currentRes(mx *mv1beta1.PodMetrics) (resource.Quantity, resource.Quantity) } func (*Pod) mapQOS(class v1.PodQOSClass) string { + // nolint:exhaustive switch class { case v1.PodQOSGuaranteed: return "GA" diff --git a/internal/render/screen_dump_test.go b/internal/render/screen_dump_test.go index 7dfad7f5..b7737a90 100644 --- a/internal/render/screen_dump_test.go +++ b/internal/render/screen_dump_test.go @@ -34,7 +34,7 @@ var _ os.FileInfo = fileInfo{} func (f fileInfo) Name() string { return "bob" } func (f fileInfo) Size() int64 { return 100 } -func (f fileInfo) Mode() os.FileMode { return os.FileMode(644) } +func (f fileInfo) Mode() os.FileMode { return os.FileMode(0644) } func (f fileInfo) ModTime() time.Time { return testTime() } func (f fileInfo) IsDir() bool { return false } func (f fileInfo) Sys() interface{} { return nil } diff --git a/internal/tchart/component.go b/internal/tchart/component.go index 171fb2a8..8a0057ba 100644 --- a/internal/tchart/component.go +++ b/internal/tchart/component.go @@ -64,6 +64,7 @@ func (c *Component) SetLegend(l string) { // InputHandler returns the handler for this primitive. func (c *Component) InputHandler() func(event *tcell.EventKey, setFocus func(p tview.Primitive)) { return c.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p tview.Primitive)) { + // nolint:exhaustive switch key := event.Key(); key { case tcell.KeyEnter: case tcell.KeyBacktab, tcell.KeyTab: diff --git a/internal/tchart/gauge.go b/internal/tchart/gauge.go index e8f4eb6b..eef478a6 100644 --- a/internal/tchart/gauge.go +++ b/internal/tchart/gauge.go @@ -164,6 +164,7 @@ func computeDelta(d1, d2 int64) delta { func printDelta(sc tcell.Screen, d delta, o image.Point, s tcell.Style) { s = s.Dim(false) + // nolint:exhaustive switch d { case DeltaLess: sc.SetContent(o.X-1, o.Y+1, '↓', nil, s) diff --git a/internal/ui/config_test.go b/internal/ui/config_test.go index cd7c18de..b5fcaeaa 100644 --- a/internal/ui/config_test.go +++ b/internal/ui/config_test.go @@ -24,6 +24,6 @@ func TestConfiguratorRefreshStyle(t *testing.T) { cfg.RefreshStyles("") assert.True(t, cfg.HasSkin()) - assert.Equal(t, tcell.ColorGhostWhite, render.StdColor) - assert.Equal(t, tcell.ColorWhiteSmoke, render.ErrColor) + assert.Equal(t, tcell.ColorGhostWhite.TrueColor(), render.StdColor) + assert.Equal(t, tcell.ColorWhiteSmoke.TrueColor(), render.ErrColor) } diff --git a/internal/ui/crumbs_test.go b/internal/ui/crumbs_test.go index 64d4e3c4..25f673ff 100644 --- a/internal/ui/crumbs_test.go +++ b/internal/ui/crumbs_test.go @@ -23,7 +23,7 @@ func TestNewCrumbs(t *testing.T) { v.StackPushed(makeComponent("c2")) v.StackPushed(makeComponent("c3")) - assert.Equal(t, "[black:aqua:b] [-:black:-] [black:aqua:b] [-:black:-] [black:orange:b] [-:black:-] \n", v.GetText(false)) + assert.Equal(t, "[#000000:#00ffff:b] [-:#000000:-] [#000000:#00ffff:b] [-:#000000:-] [#000000:#ffa500:b] [-:#000000:-] \n", v.GetText(false)) } // Helpers... diff --git a/internal/ui/flash.go b/internal/ui/flash.go index d21ddcfa..1c2f64a6 100644 --- a/internal/ui/flash.go +++ b/internal/ui/flash.go @@ -85,6 +85,7 @@ func (f *Flash) flashEmoji(l model.FlashLevel) string { if f.app.Config.K9s.NoIcons { return "" } + // nolint:exhaustive switch l { case model.FlashWarn: return emoDoh @@ -98,6 +99,7 @@ func (f *Flash) flashEmoji(l model.FlashLevel) string { // Helpers... func flashColor(l model.FlashLevel) tcell.Color { + // nolint:exhaustive switch l { case model.FlashWarn: return tcell.ColorOrange diff --git a/internal/ui/logo_test.go b/internal/ui/logo_test.go index ebb67ad5..8ed7a5db 100644 --- a/internal/ui/logo_test.go +++ b/internal/ui/logo_test.go @@ -12,7 +12,7 @@ func TestNewLogoView(t *testing.T) { v := ui.NewLogo(config.NewStyles()) v.Reset() - const elogo = "[orange::b] ____ __.________ \n[orange::b]| |/ _/ __ \\______\n[orange::b]| < \\____ / ___/\n[orange::b]| | \\ / /\\___ \\ \n[orange::b]|____|__ \\ /____//____ >\n[orange::b] \\/ \\/ \n" + const elogo = "[#ffa500::b] ____ __.________ \n[#ffa500::b]| |/ _/ __ \\______\n[#ffa500::b]| < \\____ / ___/\n[#ffa500::b]| | \\ / /\\___ \\ \n[#ffa500::b]|____|__ \\ /____//____ >\n[#ffa500::b] \\/ \\/ \n" assert.Equal(t, elogo, v.Logo().GetText(false)) assert.Equal(t, "", v.Status().GetText(false)) } @@ -22,17 +22,17 @@ func TestLogoStatus(t *testing.T) { logo, msg, e string }{ "info": { - "[green::b] ____ __.________ \n[green::b]| |/ _/ __ \\______\n[green::b]| < \\____ / ___/\n[green::b]| | \\ / /\\___ \\ \n[green::b]|____|__ \\ /____//____ >\n[green::b] \\/ \\/ \n", + "[#008000::b] ____ __.________ \n[#008000::b]| |/ _/ __ \\______\n[#008000::b]| < \\____ / ___/\n[#008000::b]| | \\ / /\\___ \\ \n[#008000::b]|____|__ \\ /____//____ >\n[#008000::b] \\/ \\/ \n", "blee", "[white::b]blee\n", }, "warn": { - "[mediumvioletred::b] ____ __.________ \n[mediumvioletred::b]| |/ _/ __ \\______\n[mediumvioletred::b]| < \\____ / ___/\n[mediumvioletred::b]| | \\ / /\\___ \\ \n[mediumvioletred::b]|____|__ \\ /____//____ >\n[mediumvioletred::b] \\/ \\/ \n", + "[#c71585::b] ____ __.________ \n[#c71585::b]| |/ _/ __ \\______\n[#c71585::b]| < \\____ / ___/\n[#c71585::b]| | \\ / /\\___ \\ \n[#c71585::b]|____|__ \\ /____//____ >\n[#c71585::b] \\/ \\/ \n", "blee", "[white::b]blee\n", }, "err": { - "[red::b] ____ __.________ \n[red::b]| |/ _/ __ \\______\n[red::b]| < \\____ / ___/\n[red::b]| | \\ / /\\___ \\ \n[red::b]|____|__ \\ /____//____ >\n[red::b] \\/ \\/ \n", + "[#ff0000::b] ____ __.________ \n[#ff0000::b]| |/ _/ __ \\______\n[#ff0000::b]| < \\____ / ___/\n[#ff0000::b]| | \\ / /\\___ \\ \n[#ff0000::b]|____|__ \\ /____//____ >\n[#ff0000::b] \\/ \\/ \n", "blee", "[white::b]blee\n", }, diff --git a/internal/ui/menu_test.go b/internal/ui/menu_test.go index 6f9eb799..ab000d93 100644 --- a/internal/ui/menu_test.go +++ b/internal/ui/menu_test.go @@ -17,9 +17,9 @@ func TestNewMenu(t *testing.T) { {Mnemonic: "0", Description: "zero", Visible: true}, }) - assert.Equal(t, " [fuchsia:-:b]<0> [white:-:d]zero ", v.GetCell(0, 0).Text) - assert.Equal(t, " [dodgerblue:-:b] [white:-:d]bleeA ", v.GetCell(0, 1).Text) - assert.Equal(t, " [dodgerblue:-:b] [white:-:d]bleeB ", v.GetCell(1, 1).Text) + assert.Equal(t, " [#ff00ff:-:b]<0> [#ffffff:-:d]zero ", v.GetCell(0, 0).Text) + assert.Equal(t, " [#1e90ff:-:b] [#ffffff:-:d]bleeA ", v.GetCell(0, 1).Text) + assert.Equal(t, " [#1e90ff:-:b] [#ffffff:-:d]bleeB ", v.GetCell(1, 1).Text) } func TestActionHints(t *testing.T) { diff --git a/internal/ui/prompt.go b/internal/ui/prompt.go index 8c963be4..5a74503b 100644 --- a/internal/ui/prompt.go +++ b/internal/ui/prompt.go @@ -129,6 +129,7 @@ func (p *Prompt) keyboard(evt *tcell.EventKey) *tcell.EventKey { return evt } + // nolint:exhaustive switch evt.Key() { case tcell.KeyBackspace2, tcell.KeyBackspace, tcell.KeyDelete: p.model.Delete() @@ -242,6 +243,7 @@ func (p *Prompt) iconFor(k model.BufferKind) rune { return ' ' } + // nolint:exhaustive switch k { case model.CommandBuffer: return '🐶' @@ -254,6 +256,7 @@ func (p *Prompt) iconFor(k model.BufferKind) rune { // Helpers... func colorFor(k model.BufferKind) tcell.Color { + // nolint:exhaustive switch k { case model.CommandBuffer: return tcell.ColorAqua diff --git a/internal/ui/select_table.go b/internal/ui/select_table.go index e0371782..159a17ef 100644 --- a/internal/ui/select_table.go +++ b/internal/ui/select_table.go @@ -114,8 +114,9 @@ func (s *SelectTable) selectionChanged(r, c int) { if r < 0 { return } - cell := s.GetCell(r, c) - s.SetSelectedStyle(tcell.StyleDefault.Foreground(s.fgColor).Background(cell.Color).Attributes(tcell.AttrBold)) + if cell := s.GetCell(r, c); cell != nil { + s.SetSelectedStyle(tcell.StyleDefault.Foreground(s.fgColor).Background(cell.Color).Attributes(tcell.AttrBold)) + } } // ClearMarks delete all marked items. @@ -142,11 +143,9 @@ func (s *SelectTable) ToggleMark() { s.marks[sel] = struct{}{} } - cell := s.GetCell(s.GetSelectedRowIndex(), 0) - if cell == nil { - return + if cell := s.GetCell(s.GetSelectedRowIndex(), 0); cell != nil { + s.SetSelectedStyle(tcell.StyleDefault.Foreground(cell.BackgroundColor).Background(cell.Color).Attributes(tcell.AttrBold)) } - s.SetSelectedStyle(tcell.StyleDefault.Foreground(cell.BackgroundColor).Background(cell.Color).Attributes(tcell.AttrBold)) } // SpanMark toggles marked row diff --git a/internal/view/app.go b/internal/view/app.go index b988aa40..d1803aab 100644 --- a/internal/view/app.go +++ b/internal/view/app.go @@ -622,7 +622,7 @@ func (a *App) aliasCmd(evt *tcell.EventKey) *tcell.EventKey { func (a *App) gotoResource(cmd, path string, clearStack bool) error { err := a.command.run(cmd, path, clearStack) if err == nil { - return err + return nil } c := NewCow(a, err.Error()) diff --git a/internal/view/cluster_info.go b/internal/view/cluster_info.go index 0d586ba4..6baaefa7 100644 --- a/internal/view/cluster_info.go +++ b/internal/view/cluster_info.go @@ -62,9 +62,6 @@ func (c *ClusterInfo) hasMetrics() bool { func (c *ClusterInfo) layout() { for row, section := range []string{"Context", "Cluster", "User", "K9s Rev", "K8s Rev", "CPU", "MEM"} { - if (section == "CPU" || section == "MEM") && !c.hasMetrics() { - continue - } c.SetCell(row, 0, c.sectionCell(section)) c.SetCell(row, 1, c.infoCell(render.NAValue)) } @@ -118,6 +115,9 @@ func (c *ClusterInfo) ClusterInfoChanged(prev, curr model.ClusterMeta) { row = c.setCell(row, ui.AsPercDelta(prev.Cpu, curr.Cpu)) _ = c.setCell(row, ui.AsPercDelta(prev.Mem, curr.Mem)) c.setDefCon(curr.Cpu, curr.Mem) + } else { + row = c.setCell(row, "[orangered::b]n/a") + _ = c.setCell(row, "[orangered::b]n/a") } c.updateStyle() }) @@ -158,6 +158,7 @@ func (c *ClusterInfo) updateStyle() { // Helpers... func flashLevel(l config.SeverityLevel) model.FlashLevel { + // nolint:exhaustive switch l { case config.SeverityHigh: return model.FlashErr @@ -169,6 +170,7 @@ func flashLevel(l config.SeverityLevel) model.FlashLevel { } func flashMessage(l config.SeverityLevel) string { + // nolint:exhaustive switch l { case config.SeverityHigh: return "Critical" diff --git a/internal/view/cronjob.go b/internal/view/cronjob.go index 341e51f5..1a848856 100644 --- a/internal/view/cronjob.go +++ b/internal/view/cronjob.go @@ -165,7 +165,7 @@ func (c *CronJob) makeSuspendForm(sel string, suspend bool) *tview.Form { func (c *CronJob) toggleSuspend(ctx context.Context, path string) error { res, err := dao.AccessorFor(c.App().factory, c.GVR()) if err != nil { - return nil + return err } cronJob, ok := res.(*dao.CronJob) if !ok { diff --git a/internal/view/exec.go b/internal/view/exec.go index 158c7dee..e471f81a 100644 --- a/internal/view/exec.go +++ b/internal/view/exec.go @@ -173,7 +173,7 @@ func clearScreen() { const ( k9sShell = "k9s-shell" k9sShellRetryCount = 10 - k9sShellRetryDelay = 500 * time.Millisecond + k9sShellRetryDelay = 1 * time.Second ) func ssh(a *App, node string) error { @@ -218,6 +218,7 @@ func nukeK9sShell(a *App) error { } func launchShellPod(a *App, node string) error { + a.Flash().Infof("Launching node shell on %s...", node) ns := a.Config.K9s.ActiveCluster().ShellPod.Namespace spec := k9sShellPod(node, a.Config.K9s.ActiveCluster().ShellPod) ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) @@ -242,6 +243,7 @@ func launchShellPod(a *App, node string) error { if err := runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &pod); err != nil { return err } + log.Debug().Msgf("Checking shell pod [%d] %v", i, pod.Status.Phase) if pod.Status.Phase == v1.PodRunning { return nil } @@ -259,6 +261,30 @@ func k9sShellPod(node string, cfg *config.ShellPod) v1.Pod { var grace int64 var priv bool = true + log.Debug().Msgf("Shell Config %#v", cfg) + c := v1.Container{ + Name: k9sShell, + Image: cfg.Image, + VolumeMounts: []v1.VolumeMount{ + { + Name: "root-vol", + MountPath: "/host", + ReadOnly: true, + }, + }, + Resources: asResource(cfg.Limits), + Stdin: true, + SecurityContext: &v1.SecurityContext{ + Privileged: &priv, + }, + } + if len(cfg.Command) != 0 { + c.Command = cfg.Command + } + if len(cfg.Args) > 0 { + c.Args = cfg.Args + } + return v1.Pod{ ObjectMeta: metav1.ObjectMeta{ Name: k9sShellPodName(), @@ -280,24 +306,7 @@ func k9sShellPod(node string, cfg *config.ShellPod) v1.Pod { }, }, }, - Containers: []v1.Container{ - { - Name: k9sShell, - Image: cfg.Image, - VolumeMounts: []v1.VolumeMount{ - { - Name: "root-vol", - MountPath: "/host", - ReadOnly: true, - }, - }, - Resources: asResource(cfg.Limits), - Stdin: true, - SecurityContext: &v1.SecurityContext{ - Privileged: &priv, - }, - }, - }, + Containers: []v1.Container{c}, }, } } diff --git a/internal/view/help.go b/internal/view/help.go index d2cd6d75..dc09dc84 100644 --- a/internal/view/help.go +++ b/internal/view/help.go @@ -42,7 +42,7 @@ func NewHelp() *Help { // Init initializes the component. func (h *Help) Init(ctx context.Context) error { if err := h.Table.Init(ctx); err != nil { - return nil + return err } h.SetSelectable(false, false) h.resetTitle() diff --git a/internal/view/live_view.go b/internal/view/live_view.go index b5c9f7dd..d74a51dd 100644 --- a/internal/view/live_view.go +++ b/internal/view/live_view.go @@ -23,16 +23,16 @@ const liveViewTitleFmt = "[fg:bg:b] %s([hilite:bg:b]%s[fg:bg:-])[fg:bg:-] " type LiveView struct { *tview.Flex + title string + model model.ResourceViewer text *tview.TextView actions ui.KeyActions app *App - title string cmdBuff *model.FishBuff - model model.ResourceViewer currentRegion, maxRegions int + cancel context.CancelFunc fullScreen bool managedField bool - cancel context.CancelFunc autoRefresh bool } @@ -196,7 +196,9 @@ func (v *LiveView) Start() { } return } - v.model.Refresh(v.defaultCtx()) + if err := v.model.Refresh(v.defaultCtx()); err != nil { + log.Error().Err(err).Msgf("refresh failed") + } } func (v *LiveView) defaultCtx() context.Context { @@ -241,6 +243,11 @@ func (v *LiveView) toggleFullScreenCmd(evt *tcell.EventKey) *tcell.EventKey { v.fullScreen = !v.fullScreen v.SetFullScreen(v.fullScreen) v.Box.SetBorder(!v.fullScreen) + if v.fullScreen { + v.Box.SetBorderPadding(0, 0, 0, 0) + } else { + v.Box.SetBorderPadding(0, 0, 1, 1) + } return nil } diff --git a/internal/view/log.go b/internal/view/log.go index 6bf3672f..fb5ea216 100644 --- a/internal/view/log.go +++ b/internal/view/log.go @@ -409,6 +409,11 @@ func (l *Log) toggleFullScreenCmd(evt *tcell.EventKey) *tcell.EventKey { func (l *Log) goFullScreen() { l.SetFullScreen(l.indicator.FullScreen()) l.Box.SetBorder(!l.indicator.FullScreen()) + if l.indicator.FullScreen() { + l.logs.SetBorderPadding(0, 0, 0, 0) + } else { + l.logs.SetBorderPadding(0, 0, 1, 1) + } } // ---------------------------------------------------------------------------- diff --git a/internal/view/pf_extender.go b/internal/view/pf_extender.go index 02a4dc1f..111910ac 100644 --- a/internal/view/pf_extender.go +++ b/internal/view/pf_extender.go @@ -63,7 +63,7 @@ func (p *PortForwardExtender) portFwdCmd(evt *tcell.EventKey) *tcell.EventKey { func (p *PortForwardExtender) fetchPodName(path string) (string, error) { res, err := dao.AccessorFor(p.App().factory, p.GVR()) if err != nil { - return "", nil + return "", err } ctrl, ok := res.(dao.Controller) if !ok { diff --git a/internal/view/restart_extender.go b/internal/view/restart_extender.go index d76c9be5..1d89c754 100644 --- a/internal/view/restart_extender.go +++ b/internal/view/restart_extender.go @@ -64,7 +64,7 @@ func (r *RestartExtender) restartCmd(evt *tcell.EventKey) *tcell.EventKey { func (r *RestartExtender) restartRollout(ctx context.Context, path string) error { res, err := dao.AccessorFor(r.App().factory, r.GVR()) if err != nil { - return nil + return err } s, ok := res.(dao.Restartable) if !ok { diff --git a/internal/view/scale_extender.go b/internal/view/scale_extender.go index e6a788a6..adce5df8 100644 --- a/internal/view/scale_extender.go +++ b/internal/view/scale_extender.go @@ -113,7 +113,7 @@ func (s *ScaleExtender) makeStyledForm() *tview.Form { func (s *ScaleExtender) scale(ctx context.Context, path string, replicas int) error { res, err := dao.AccessorFor(s.App().factory, s.GVR()) if err != nil { - return nil + return err } scaler, ok := res.(dao.Scalable) if !ok { diff --git a/internal/view/yaml_test.go b/internal/view/yaml_test.go index 5e7ed5e9..4c01a6a0 100644 --- a/internal/view/yaml_test.go +++ b/internal/view/yaml_test.go @@ -14,44 +14,44 @@ func TestYaml(t *testing.T) { { `api: fred version: v1`, - `[steelblue::b]api[white::-]: [papayawhip::]fred - [steelblue::b]version[white::-]: [papayawhip::]v1`, + `[#4682b4::b]api[#ffffff::-]: [#ffefd5::]fred + [#4682b4::b]version[#ffffff::-]: [#ffefd5::]v1`, }, { `api: <<<"search_0">>>fred<<<"">>> version: v1`, - `[steelblue::b]api[white::-]: [papayawhip::]["search_0"]fred[""] - [steelblue::b]version[white::-]: [papayawhip::]v1`, + `[#4682b4::b]api[#ffffff::-]: [#ffefd5::]["search_0"]fred[""] + [#4682b4::b]version[#ffffff::-]: [#ffefd5::]v1`, }, { `api: version: v1`, - `[steelblue::b]api[white::-]: - [steelblue::b]version[white::-]: [papayawhip::]v1`, + `[#4682b4::b]api[#ffffff::-]: + [#4682b4::b]version[#ffffff::-]: [#ffefd5::]v1`, }, { " fred:blee", - "[papayawhip::] fred:blee", + "[#ffefd5::] fred:blee", }, { "fred blee: blee", - "[steelblue::b]fred blee[white::-]: [papayawhip::]blee", + "[#4682b4::b]fred blee[#ffffff::-]: [#ffefd5::]blee", }, { "Node-Selectors: ", - "[steelblue::b]Node-Selectors[white::-]: [papayawhip::] ", + "[#4682b4::b]Node-Selectors[#ffffff::-]: [#ffefd5::] ", }, { "fred.blee: ", - "[steelblue::b]fred.blee[white::-]: [papayawhip::] ", + "[#4682b4::b]fred.blee[#ffffff::-]: [#ffefd5::] ", }, { "certmanager.k8s.io/cluster-issuer: nameOfClusterIssuer", - "[steelblue::b]certmanager.k8s.io/cluster-issuer[white::-]: [papayawhip::]nameOfClusterIssuer", + "[#4682b4::b]certmanager.k8s.io/cluster-issuer[#ffffff::-]: [#ffefd5::]nameOfClusterIssuer", }, { "Message: Pod The node was low on resource: [DiskPressure].", - "[steelblue::b]Message[white::-]: [papayawhip::]Pod The node was low on resource: [DiskPressure[].", + "[#4682b4::b]Message[#ffffff::-]: [#ffefd5::]Pod The node was low on resource: [DiskPressure[].", }, } diff --git a/internal/xray/section.go b/internal/xray/section.go index edf2ba2d..a4f23965 100644 --- a/internal/xray/section.go +++ b/internal/xray/section.go @@ -56,6 +56,7 @@ func (*Section) outcomeRefs(parent *TreeNode, section render.Section) { func colorize(s string, l config.Level) string { c := "green" + // nolint:exhaustive switch l { case config.ErrorLevel: c = "red"