From 34da44b441598c68fb6de1571f2a38f74d66bb01 Mon Sep 17 00:00:00 2001 From: Fernand Galiana Date: Tue, 26 Dec 2023 10:30:11 -0700 Subject: [PATCH] K9s/release v0.30.4 (#2392) * v0.30.3 version update (#2383) * Update build v0.30.2 * v0.30.3 * [Bug] Fix #2387 * [Bug] Fix #2391 * rel v0.30.4 --------- Co-authored-by: Emanuele Ciurleo --- Makefile | 2 +- change_logs/release_v0.30.4.md | 52 ++++++++++++++++++++++++++++ internal/client/client.go | 46 +++++++++++++++++++++++- internal/client/config.go | 4 +-- internal/client/config_test.go | 2 +- internal/config/data/dir.go | 11 ++---- internal/config/data/helpers_test.go | 31 +++++++++++++++++ internal/config/k9s.go | 3 +- internal/view/app.go | 6 ++-- snap/snapcraft.yaml | 2 +- 10 files changed, 140 insertions(+), 19 deletions(-) create mode 100644 change_logs/release_v0.30.4.md diff --git a/Makefile b/Makefile index 298dfa8d..a84db0a7 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ DATE ?= $(shell TZ=UTC date -j -f "%s" ${SOURCE_DATE_EPOCH} +"%Y-%m-%dT%H: else DATE ?= $(shell date -u -d @${SOURCE_DATE_EPOCH} +"%Y-%m-%dT%H:%M:%SZ") endif -VERSION ?= v0.30.3 +VERSION ?= v0.30.4 IMG_NAME := derailed/k9s IMAGE := ${IMG_NAME}:${VERSION} diff --git a/change_logs/release_v0.30.4.md b/change_logs/release_v0.30.4.md new file mode 100644 index 00000000..c7a1ad20 --- /dev/null +++ b/change_logs/release_v0.30.4.md @@ -0,0 +1,52 @@ + + +# Release v0.30.4 + +## 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! 🎄 + +Thank you all for pitching in and helping flesh out issues!! + +--- + +## Videos Are In The Can! + +Please dial [K9s Channel](https://www.youtube.com/channel/UC897uwPygni4QIjkPCpgjmw) for up coming content... + +* [K9s v0.30.0 Sneak peek](https://youtu.be/mVBc1XneRJ4) +* [Vulnerability Scans](https://youtu.be/ULkl0MsaidU) + +--- + +## Resolved Issues + +* [#2391](https://github.com/derailed/k9s/issues/2391) Version 0.30.* has issues with : chars in the cluster names from AWS +* [#2397](https://github.com/derailed/k9s/issues/2387) Error: invalid namespace xxx +* [#2389](https://github.com/derailed/k9s/issues/2389) Mixed-case named contexts cannot be switched to from contexts view +* [#2382](https://github.com/derailed/k9s/issues/2382) Header always shows Cluster from kubeconfig current-context + +--- + +## Contributed PRs + +Please be sure to give `Big Thanks!` and `ATTA Girls/Boys!` to all the fine contributors for making K9s better for all of us!! + +* [#2390](https://github.com/derailed/k9s/pull/2390) case sensitive for specific command args and flags + +--- + + © 2023 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0) diff --git a/internal/client/client.go b/internal/client/client.go index 577c3a3f..66bcf3fa 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -216,15 +216,59 @@ func (a *APIClient) IsValidNamespace(ns string) bool { if IsAllNamespace(ns) { return true } + + ok, err := a.CanI(ClusterScope, "v1/namespaces", []string{ListVerb}) + if !ok || err != nil { + cool, err := a.isValidNamespace(ns) + if err != nil { + log.Error().Err(err).Msgf("unable to assert valid namespace") + } + return cool + } nn, err := a.ValidNamespaceNames() if err != nil { return false } - _, ok := nn[ns] + _, ok = nn[ns] return ok } +func (a *APIClient) cachedNamespaceNames() NamespaceNames { + cns, ok := a.cache.Get("validNamespaces") + if !ok { + return make(NamespaceNames) + } + + return cns.(NamespaceNames) +} + +func (a *APIClient) isValidNamespace(n string) (bool, error) { + if a == nil { + return false, errors.New("invalid client") + } + + cnss := a.cachedNamespaceNames() + if _, ok := cnss[n]; ok { + return true, nil + } + + dial, err := a.Dial() + if err != nil { + return false, err + } + ctx, cancel := context.WithTimeout(context.Background(), a.config.CallTimeout()) + defer cancel() + _, err = dial.CoreV1().Namespaces().Get(ctx, n, metav1.GetOptions{}) + if err != nil { + return false, err + } + cnss[n] = struct{}{} + a.cache.Add("validNamespaces", cnss, cacheExpiry) + + return true, nil +} + // ValidNamespaceNames returns all available namespaces. func (a *APIClient) ValidNamespaceNames() (NamespaceNames, error) { if a == nil { diff --git a/internal/client/config.go b/internal/client/config.go index 76d51f4b..66990488 100644 --- a/internal/client/config.go +++ b/internal/client/config.go @@ -103,7 +103,7 @@ func (c *Config) CurrentClusterName() (string, error) { if isSet(c.flags.Context) { ct, ok = cfg.Contexts[*c.flags.Context] if !ok { - return "", fmt.Errorf("invalid context specified: %q", *c.flags.Context) + return "", fmt.Errorf("current-cluster - invalid context specified: %q", *c.flags.Context) } } @@ -156,7 +156,7 @@ func (c *Config) GetContext(n string) (*api.Context, error) { return c, nil } - return nil, fmt.Errorf("invalid context `%s specified", n) + return nil, fmt.Errorf("getcontext - invalid context specified: %q", n) } // Contexts fetch all available contexts. diff --git a/internal/client/config_test.go b/internal/client/config_test.go index f7a6f1a5..046e5dd6 100644 --- a/internal/client/config_test.go +++ b/internal/client/config_test.go @@ -154,7 +154,7 @@ func TestConfigGetContext(t *testing.T) { }, "custom": { cluster: "bozo", - err: errors.New("invalid context `bozo specified"), + err: errors.New(`getcontext - invalid context specified: "bozo"`), }, } diff --git a/internal/config/data/dir.go b/internal/config/data/dir.go index 6c957759..b8e5d88d 100644 --- a/internal/config/data/dir.go +++ b/internal/config/data/dir.go @@ -34,14 +34,9 @@ func (d Dir) Load(n string, ct *api.Context) (*Config, error) { } var ( - path = filepath.Join( - d.root, - SanitizeFileName(ct.Cluster), - SanitizeFileName(n), - MainConfigFile, - ) - cfg *Config - err error + path = filepath.Join(d.root, SanitizeContextSubpath(ct.Cluster, n), MainConfigFile) + cfg *Config + err error ) if f, e := os.Stat(path); os.IsNotExist(e) || f.Size() == 0 { log.Debug().Msgf("Context config not found! Generating... %q", path) diff --git a/internal/config/data/helpers_test.go b/internal/config/data/helpers_test.go index be4a6a85..ed82e458 100644 --- a/internal/config/data/helpers_test.go +++ b/internal/config/data/helpers_test.go @@ -12,6 +12,37 @@ import ( "github.com/stretchr/testify/assert" ) +func TestSanitizeFileName(t *testing.T) { + uu := map[string]struct { + file, e string + }{ + "empty": {}, + "plain": { + file: "bumble-bee-tuna", + e: "bumble-bee-tuna", + }, + "slash": { + file: "bumble/bee/tuna", + e: "bumble-bee-tuna", + }, + "column": { + file: "bumble::bee:tuna", + e: "bumble-bee-tuna", + }, + "eks": { + file: "arn:aws:eks:us-east-1:123456789:cluster/us-east-1-app-dev-common-eks", + e: "arn-aws-eks-us-east-1-123456789-cluster-us-east-1-app-dev-common-eks", + }, + } + + for k := range uu { + u := uu[k] + t.Run(k, func(t *testing.T) { + assert.Equal(t, u.e, data.SanitizeFileName(u.file)) + }) + } +} + func TestHelperInList(t *testing.T) { uu := []struct { item string diff --git a/internal/config/k9s.go b/internal/config/k9s.go index 18e1b2da..fd8bdae6 100644 --- a/internal/config/k9s.go +++ b/internal/config/k9s.go @@ -61,8 +61,7 @@ func (k *K9s) Save() error { if k.activeConfig != nil { path := filepath.Join( AppContextsDir, - k.activeConfig.Context.ClusterName, - k.activeContextName, + data.SanitizeContextSubpath(k.activeConfig.Context.ClusterName, k.activeContextName), data.MainConfigFile, ) return k.activeConfig.Save(path) diff --git a/internal/view/app.go b/internal/view/app.go index 9cbf742d..bbba78a2 100644 --- a/internal/view/app.go +++ b/internal/view/app.go @@ -100,7 +100,7 @@ func (a *App) Init(version string, rate int) error { a.factory = watch.NewFactory(a.Conn()) ok, err := a.isValidNS(ns) if !ok && err == nil { - return fmt.Errorf("invalid namespace %s", ns) + return fmt.Errorf("app-init - invalid namespace: %q", ns) } a.initFactory(ns) @@ -415,7 +415,7 @@ func (a *App) switchNS(ns string) error { return err } if !ok { - return fmt.Errorf("invalid namespace %q", ns) + return fmt.Errorf("switchns - invalid namespace: %q", ns) } if err := a.Config.SetActiveNamespace(ns); err != nil { return err @@ -433,7 +433,7 @@ func (a *App) isValidNS(ns string) (bool, error) { } if !a.Conn().IsValidNamespace(ns) { - return false, fmt.Errorf("invalid namespace: %q", ns) + return false, fmt.Errorf("isvalidns - invalid namespace: %q", ns) } return true, nil diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index b612e4d7..342a0a8e 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -1,6 +1,6 @@ name: k9s base: core20 -version: 'v0.30.3' +version: 'v0.30.4' summary: K9s is a CLI to view and manage your Kubernetes clusters. 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.