Skip to content

Commit

Permalink
K9s release v0.32.2 (#2598)
Browse files Browse the repository at this point in the history
* [Maint] cleaning up

* [Bug] Fix #2593

* [Bug] Fix #2582

* Release v0.32.2
  • Loading branch information
derailed authored Mar 6, 2024
1 parent 69cd0cd commit ecd33ff
Show file tree
Hide file tree
Showing 18 changed files with 105 additions and 70 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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.32.1
VERSION ?= v0.32.2
IMG_NAME := derailed/k9s
IMAGE := ${IMG_NAME}:${VERSION}

Expand Down
43 changes: 43 additions & 0 deletions change_logs/release_v0.32.2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<img src="https://raw.githubusercontent.com/derailed/k9s/master/assets/k9s.png" align="center" width="800" height="auto"/>

# Release v0.32.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!

Mo aftermath ;(

---

## 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

* [#2582](https://github.com/derailed/k9s/issues/2582) Slowness due to client-side throttling in v0.32.0 (Maybe??)
* [#2593](https://github.com/derailed/k9s/issues/2593) Popeye not working in 0.32.X

---

<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)
15 changes: 14 additions & 1 deletion internal/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ func (a *APIClient) ValidNamespaceNames() (NamespaceNames, error) {
}
}

ok, err := a.CanI(ClusterScope, "v1/namespaces", "", []string{ListVerb})
ok, err := a.CanI(ClusterScope, "v1/namespaces", "", ListAccess)
if !ok || err != nil {
return nil, fmt.Errorf("user not authorized to list all namespaces")
}
Expand Down Expand Up @@ -524,12 +524,25 @@ func (a *APIClient) MXDial() (*versioned.Clientset, error) {
return a.getMxsClient(), err
}

func (a *APIClient) invalidateCache() error {
dial, err := a.CachedDiscovery()
if err != nil {
return err
}
dial.Invalidate()

return nil
}

// SwitchContext handles kubeconfig context switches.
func (a *APIClient) SwitchContext(name string) error {
log.Debug().Msgf("Switching context %q", name)
if err := a.config.SwitchContext(name); err != nil {
return err
}
if err := a.invalidateCache(); err != nil {
return err
}
a.reset()
ResetMetrics()

Expand Down
3 changes: 3 additions & 0 deletions internal/client/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ const (
)

var (
// PatchAccess patch a resource.
PatchAccess = []string{PatchVerb}

// GetAccess reads a resource.
GetAccess = []string{GetVerb}

Expand Down
3 changes: 2 additions & 1 deletion internal/config/alias.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,8 @@ func (a *Aliases) loadDefaultAliases() {
a.declare("help", "h", "?")
a.declare("quit", "q", "q!", "qa", "Q")
a.declare("aliases", "alias", "a")
a.declare("popeye", "pop")
// !!BOZO!!
// a.declare("popeye", "pop")
a.declare("helm", "charts", "chart", "hm")
a.declare("dir", "d")
a.declare("contexts", "context", "ctx")
Expand Down
7 changes: 4 additions & 3 deletions internal/config/alias_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package config_test
import (
"fmt"
"os"
"path"
"slices"
"testing"

Expand Down Expand Up @@ -109,8 +110,8 @@ func TestAliasesLoad(t *testing.T) {
config.AppConfigDir = "testdata/aliases"
a := config.NewAliases()

assert.Nil(t, a.Load("testdata/aliases/plain.yaml"))
assert.Equal(t, 56, len(a.Alias))
assert.Nil(t, a.Load(path.Join(config.AppConfigDir, "plain.yaml")))
assert.Equal(t, 54, len(a.Alias))
}

func TestAliasesSave(t *testing.T) {
Expand All @@ -123,7 +124,7 @@ func TestAliasesSave(t *testing.T) {

assert.Equal(t, c, len(a.Alias))
assert.Nil(t, a.Save())
assert.Nil(t, a.LoadFile("/tmp/test-aliases/aliases.yaml"))
assert.Nil(t, a.LoadFile(config.AppAliasesFile))
assert.Equal(t, c, len(a.Alias))
}

Expand Down
4 changes: 2 additions & 2 deletions internal/config/testdata/aliases/plain.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
aliases:
dp: "apps.v1.deployments"
pe: ".v1.pods"
dp: "apps/v1/deployments"
pe: "v1/pods"
4 changes: 2 additions & 2 deletions internal/dao/dp.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func (d *Deployment) Restart(ctx context.Context, path string) error {
return err
}

auth, err := d.Client().CanI(dp.Namespace, "apps/v1/deployments", dp.Name, []string{client.PatchVerb})
auth, err := d.Client().CanI(dp.Namespace, "apps/v1/deployments", dp.Name, client.PatchAccess)
if err != nil {
return err
}
Expand Down Expand Up @@ -261,7 +261,7 @@ func (d *Deployment) GetPodSpec(path string) (*v1.PodSpec, error) {
// SetImages sets container images.
func (d *Deployment) SetImages(ctx context.Context, path string, imageSpecs ImageSpecs) error {
ns, n := client.Namespaced(path)
auth, err := d.Client().CanI(ns, "apps/v1/deployments", n, []string{client.PatchVerb})
auth, err := d.Client().CanI(ns, "apps/v1/deployments", n, client.PatchAccess)
if err != nil {
return err
}
Expand Down
4 changes: 2 additions & 2 deletions internal/dao/ds.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func (d *DaemonSet) Restart(ctx context.Context, path string) error {
return err
}

auth, err := d.Client().CanI(ds.Namespace, "apps/v1/daemonsets", ds.Name, []string{client.PatchVerb})
auth, err := d.Client().CanI(ds.Namespace, "apps/v1/daemonsets", ds.Name, client.PatchAccess)
if err != nil {
return err
}
Expand Down Expand Up @@ -280,7 +280,7 @@ func (d *DaemonSet) GetPodSpec(path string) (*v1.PodSpec, error) {
// SetImages sets container images.
func (d *DaemonSet) SetImages(ctx context.Context, path string, imageSpecs ImageSpecs) error {
ns, n := client.Namespaced(path)
auth, err := d.Client().CanI(ns, "apps/v1/daemonset", n, []string{client.PatchVerb})
auth, err := d.Client().CanI(ns, "apps/v1/daemonset", n, client.PatchAccess)
if err != nil {
return err
}
Expand Down
4 changes: 2 additions & 2 deletions internal/dao/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ func (n *Node) ensureCordoned(path string) (bool, error) {
// FetchNode retrieves a node.
func FetchNode(ctx context.Context, f Factory, path string) (*v1.Node, error) {
_, n := client.Namespaced(path)
auth, err := f.Client().CanI(client.ClusterScope, "v1/nodes", n, []string{"get"})
auth, err := f.Client().CanI(client.ClusterScope, "v1/nodes", n, client.GetAccess)
if err != nil {
return nil, err
}
Expand All @@ -272,7 +272,7 @@ func FetchNode(ctx context.Context, f Factory, path string) (*v1.Node, error) {

// FetchNodes retrieves all nodes.
func FetchNodes(ctx context.Context, f Factory, labelsSel string) (*v1.NodeList, error) {
auth, err := f.Client().CanI(client.ClusterScope, "v1/nodes", "", []string{client.ListVerb})
auth, err := f.Client().CanI(client.ClusterScope, "v1/nodes", "", client.ListAccess)
if err != nil {
return nil, err
}
Expand Down
4 changes: 2 additions & 2 deletions internal/dao/pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ func (p *Pod) List(ctx context.Context, ns string) ([]runtime.Object, error) {
// Logs fetch container logs for a given pod and container.
func (p *Pod) Logs(path string, opts *v1.PodLogOptions) (*restclient.Request, error) {
ns, n := client.Namespaced(path)
auth, err := p.Client().CanI(ns, "v1/pods:log", n, []string{client.GetVerb})
auth, err := p.Client().CanI(ns, "v1/pods:log", n, client.GetAccess)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -426,7 +426,7 @@ func (p *Pod) GetPodSpec(path string) (*v1.PodSpec, error) {
// SetImages sets container images.
func (p *Pod) SetImages(ctx context.Context, path string, imageSpecs ImageSpecs) error {
ns, n := client.Namespaced(path)
auth, err := p.Client().CanI(ns, "v1/pod", n, []string{client.PatchVerb})
auth, err := p.Client().CanI(ns, "v1/pod", n, client.PatchAccess)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion internal/dao/port_forwarder.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ func (p *PortForwarder) Start(path string, tt port.PortTunnel) (*portforward.Por
p.path, p.tunnel, p.age = path, tt, time.Now()

ns, n := client.Namespaced(path)
auth, err := p.Client().CanI(ns, "v1/pods", n, []string{client.GetVerb})
auth, err := p.Client().CanI(ns, "v1/pods", n, client.GetAccess)
if err != nil {
return nil, err
}
Expand Down
66 changes: 18 additions & 48 deletions internal/dao/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,50 +21,24 @@ const (
crdCat = "crd"
k9sCat = "k9s"
helmCat = "helm"
crdGVR = "apiextensions.k8s.io/v1/customresourcedefinitions"
)

// MetaAccess tracks resources metadata.
var MetaAccess = NewMeta()

var stdGroups = []string{
"admissionregistration.k8s.io/v1",
"admissionregistration.k8s.io/v1beta1",
"apiextensions.k8s.io/v1",
"apiextensions.k8s.io/v1beta1",
"apiregistration.k8s.io/v1",
"apiregistration.k8s.io/v1beta1",
"apps/v1",
"authentication.k8s.io/v1",
"authentication.k8s.io/v1beta1",
"authorization.k8s.io/v1",
"authorization.k8s.io/v1beta1",
"autoscaling/v1",
"autoscaling/v2beta1",
"autoscaling/v2beta2",
"batch/v1",
"batch/v1beta1",
"certificates.k8s.io/v1",
"certificates.k8s.io/v1beta1",
"coordination.k8s.io/v1",
"coordination.k8s.io/v1beta1",
"discovery.k8s.io/v1beta1",
"dynatrace.com/v1alpha1",
"events.k8s.io/v1",
"extensions/v1beta1",
"flowcontrol.apiserver.k8s.io/v1beta1",
"metrics.k8s.io/v1beta1",
"networking.k8s.io/v1",
"networking.k8s.io/v1beta1",
"node.k8s.io/v1",
"node.k8s.io/v1beta1",
"policy/v1beta1",
"rbac.authorization.k8s.io/v1",
"rbac.authorization.k8s.io/v1beta1",
"scheduling.k8s.io/v1",
"scheduling.k8s.io/v1beta1",
"storage.k8s.io/v1",
"storage.k8s.io/v1beta1",
"v1",
var stdGroups = map[string]struct{}{
"apps/v1": {},
"autoscaling/v1": {},
"autoscaling/v2": {},
"autoscaling/v2beta1": {},
"autoscaling/v2beta2": {},
"batch/v1": {},
"batch/v1beta1": {},
"extensions/v1beta1": {},
"policy/v1beta1": {},
"policy/v1": {},
"v1": {},
}

func (m ResourceMetas) clear() {
Expand Down Expand Up @@ -372,7 +346,6 @@ func loadPreferred(f Factory, m ResourceMetas) error {
if err != nil {
return err
}
dial.Invalidate()
rr, err := dial.ServerPreferredResources()
if err != nil {
log.Debug().Err(err).Msgf("Failed to load preferred resources")
Expand All @@ -387,7 +360,7 @@ func loadPreferred(f Factory, m ResourceMetas) error {
if res.SingularName == "" {
res.SingularName = strings.ToLower(res.Kind)
}
if !isStandardGroup(res.Group) {
if !isStandardGroup(r.GroupVersion) {
res.Categories = append(res.Categories, crdCat)
}
m[gvr] = res
Expand All @@ -397,14 +370,12 @@ func loadPreferred(f Factory, m ResourceMetas) error {
return nil
}

func isStandardGroup(r string) bool {
for _, res := range stdGroups {
if strings.Index(res, r) == 0 {
return true
}
func isStandardGroup(gv string) bool {
if _, ok := stdGroups[gv]; ok {
return true
}

return false
return strings.Contains(gv, "k8s.io")
}

var deprecatedGVRs = map[client.GVR]struct{}{
Expand All @@ -420,7 +391,6 @@ func loadCRDs(f Factory, m ResourceMetas) {
if f.Client() == nil || !f.Client().ConnectionOK() {
return
}
const crdGVR = "apiextensions.k8s.io/v1/customresourcedefinitions"
oo, err := f.List(crdGVR, client.ClusterScope, false, labels.Everything())
if err != nil {
log.Warn().Err(err).Msgf("Fail CRDs load")
Expand Down
4 changes: 2 additions & 2 deletions internal/dao/sts.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ func (s *StatefulSet) Restart(ctx context.Context, path string) error {
s.Forwarders().Kill(client.FQN(p.Namespace, p.Name))
}

auth, err := s.Client().CanI(sts.Namespace, "apps/v1/statefulsets", n, []string{client.PatchVerb})
auth, err := s.Client().CanI(sts.Namespace, "apps/v1/statefulsets", n, client.PatchAccess)
if err != nil {
return err
}
Expand Down Expand Up @@ -291,7 +291,7 @@ func (s *StatefulSet) GetPodSpec(path string) (*v1.PodSpec, error) {
// SetImages sets container images.
func (s *StatefulSet) SetImages(ctx context.Context, path string, imageSpecs ImageSpecs) error {
ns, n := client.Namespaced(path)
auth, err := s.Client().CanI(ns, "apps/v1/statefulset", n, []string{client.PatchVerb})
auth, err := s.Client().CanI(ns, "apps/v1/statefulset", n, client.PatchAccess)
if err != nil {
return err
}
Expand Down
4 changes: 4 additions & 0 deletions internal/model/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,10 @@ func (t *Table) updater(ctx context.Context) {
}

func (t *Table) refresh(ctx context.Context) error {
defer func(ti time.Time) {
log.Trace().Msgf("Refresh [%s](%d) %s ", t.gvr, t.data.RowCount(), time.Since(ti))
}(time.Now())

if !atomic.CompareAndSwapInt32(&t.inUpdate, 0, 1) {
log.Debug().Msgf("Dropping update...")
return nil
Expand Down
2 changes: 1 addition & 1 deletion internal/model1/table_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,6 @@ func (t *TableData) Reset(ns string) {

func (t *TableData) Reconcile(ctx context.Context, r Renderer, oo []runtime.Object) error {
var rows Rows

if len(oo) > 0 {
if r.IsGeneric() {
table, ok := oo[0].(*metav1.Table)
Expand Down Expand Up @@ -399,6 +398,7 @@ func (t *TableData) Clone() *TableData {
header: t.header.Clone(),
rowEvents: t.rowEvents.Clone(),
namespace: t.namespace,
gvr: t.gvr,
}
}

Expand Down
2 changes: 1 addition & 1 deletion internal/view/browser.go
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ func editRes(app *App, gvr client.GVR, path string) error {
if gvr.String() == "v1/namespaces" {
ns = n
}
if ok, err := app.Conn().CanI(ns, gvr.String(), n, []string{"patch"}); !ok || err != nil {
if ok, err := app.Conn().CanI(ns, gvr.String(), n, client.PatchAccess); !ok || err != nil {
return fmt.Errorf("current user can't edit resource %s", gvr)
}

Expand Down
2 changes: 1 addition & 1 deletion snap/snapcraft.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: k9s
base: core20
version: 'v0.32.1'
version: 'v0.32.2'
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.
Expand Down

0 comments on commit ecd33ff

Please sign in to comment.