parent
6881892433
commit
7603f27c9a
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.40.0
|
VERSION ?= v0.40.1
|
||||||
IMG_NAME := derailed/k9s
|
IMG_NAME := derailed/k9s
|
||||||
IMAGE := ${IMG_NAME}:${VERSION}
|
IMAGE := ${IMG_NAME}:${VERSION}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
<img src="https://raw.githubusercontent.com/derailed/k9s/master/assets/k9s.png" align="center" width="800" height="auto"/>
|
||||||
|
|
||||||
|
# Release v0.40.1
|
||||||
|
|
||||||
|
## 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!
|
||||||
|
|
||||||
|
😳 Aye! Buzz kill on the 0.40.0 aftermath... 🙀 👻
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Videos Are In The Can!
|
||||||
|
|
||||||
|
Please dial [K9s Channel](https://www.youtube.com/channel/UC897uwPygni4QIjkPCpgjmw) for up coming content...
|
||||||
|
|
||||||
|
* [K9s v0.40.0 <Column Blow> Sneak peek](https://youtu.be/iy6RDozAM4A)
|
||||||
|
* [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
|
||||||
|
|
||||||
|
* [#3113](https://github.com/derailed/k9s/issues/3113) 0.40.0 can't retain temporary view sort
|
||||||
|
* [#3111](https://github.com/derailed/k9s/issues/3111) k9s can't describe or print YAML for HPAs in all namespaces view
|
||||||
|
* [#2966](https://github.com/derailed/k9s/issues/2966) Go to the Contexts page and filter, contexts that are matched will be filtered ou
|
||||||
|
* [#2962](https://github.com/derailed/k9s/issues/2962) Small colour/filtering related bug
|
||||||
|
* [#2961](https://github.com/derailed/k9s/issues/2961) Drain node with the -disable-eviction
|
||||||
|
* [#2958](https://github.com/derailed/k9s/issues/2958) Restart count in container view associated with the wrong container
|
||||||
|
* [#2945](https://github.com/derailed/k9s/issues/2945) Could we add ServiceAccount Column in v1/POD view
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 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!!
|
||||||
|
|
||||||
|
* [#3094](https://github.com/derailed/k9s/pull/3094) Log in as root to the node.
|
||||||
|
* [#3033](https://github.com/derailed/k9s/pull/3033) Skip cache invalidation on failed connection
|
||||||
|
* [#2965](https://github.com/derailed/k9s/pull/2965) Make menu foreground style configurable through skins
|
||||||
|
* [#2952](https://github.com/derailed/k9s/pull/2952) A modest attempt to improve the logo aesthetics
|
||||||
|
* [#2833](https://github.com/derailed/k9s/pull/2833) allow scaling custom resource
|
||||||
|
* [#2799](https://github.com/derailed/k9s/pull/2799) feat(app): add history navigation with [ and ], most recent command with -
|
||||||
|
* [#2719](https://github.com/derailed/k9s/pull/2719) fix: stop table header cells from being selectable
|
||||||
|
* [#2865](https://github.com/derailed/k9s/pull/2865) Feature/DisableAutoscroll
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<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)
|
||||||
|
|
@ -4,7 +4,6 @@ package dao
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
|
@ -24,13 +23,30 @@ type Dynamic struct {
|
||||||
Generic
|
Generic
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get returns a given resource as a table object.
|
||||||
func (d *Dynamic) Get(ctx context.Context, path string) (runtime.Object, error) {
|
func (d *Dynamic) Get(ctx context.Context, path string) (runtime.Object, error) {
|
||||||
return nil, errors.New("Not implemented")
|
oo, err := d.toTable(ctx, path)
|
||||||
|
if err != nil || len(oo) == 0 {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return oo[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// List returns a collection of resources as one or more table objects.
|
||||||
func (d *Dynamic) List(ctx context.Context, ns string) ([]runtime.Object, error) {
|
func (d *Dynamic) List(ctx context.Context, ns string) ([]runtime.Object, error) {
|
||||||
|
return d.toTable(ctx, ns)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dynamic) toTable(ctx context.Context, fqn string) ([]runtime.Object, error) {
|
||||||
strLabel, _ := ctx.Value(internal.KeyLabels).(string)
|
strLabel, _ := ctx.Value(internal.KeyLabels).(string)
|
||||||
|
|
||||||
|
opts := []string{d.gvr.R()}
|
||||||
|
ns, n := client.Namespaced(fqn)
|
||||||
|
if n != "" {
|
||||||
|
opts = append(opts, n)
|
||||||
|
}
|
||||||
|
|
||||||
allNS := client.IsAllNamespaces(ns)
|
allNS := client.IsAllNamespaces(ns)
|
||||||
flags := cmdutil.NewMatchVersionFlags(d.getFactory().Client().Config().Flags())
|
flags := cmdutil.NewMatchVersionFlags(d.getFactory().Client().Config().Flags())
|
||||||
f := cmdutil.NewFactory(flags)
|
f := cmdutil.NewFactory(flags)
|
||||||
|
|
@ -40,7 +56,7 @@ func (d *Dynamic) List(ctx context.Context, ns string) ([]runtime.Object, error)
|
||||||
LabelSelectorParam(strLabel).
|
LabelSelectorParam(strLabel).
|
||||||
FieldSelectorParam("").
|
FieldSelectorParam("").
|
||||||
RequestChunksOf(0).
|
RequestChunksOf(0).
|
||||||
ResourceTypeOrNameArgs(true, d.gvr.R()).
|
ResourceTypeOrNameArgs(true, opts...).
|
||||||
ContinueOnError().
|
ContinueOnError().
|
||||||
Latest().
|
Latest().
|
||||||
Flatten().
|
Flatten().
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/derailed/k9s/internal/client"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
@ -17,8 +18,7 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
"github.com/derailed/k9s/internal/client"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -32,19 +32,19 @@ const (
|
||||||
// MetaAccess tracks resources metadata.
|
// MetaAccess tracks resources metadata.
|
||||||
var MetaAccess = NewMeta()
|
var MetaAccess = NewMeta()
|
||||||
|
|
||||||
var stdGroups = map[string]struct{}{
|
var stdGroups = sets.New[string](
|
||||||
"apps/v1": {},
|
"apps/v1",
|
||||||
"autoscaling/v1": {},
|
"autoscaling/v1",
|
||||||
"autoscaling/v2": {},
|
"autoscaling/v2",
|
||||||
"autoscaling/v2beta1": {},
|
"autoscaling/v2beta1",
|
||||||
"autoscaling/v2beta2": {},
|
"autoscaling/v2beta2",
|
||||||
"batch/v1": {},
|
"batch/v1",
|
||||||
"batch/v1beta1": {},
|
"batch/v1beta1",
|
||||||
"extensions/v1beta1": {},
|
"extensions/v1beta1",
|
||||||
"policy/v1beta1": {},
|
"policy/v1beta1",
|
||||||
"policy/v1": {},
|
"policy/v1",
|
||||||
"v1": {},
|
"v1",
|
||||||
}
|
)
|
||||||
|
|
||||||
func (m ResourceMetas) clear() {
|
func (m ResourceMetas) clear() {
|
||||||
for k := range m {
|
for k := range m {
|
||||||
|
|
@ -381,20 +381,15 @@ func loadPreferred(f Factory, m ResourceMetas) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func isStandardGroup(gv string) bool {
|
func isStandardGroup(gv string) bool {
|
||||||
if _, ok := stdGroups[gv]; ok {
|
return stdGroups.Has(gv) || strings.Contains(gv, "k8s.io")
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return strings.Contains(gv, "k8s.io")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var deprecatedGVRs = map[client.GVR]struct{}{
|
var deprecatedGVRs = sets.New[client.GVR](
|
||||||
client.NewGVR("extensions/v1beta1/ingresses"): {},
|
client.NewGVR("extensions/v1beta1/ingresses"),
|
||||||
}
|
)
|
||||||
|
|
||||||
func isDeprecated(gvr client.GVR) bool {
|
func isDeprecated(gvr client.GVR) bool {
|
||||||
_, ok := deprecatedGVRs[gvr]
|
return deprecatedGVRs.Has(gvr)
|
||||||
return ok
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadCRDs Wait for the cache to synced and then add some additional properties to CRD.
|
// loadCRDs Wait for the cache to synced and then add some additional properties to CRD.
|
||||||
|
|
|
||||||
|
|
@ -84,9 +84,9 @@ var Registry = map[string]ResourceMeta{
|
||||||
},
|
},
|
||||||
|
|
||||||
// Core...
|
// Core...
|
||||||
// "v1/endpoints": {
|
"v1/endpoints": {
|
||||||
// Renderer: &render.Endpoints{},
|
Renderer: &render.Endpoints{},
|
||||||
// },
|
},
|
||||||
"v1/pods": {
|
"v1/pods": {
|
||||||
DAO: &dao.Pod{},
|
DAO: &dao.Pod{},
|
||||||
Renderer: render.NewPod(),
|
Renderer: render.NewPod(),
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,10 @@ import (
|
||||||
"k8s.io/client-go/util/jsonpath"
|
"k8s.io/client-go/util/jsonpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ColsSpecs represents a collection of column specification ie NAME:spec|flags.
|
||||||
type ColsSpecs []string
|
type ColsSpecs []string
|
||||||
|
|
||||||
|
// NewColsSpecs returns a new instance.
|
||||||
func NewColsSpecs(cols ...string) ColsSpecs {
|
func NewColsSpecs(cols ...string) ColsSpecs {
|
||||||
return ColsSpecs(cols)
|
return ColsSpecs(cols)
|
||||||
}
|
}
|
||||||
|
|
@ -40,6 +42,7 @@ func (cc ColsSpecs) parseSpecs() (ColumnSpecs, error) {
|
||||||
return specs, nil
|
return specs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RenderedCols tracks a collection of column header and cust column parse expression.
|
||||||
type RenderedCols []RenderedCol
|
type RenderedCols []RenderedCol
|
||||||
|
|
||||||
func (rr RenderedCols) hydrateRow(row *model1.Row) {
|
func (rr RenderedCols) hydrateRow(row *model1.Row) {
|
||||||
|
|
@ -50,6 +53,7 @@ func (rr RenderedCols) hydrateRow(row *model1.Row) {
|
||||||
row.Fields = ff
|
row.Fields = ff
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HasHeader checks if a given header is present in the collection.
|
||||||
func (rr RenderedCols) HasHeader(n string) bool {
|
func (rr RenderedCols) HasHeader(n string) bool {
|
||||||
for _, r := range rr {
|
for _, r := range rr {
|
||||||
if r.has(n) {
|
if r.has(n) {
|
||||||
|
|
@ -60,26 +64,31 @@ func (rr RenderedCols) HasHeader(n string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RenderedCol represents a column header and a column spec.
|
||||||
type RenderedCol struct {
|
type RenderedCol struct {
|
||||||
Header model1.HeaderColumn
|
Header model1.HeaderColumn
|
||||||
Value string
|
Value string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Has checks if the header column match the given name.
|
||||||
func (r RenderedCol) has(n string) bool {
|
func (r RenderedCol) has(n string) bool {
|
||||||
return r.Header.Name == n
|
return r.Header.Name == n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ColumnSpec tracks a header column and an options cust column spec.
|
||||||
type ColumnSpec struct {
|
type ColumnSpec struct {
|
||||||
Header model1.HeaderColumn
|
Header model1.HeaderColumn
|
||||||
Spec string
|
Spec string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ColumnSpecs tracks a collection of column specs.
|
||||||
type ColumnSpecs []ColumnSpec
|
type ColumnSpecs []ColumnSpec
|
||||||
|
|
||||||
func (c ColumnSpecs) isEmpty() bool {
|
func (c ColumnSpecs) isEmpty() bool {
|
||||||
return len(c) == 0
|
return len(c) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Header builds a new header that is a super set of custom and/or default header.
|
||||||
func (cc ColumnSpecs) Header(rh model1.Header) model1.Header {
|
func (cc ColumnSpecs) Header(rh model1.Header) model1.Header {
|
||||||
hh := make(model1.Header, 0, len(cc))
|
hh := make(model1.Header, 0, len(cc))
|
||||||
for _, h := range cc {
|
for _, h := range cc {
|
||||||
|
|
|
||||||
|
|
@ -92,18 +92,26 @@ func (t *Table) Render(o any, ns string, r *model1.Row) error {
|
||||||
func (t *Table) defaultRow(row *metav1.TableRow, ns string, r *model1.Row) error {
|
func (t *Table) defaultRow(row *metav1.TableRow, ns string, r *model1.Row) error {
|
||||||
th := t.defaultHeader()
|
th := t.defaultHeader()
|
||||||
ons, name := ns, UnknownValue
|
ons, name := ns, UnknownValue
|
||||||
if row.Object.Object != nil {
|
switch {
|
||||||
m, _ := meta.Accessor(row.Object.Object)
|
case row.Object.Object != nil:
|
||||||
if m != nil {
|
if m, _ := meta.Accessor(row.Object.Object); m != nil {
|
||||||
ons, name = m.GetNamespace(), m.GetName()
|
ons, name = m.GetNamespace(), m.GetName()
|
||||||
}
|
}
|
||||||
} else if idx, ok := th.IndexOf("NAME", true); ok && idx >= 0 {
|
case row.Object.Raw != nil:
|
||||||
name = row.Cells[idx].(string)
|
var pm metav1.PartialObjectMetadata
|
||||||
if idx, ok := th.IndexOf("NAMESPACE", true); ok && idx >= 0 {
|
if err := json.Unmarshal(row.Object.Raw, &pm); err != nil {
|
||||||
ons = row.Cells[idx].(string)
|
return err
|
||||||
|
}
|
||||||
|
ons, name = pm.Namespace, pm.Name
|
||||||
|
default:
|
||||||
|
if idx, ok := th.IndexOf("NAME", true); ok && idx >= 0 {
|
||||||
|
name = row.Cells[idx].(string)
|
||||||
|
if idx, ok := th.IndexOf("NAMESPACE", true); ok && idx >= 0 {
|
||||||
|
ons = row.Cells[idx].(string)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if client.IsClusterWide(ons) {
|
if client.IsClusterWide(ons) {
|
||||||
ons = client.ClusterScope
|
ons = client.ClusterScope
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -157,9 +157,12 @@ func (t *Table) GVR() client.GVR { return t.gvr }
|
||||||
func (t *Table) ViewSettingsChanged(vs *config.ViewSetting) {
|
func (t *Table) ViewSettingsChanged(vs *config.ViewSetting) {
|
||||||
if t.setViewSetting(vs) {
|
if t.setViewSetting(vs) {
|
||||||
if vs == nil {
|
if vs == nil {
|
||||||
t.setSortCol(model1.SortColumn{})
|
if !t.getMSort() {
|
||||||
|
t.setSortCol(model1.SortColumn{})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t.setMSort(false)
|
||||||
}
|
}
|
||||||
t.setMSort(false)
|
|
||||||
t.Refresh()
|
t.Refresh()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
name: k9s
|
name: k9s
|
||||||
base: core22
|
base: core22
|
||||||
version: 'v0.40.0'
|
version: 'v0.40.1'
|
||||||
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