K9s/release v0.31.2 (#2452)

* [Bug] Fix #2428

* fix #2446

* fix #2449

* schemas updates

* Add debug info

* v0.31.2 rel notes
mine
Fernand Galiana 2024-01-09 11:34:46 -07:00 committed by GitHub
parent 98a7f3f1d6
commit 65100b05d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 102 additions and 28 deletions

View File

@ -11,7 +11,7 @@ DATE ?= $(shell TZ=UTC date -j -f "%s" ${SOURCE_DATE_EPOCH} +"%Y-%m-%dT%H:
else else
DATE ?= $(shell date -u -d @${SOURCE_DATE_EPOCH} +"%Y-%m-%dT%H:%M:%SZ") DATE ?= $(shell date -u -d @${SOURCE_DATE_EPOCH} +"%Y-%m-%dT%H:%M:%SZ")
endif endif
VERSION ?= v0.31.1 VERSION ?= v0.31.2
IMG_NAME := derailed/k9s IMG_NAME := derailed/k9s
IMAGE := ${IMG_NAME}:${VERSION} IMAGE := ${IMG_NAME}:${VERSION}

View File

@ -0,0 +1,51 @@
<img src="https://raw.githubusercontent.com/derailed/k9s/master/assets/k9s.png" align="center" width="800" height="auto"/>
# Release v0.31.2
## Notes
Thank you to all that contributed with flushing out issues and enhancements for K9s!
I'll try to mark some of these issues as fixed. But if you don't mind grab the latest rev
and see if we're happier with some of the fixes!
If you've filed an issue please help me verify and close.
Your support, kindness and awesome suggestions to make K9s better are, as ever, very much noted and appreciated!
Also big thanks to all that have allocated their own time to help others on both slack and on this repo!!
As you may know, K9s is not pimped out by corps with deep pockets, thus if you feel K9s is helping your Kubernetes journey,
please consider joining our [sponsorship program](https://github.com/sponsors/derailed) and/or make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
On Slack? Please join us [K9slackers](https://join.slack.com/t/k9sers/shared_invite/enQtOTA5MDEyNzI5MTU0LWQ1ZGI3MzliYzZhZWEyNzYxYzA3NjE0YTk1YmFmNzViZjIyNzhkZGI0MmJjYzhlNjdlMGJhYzE2ZGU1NjkyNTM)
## Maintenance Release!
Yikes! The aftermath...
Thank you all for pitching in and helping flesh out issues!!
Please make sure to add gory details to issues ie relevant configs, debug logs, etc...
Comments like: `same here!` doesn't really help us zero in. Everyone has slightly different settings/platforms so every little bits of info helps with the resolves.
Thank you!!
---
## Videos Are In The Can!
Please dial [K9s Channel](https://www.youtube.com/channel/UC897uwPygni4QIjkPCpgjmw) for up coming content...
* [K9s v0.31.0 Configs+Sneak peek](https://youtu.be/X3444KfjguE)
* [K9s v0.30.0 Sneak peek](https://youtu.be/mVBc1XneRJ4)
* [Vulnerability Scans](https://youtu.be/ULkl0MsaidU)
---
## Resolved Issues
* [#2449](https://github.com/derailed/k9s/issues/2449) [Bug]: views.yaml columns not respected on startup
* [#2448](https://github.com/derailed/k9s/issues/2448) Missing '.thresholds' in config.yaml result in 'assignment to entry in nil map'
* [#2446](https://github.com/derailed/k9s/issues/2446) Context Switch unreliable/not working
---
<img src="https://raw.githubusercontent.com/derailed/k9s/master/assets/imhotep_logo.png" width="32" height="auto"/> © 2024 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)

View File

@ -118,7 +118,7 @@ func (c *Config) CurrentContextName() (string, error) {
} }
cfg, err := c.RawConfig() cfg, err := c.RawConfig()
if err != nil { if err != nil {
return "", err return "", fmt.Errorf("fail to load rawConfig: %w", err)
} }
return cfg.CurrentContext, nil return cfg.CurrentContext, nil

View File

@ -68,16 +68,16 @@ func (c *Config) Refine(flags *genericclioptions.ConfigFlags, k9sFlags *Flags, c
} }
if isStringSet(flags.Context) { if isStringSet(flags.Context) {
if _, err := c.K9s.ActivateContext(*flags.Context); err != nil { if _, err := c.K9s.ActivateContext(*flags.Context); err != nil {
return err return fmt.Errorf("k8sflags. unable to activate context %q: %w", *flags.Context, err)
} }
} else { } else {
n, err := cfg.CurrentContextName() n, err := cfg.CurrentContextName()
if err != nil { if err != nil {
return err return fmt.Errorf("unable to retrieve kubeconfig current context %q: %w", n, err)
} }
_, err = c.K9s.ActivateContext(n) _, err = c.K9s.ActivateContext(n)
if err != nil { if err != nil {
return err return fmt.Errorf("unable to activate context %q: %w", *flags.Context, err)
} }
} }
log.Debug().Msgf("Active Context %q", c.K9s.ActiveContextName()) log.Debug().Msgf("Active Context %q", c.K9s.ActiveContextName())
@ -220,7 +220,7 @@ func (c *Config) Load(path string) error {
var cfg Config var cfg Config
if err := yaml.Unmarshal(bb, &cfg); err != nil { if err := yaml.Unmarshal(bb, &cfg); err != nil {
return err return fmt.Errorf("main config yaml load failed: %w", err)
} }
c.Merge(&cfg) c.Merge(&cfg)

View File

@ -4,7 +4,6 @@
package config_test package config_test
import ( import (
"errors"
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
@ -407,7 +406,7 @@ func TestConfigRefine(t *testing.T) {
uu := map[string]struct { uu := map[string]struct {
flags *genericclioptions.ConfigFlags flags *genericclioptions.ConfigFlags
k9sFlags *config.Flags k9sFlags *config.Flags
err error err string
context string context string
cluster string cluster string
namespace string namespace string
@ -488,7 +487,7 @@ func TestConfigRefine(t *testing.T) {
KubeConfig: &cfgFile, KubeConfig: &cfgFile,
Context: &ns1, Context: &ns1,
}, },
err: errors.New(`no context found for: "ns-1"`), err: `k8sflags. unable to activate context "ns-1": no context found for: "ns-1"`,
}, },
"use-current-context": { "use-current-context": {
flags: &genericclioptions.ConfigFlags{ flags: &genericclioptions.ConfigFlags{
@ -507,7 +506,7 @@ func TestConfigRefine(t *testing.T) {
err := cfg.Refine(u.flags, u.k9sFlags, client.NewConfig(u.flags)) err := cfg.Refine(u.flags, u.k9sFlags, client.NewConfig(u.flags))
if err != nil { if err != nil {
assert.Equal(t, u.err, err) assert.Equal(t, u.err, err.Error())
} else { } else {
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, u.context, cfg.K9s.ActiveContextName()) assert.Equal(t, u.context, cfg.K9s.ActiveContextName())

View File

@ -68,7 +68,7 @@ func (d *Dir) loadConfig(path string) (*Config, error) {
var cfg Config var cfg Config
if err := yaml.Unmarshal(bb, &cfg); err != nil { if err := yaml.Unmarshal(bb, &cfg); err != nil {
return nil, err return nil, fmt.Errorf("context-config yaml load failed: %w\n%s", err, string(bb))
} }
return &cfg, nil return &cfg, nil

View File

@ -30,9 +30,17 @@
}, },
"shellPod": { "shellPod": {
"type": "object", "type": "object",
"additionalProperties": false, "additionalProperties": true,
"properties": { "properties": {
"image": { "type": "string" }, "image": { "type": "string" },
"command": {
"type": "array",
"items": { "type": "string"}
},
"args": {
"type": "array",
"items": { "type": "string"}
},
"namespace": { "type": "string" }, "namespace": { "type": "string" },
"limits": { "limits": {
"type": "object", "type": "object",
@ -41,7 +49,13 @@
"memory": { "type": "string" } "memory": { "type": "string" }
}, },
"required": ["cpu", "memory"] "required": ["cpu", "memory"]
} },
"labels": {
"type": "object",
"additionalProperties": { "type": "string" },
"required": []
},
"tty": { "type": "boolean" }
}, },
"required": ["image", "namespace", "limits"] "required": ["image", "namespace", "limits"]
}, },

View File

@ -10,6 +10,7 @@ import (
"github.com/derailed/k9s/internal/client" "github.com/derailed/k9s/internal/client"
"github.com/derailed/k9s/internal/config/data" "github.com/derailed/k9s/internal/config/data"
"github.com/rs/zerolog/log"
) )
// K9s tracks K9s configuration options. // K9s tracks K9s configuration options.
@ -65,10 +66,11 @@ func (k *K9s) resetConnection(conn client.Connection) {
k.conn = conn k.conn = conn
} }
// Save saves the k9s config to dis. // Save saves the k9s config to disk.
func (k *K9s) Save() error { func (k *K9s) Save() error {
if k.activeConfig == nil { if k.activeConfig == nil {
return fmt.Errorf("save failed. no active config detected") log.Warn().Msgf("Save failed. no active config detected")
return nil
} }
path := filepath.Join( path := filepath.Join(
AppContextsDir, AppContextsDir,
@ -97,7 +99,9 @@ func (k *K9s) Merge(k1 *K9s) {
k.ShellPod = k1.ShellPod k.ShellPod = k1.ShellPod
k.Logger = k1.Logger k.Logger = k1.Logger
k.ImageScans = k1.ImageScans k.ImageScans = k1.ImageScans
k.Thresholds = k1.Thresholds if k1.Thresholds != nil {
k.Thresholds = k1.Thresholds
}
} }
// AppScreenDumpDir fetch screen dumps dir. // AppScreenDumpDir fetch screen dumps dir.
@ -193,6 +197,9 @@ func (k *K9s) ActivateContext(n string) (*data.Context, error) {
if k.activeConfig.Context == nil { if k.activeConfig.Context == nil {
return nil, fmt.Errorf("context activation failed for: %s", n) return nil, fmt.Errorf("context activation failed for: %s", n)
} }
if k.activeConfig.Context == nil {
return nil, fmt.Errorf("context activation failed for: %s", n)
}
return k.activeConfig.Context, nil return k.activeConfig.Context, nil
} }

View File

@ -453,10 +453,12 @@ func (a *App) isValidNS(ns string) (bool, error) {
return true, nil return true, nil
} }
func (a *App) switchContext(ci *cmd.Interpreter) error { func (a *App) switchContext(ci *cmd.Interpreter, force bool) error {
name, ok := ci.HasContext() name, ok := ci.HasContext()
if !ok || a.Config.ActiveContextName() == name { if !ok || a.Config.ActiveContextName() == name {
return nil if !force {
return nil
}
} }
a.Halt() a.Halt()

View File

@ -249,13 +249,6 @@ func (b *Browser) TableDataChanged(data *render.TableData) {
b.app.QueueUpdateDraw(func() { b.app.QueueUpdateDraw(func() {
b.refreshActions() b.refreshActions()
if !b.app.Config.K9s.UI.Reactive {
if err := b.app.RefreshCustomViews(); err != nil {
log.Warn().Err(err).Msg("CustomViews load failed")
b.app.Logo().Warn("Views load failed!")
}
}
b.Update(data, b.app.Conn().HasMetrics()) b.Update(data, b.app.Conn().HasMetrics())
}) })
} }

View File

@ -167,7 +167,7 @@ func (c *Command) run(p *cmd.Interpreter, fqn string, clearStack bool) error {
return err return err
} }
if err := c.app.switchContext(p); err != nil { if err := c.app.switchContext(p, false); err != nil {
return err return err
} }
} }

View File

@ -129,5 +129,5 @@ func useContext(app *App, name string) error {
return err return err
} }
return app.switchContext(cmd.NewInterpreter("ctx " + name)) return app.switchContext(cmd.NewInterpreter("ctx "+name), true)
} }

View File

@ -15,6 +15,7 @@ import (
"github.com/derailed/k9s/internal/render" "github.com/derailed/k9s/internal/render"
"github.com/derailed/k9s/internal/ui" "github.com/derailed/k9s/internal/ui"
"github.com/derailed/tcell/v2" "github.com/derailed/tcell/v2"
"github.com/rs/zerolog/log"
) )
// Table represents a table viewer. // Table represents a table viewer.
@ -46,6 +47,13 @@ func (t *Table) Init(ctx context.Context) (err error) {
ctx = context.WithValue(ctx, internal.KeyHasMetrics, t.app.Conn().HasMetrics()) ctx = context.WithValue(ctx, internal.KeyHasMetrics, t.app.Conn().HasMetrics())
} }
ctx = context.WithValue(ctx, internal.KeyStyles, t.app.Styles) ctx = context.WithValue(ctx, internal.KeyStyles, t.app.Styles)
if !t.app.Config.K9s.UI.Reactive {
if err := t.app.RefreshCustomViews(); err != nil {
log.Warn().Err(err).Msg("CustomViews load failed")
t.app.Logo().Warn("Views load failed!")
}
}
ctx = context.WithValue(ctx, internal.KeyViewConfig, t.app.CustomView) ctx = context.WithValue(ctx, internal.KeyViewConfig, t.app.CustomView)
t.Table.Init(ctx) t.Table.Init(ctx)
t.SetInputCapture(t.keyboard) t.SetInputCapture(t.keyboard)

View File

@ -1,6 +1,6 @@
name: k9s name: k9s
base: core20 base: core20
version: 'v0.31.1' version: 'v0.31.2'
summary: K9s is a CLI to view and manage your Kubernetes clusters. summary: K9s is a CLI to view and manage your Kubernetes clusters.
description: | description: |
K9s is a CLI to view and manage your Kubernetes clusters. By leveraging a terminal UI, you can easily traverse Kubernetes resources and view the state of your clusters in a single powerful session. K9s is a CLI to view and manage your Kubernetes clusters. By leveraging a terminal UI, you can easily traverse Kubernetes resources and view the state of your clusters in a single powerful session.