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 <emanuele@ciurleo.com>mine
parent
27cc859e68
commit
34da44b441
2
Makefile
2
Makefile
|
|
@ -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.30.3
|
VERSION ?= v0.30.4
|
||||||
IMG_NAME := derailed/k9s
|
IMG_NAME := derailed/k9s
|
||||||
IMAGE := ${IMG_NAME}:${VERSION}
|
IMAGE := ${IMG_NAME}:${VERSION}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
<img src="https://raw.githubusercontent.com/derailed/k9s/master/assets/k9s-xmas.png" align="center" width="800" height="auto"/>
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<img src="https://raw.githubusercontent.com/derailed/k9s/master/assets/imhotep_logo.png" width="32" height="auto"/> © 2023 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
|
@ -216,15 +216,59 @@ func (a *APIClient) IsValidNamespace(ns string) bool {
|
||||||
if IsAllNamespace(ns) {
|
if IsAllNamespace(ns) {
|
||||||
return true
|
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()
|
nn, err := a.ValidNamespaceNames()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
_, ok := nn[ns]
|
_, ok = nn[ns]
|
||||||
|
|
||||||
return ok
|
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.
|
// ValidNamespaceNames returns all available namespaces.
|
||||||
func (a *APIClient) ValidNamespaceNames() (NamespaceNames, error) {
|
func (a *APIClient) ValidNamespaceNames() (NamespaceNames, error) {
|
||||||
if a == nil {
|
if a == nil {
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ func (c *Config) CurrentClusterName() (string, error) {
|
||||||
if isSet(c.flags.Context) {
|
if isSet(c.flags.Context) {
|
||||||
ct, ok = cfg.Contexts[*c.flags.Context]
|
ct, ok = cfg.Contexts[*c.flags.Context]
|
||||||
if !ok {
|
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 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.
|
// Contexts fetch all available contexts.
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,7 @@ func TestConfigGetContext(t *testing.T) {
|
||||||
},
|
},
|
||||||
"custom": {
|
"custom": {
|
||||||
cluster: "bozo",
|
cluster: "bozo",
|
||||||
err: errors.New("invalid context `bozo specified"),
|
err: errors.New(`getcontext - invalid context specified: "bozo"`),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,12 +34,7 @@ func (d Dir) Load(n string, ct *api.Context) (*Config, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
path = filepath.Join(
|
path = filepath.Join(d.root, SanitizeContextSubpath(ct.Cluster, n), MainConfigFile)
|
||||||
d.root,
|
|
||||||
SanitizeFileName(ct.Cluster),
|
|
||||||
SanitizeFileName(n),
|
|
||||||
MainConfigFile,
|
|
||||||
)
|
|
||||||
cfg *Config
|
cfg *Config
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,37 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"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) {
|
func TestHelperInList(t *testing.T) {
|
||||||
uu := []struct {
|
uu := []struct {
|
||||||
item string
|
item string
|
||||||
|
|
|
||||||
|
|
@ -61,8 +61,7 @@ func (k *K9s) Save() error {
|
||||||
if k.activeConfig != nil {
|
if k.activeConfig != nil {
|
||||||
path := filepath.Join(
|
path := filepath.Join(
|
||||||
AppContextsDir,
|
AppContextsDir,
|
||||||
k.activeConfig.Context.ClusterName,
|
data.SanitizeContextSubpath(k.activeConfig.Context.ClusterName, k.activeContextName),
|
||||||
k.activeContextName,
|
|
||||||
data.MainConfigFile,
|
data.MainConfigFile,
|
||||||
)
|
)
|
||||||
return k.activeConfig.Save(path)
|
return k.activeConfig.Save(path)
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@ func (a *App) Init(version string, rate int) error {
|
||||||
a.factory = watch.NewFactory(a.Conn())
|
a.factory = watch.NewFactory(a.Conn())
|
||||||
ok, err := a.isValidNS(ns)
|
ok, err := a.isValidNS(ns)
|
||||||
if !ok && err == nil {
|
if !ok && err == nil {
|
||||||
return fmt.Errorf("invalid namespace %s", ns)
|
return fmt.Errorf("app-init - invalid namespace: %q", ns)
|
||||||
}
|
}
|
||||||
a.initFactory(ns)
|
a.initFactory(ns)
|
||||||
|
|
||||||
|
|
@ -415,7 +415,7 @@ func (a *App) switchNS(ns string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !ok {
|
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 {
|
if err := a.Config.SetActiveNamespace(ns); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -433,7 +433,7 @@ func (a *App) isValidNS(ns string) (bool, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !a.Conn().IsValidNamespace(ns) {
|
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
|
return true, nil
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
name: k9s
|
name: k9s
|
||||||
base: core20
|
base: core20
|
||||||
version: 'v0.30.3'
|
version: 'v0.30.4'
|
||||||
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.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue