Fix lint build (#3066)

* clean up

* fix bug computing resource limits

* update rs rendering to match kubectl

* display ctx view if all hell fails

* clean ups and refactors

* fix linter issues
mine
Fernand Galiana 2025-01-19 09:47:29 -07:00 committed by GitHub
parent 4642077975
commit d72467a582
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 58 additions and 44 deletions

View File

@ -1088,12 +1088,12 @@ to make this project a reality!
## Meet The Core Team!
If you have chops in GO and K8s and would like to offer your time to help maintain and enhance this project, please reach out to me.
* [Fernand Galiana](https://github.com/derailed)
* <img src="assets/mail.png" width="16" height="auto" alt="email"/> fernand@imhotep.io
* <img src="assets/twitter.png" width="16" height="auto" alt="twitter"/> [@kitesurfer](https://twitter.com/kitesurfer?lang=en)
* [Aleksei Romanenko](https://github.com/slimus)
We always enjoy hearing from folks who benefit from our work!
## Contributions Guideline

View File

@ -545,16 +545,13 @@ func (a *APIClient) SwitchContext(name string) error {
if err := a.config.SwitchContext(name); err != nil {
return err
}
if err := a.invalidateCache(); err != nil {
return err
}
a.reset()
ResetMetrics()
// Need reload to pick up any kubeconfig changes.
a.config = NewConfig(a.config.flags)
return nil
return a.invalidateCache()
}
func (a *APIClient) reset() {

View File

@ -63,7 +63,7 @@ func TestHelperInList(t *testing.T) {
func TestEnsureDirPathNone(t *testing.T) {
var mod os.FileMode = 0744
dir := filepath.Join("/tmp", "fred")
dir := filepath.Join("/tmp", "k9s-test")
os.Remove(dir)
path := filepath.Join(dir, "duh.yaml")

View File

@ -1,3 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of K9s
package data
// Proxy tracks a context's proxy configuration.

View File

@ -13,7 +13,8 @@ import (
v1 "k8s.io/api/core/v1"
)
func isBoolSet(b *bool) bool {
// IsBoolSet checks if a bool ptr is set.
func IsBoolSet(b *bool) bool {
return b != nil && *b
}
@ -70,8 +71,3 @@ func MustK9sUser() string {
}
return usr.Username
}
// IsBoolSet checks if a bool prt is set.
func IsBoolSet(b *bool) bool {
return b != nil && *b
}

View File

@ -292,7 +292,7 @@ func (k *K9s) Override(k9sFlags *Flags) {
// IsHeadless returns headless setting.
func (k *K9s) IsHeadless() bool {
if isBoolSet(k.manualHeadless) {
if IsBoolSet(k.manualHeadless) {
return true
}
@ -301,7 +301,7 @@ func (k *K9s) IsHeadless() bool {
// IsLogoless returns logoless setting.
func (k *K9s) IsLogoless() bool {
if isBoolSet(k.manualLogoless) {
if IsBoolSet(k.manualLogoless) {
return true
}
@ -310,7 +310,7 @@ func (k *K9s) IsLogoless() bool {
// IsCrumbsless returns crumbsless setting.
func (k *K9s) IsCrumbsless() bool {
if isBoolSet(k.manualCrumbsless) {
if IsBoolSet(k.manualCrumbsless) {
return true
}

View File

@ -116,7 +116,7 @@ func getContainerStatus(kind string, name string, status v1.PodStatus) *v1.Conta
func (c *Container) fetchPod(fqn string) (*v1.Pod, error) {
o, err := c.getFactory().Get("v1/pods", fqn, true, labels.Everything())
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to locate pod %q: %w", fqn, err)
}
var po v1.Pod
err = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &po)

View File

@ -43,15 +43,12 @@ func (g *Generic) List(ctx context.Context, ns string) ([]runtime.Object, error)
ns = client.BlankNamespace
}
var (
ll *unstructured.UnstructuredList
err error
)
dial, err := g.dynClient()
if err != nil {
return nil, err
}
var ll *unstructured.UnstructuredList
if client.IsClusterScoped(ns) {
ll, err = dial.List(ctx, metav1.ListOptions{LabelSelector: labelSel})
} else {
@ -71,12 +68,13 @@ func (g *Generic) List(ctx context.Context, ns string) ([]runtime.Object, error)
// Get returns a given resource.
func (g *Generic) Get(ctx context.Context, path string) (runtime.Object, error) {
var opts metav1.GetOptions
ns, n := client.Namespaced(path)
dial, err := g.dynClient()
if err != nil {
return nil, err
}
var opts metav1.GetOptions
if client.IsClusterScoped(ns) {
return dial.Get(ctx, n, opts)
}

View File

@ -257,7 +257,7 @@ func FetchNode(ctx context.Context, f Factory, path string) (*v1.Node, error) {
return nil, fmt.Errorf("user is not authorized to list nodes")
}
o, err := f.Get("v1/nodes", client.FQN(client.ClusterScope, path), false, labels.Everything())
o, err := f.Get("v1/nodes", client.FQN(client.ClusterScope, path), true, labels.Everything())
if err != nil {
return nil, err
}

View File

@ -424,7 +424,8 @@ func loadCRDs(f Factory, m ResourceMetas) {
var meta metav1.APIResource
meta.Kind = crd.Spec.Names.Kind
meta.Group = crd.Spec.Group
meta.Name = crd.Name
meta.Name = strings.TrimSuffix(crd.Name, "."+meta.Group)
meta.SingularName = crd.Spec.Names.Singular
meta.ShortNames = crd.Spec.Names.ShortNames
meta.Namespaced = crd.Spec.Scope == apiext.NamespaceScoped
@ -435,11 +436,6 @@ func loadCRDs(f Factory, m ResourceMetas) {
}
}
// meta, errs := extractMeta(o)
// if len(errs) > 0 {
// log.Error().Err(errs[0]).Msgf("Fail to extract CRD meta (%d) errors", len(errs))
// continue
// }
meta.Categories = append(meta.Categories, crdCat)
gvr := client.NewGVRFromMeta(meta)
m[gvr] = meta

View File

@ -138,8 +138,8 @@ func (p Pod) Render(o interface{}, ns string, row *model1.Row) error {
}
c, r := gatherCoMX(&po.Spec, ccmx)
phase := p.Phase(&po)
row.ID = client.MetaFQN(po.ObjectMeta)
row.ID = client.MetaFQN(po.ObjectMeta)
row.Fields = model1.Fields{
po.Namespace,
po.Name,
@ -254,7 +254,7 @@ func cosLimits(cc []v1.Container) (resource.Quantity, resource.Quantity) {
for _, c := range cc {
limits := c.Resources.Limits
if len(limits) == 0 {
return resource.Quantity{}, resource.Quantity{}
continue
}
if limits.Cpu() != nil {
cpu.Add(*limits.Cpu())
@ -263,6 +263,7 @@ func cosLimits(cc []v1.Container) (resource.Quantity, resource.Quantity) {
mem.Add(*limits.Memory())
}
}
return *cpu, *mem
}

View File

@ -6,6 +6,7 @@ package render
import (
"fmt"
"strconv"
"strings"
"github.com/derailed/k9s/internal/client"
"github.com/derailed/k9s/internal/model1"
@ -34,7 +35,9 @@ func (ReplicaSet) Header(ns string) model1.Header {
model1.HeaderColumn{Name: "DESIRED", Align: tview.AlignRight},
model1.HeaderColumn{Name: "CURRENT", Align: tview.AlignRight},
model1.HeaderColumn{Name: "READY", Align: tview.AlignRight},
model1.HeaderColumn{Name: "LABELS", Wide: true},
model1.HeaderColumn{Name: "CONTAINERS", Wide: true},
model1.HeaderColumn{Name: "IMAGES", Wide: true},
model1.HeaderColumn{Name: "SELECTOR", Wide: true},
model1.HeaderColumn{Name: "VALID", Wide: true},
model1.HeaderColumn{Name: "AGE", Time: true},
}
@ -46,12 +49,21 @@ func (r ReplicaSet) Render(o interface{}, ns string, row *model1.Row) error {
if !ok {
return fmt.Errorf("expected ReplicaSet, but got %T", o)
}
var rs appsv1.ReplicaSet
err := runtime.DefaultUnstructuredConverter.FromUnstructured(raw.Object, &rs)
if err != nil {
return err
}
var (
cc = rs.Spec.Template.Spec.Containers
cos, imgs = make([]string, 0, len(cc)), make([]string, 0, len(cc))
)
for _, co := range cc {
cos, imgs = append(cos, co.Name), append(imgs, co.Image)
}
row.ID = client.MetaFQN(rs.ObjectMeta)
row.Fields = model1.Fields{
rs.Namespace,
@ -60,6 +72,8 @@ func (r ReplicaSet) Render(o interface{}, ns string, row *model1.Row) error {
strconv.Itoa(int(*rs.Spec.Replicas)),
strconv.Itoa(int(rs.Status.Replicas)),
strconv.Itoa(int(rs.Status.ReadyReplicas)),
strings.Join(cos, ","),
strings.Join(imgs, ","),
mapToStr(rs.Labels),
AsStatus(r.diagnose(rs)),
ToAge(rs.GetCreationTimestamp()),

View File

@ -530,7 +530,7 @@ func (a *App) Run() error {
})
}()
if err := a.command.defaultCmd(); err != nil {
if err := a.command.defaultCmd(true); err != nil {
return err
}
a.SetRunning(true)

View File

@ -209,19 +209,24 @@ func (c *Command) run(p *cmd.Interpreter, fqn string, clearStack bool) error {
return c.exec(p, gvr, co, clearStack)
}
func (c *Command) defaultCmd() error {
func (c *Command) defaultCmd(isRoot bool) error {
if c.app.Conn() == nil || !c.app.Conn().ConnectionOK() {
return c.run(cmd.NewInterpreter("context"), "", true)
}
defCmd := "pod"
if isRoot {
defCmd = "ctx"
}
p := cmd.NewInterpreter(c.app.Config.ActiveView())
if p.IsBlank() {
return c.run(p.Reset("pod"), "", true)
return c.run(p.Reset(defCmd), "", true)
}
if err := c.run(p, "", true); err != nil {
log.Error().Err(err).Msgf("Default run command failed %q", p.GetLine())
return c.run(p.Reset("pod"), "", true)
p = p.Reset(defCmd)
log.Error().Err(fmt.Errorf("Command failed. Using default command: %s", p.GetLine()))
return c.run(p, "", true)
}
return nil

View File

@ -393,6 +393,7 @@ func (l *Log) toggleAllContainers(evt *tcell.EventKey) *tcell.EventKey {
func (l *Log) filterCmd(evt *tcell.EventKey) *tcell.EventKey {
if !l.logs.cmdBuff.IsActive() {
fmt.Fprintln(l.ansiWriter)
return evt
}
@ -451,7 +452,7 @@ func (l *Log) clearCmd(*tcell.EventKey) *tcell.EventKey {
func (l *Log) markCmd(*tcell.EventKey) *tcell.EventKey {
_, _, w, _ := l.GetRect()
fmt.Fprintf(l.ansiWriter, "\n[%s:-:b]%s[-:-:-]", l.app.Styles.Views().Log.FgColor.String(), strings.Repeat("", w-4))
fmt.Fprintf(l.ansiWriter, "\n[%s:-:b]%s[-:-:-]", l.app.Styles.Views().Log.FgColor.String(), strings.Repeat("-", w-4))
l.follow = true
return nil

View File

@ -20,8 +20,6 @@ import (
"github.com/rs/zerolog/log"
)
const promptPage = "prompt"
// PortForward presents active portforward viewer.
type PortForward struct {
ResourceViewer

View File

@ -21,7 +21,7 @@ import (
const (
defaultResync = 10 * time.Minute
defaultWaitTime = 250 * time.Millisecond
defaultWaitTime = 500 * time.Millisecond
)
// Factory tracks various resource informers.
@ -72,13 +72,13 @@ func (f *Factory) Terminate() {
// List returns a resource collection.
func (f *Factory) List(gvr, ns string, wait bool, labels labels.Selector) ([]runtime.Object, error) {
if client.IsAllNamespace(ns) {
ns = client.BlankNamespace
}
inf, err := f.CanForResource(ns, gvr, client.ListAccess)
if err != nil {
return nil, err
}
if client.IsAllNamespace(ns) {
ns = client.BlankNamespace
}
var oo []runtime.Object
if client.IsClusterScoped(ns) {
@ -110,6 +110,10 @@ func (f *Factory) HasSynced(gvr, ns string) (bool, error) {
// Get retrieves a given resource.
func (f *Factory) Get(gvr, fqn string, wait bool, sel labels.Selector) (runtime.Object, error) {
ns, n := namespaced(fqn)
if client.IsAllNamespace(ns) {
ns = client.BlankNamespace
}
inf, err := f.CanForResource(ns, gvr, []string{client.GetVerb})
if err != nil {
return nil, err
@ -128,6 +132,7 @@ func (f *Factory) Get(gvr, fqn string, wait bool, sel labels.Selector) (runtime.
if client.IsClusterScoped(ns) {
return inf.Lister().Get(n)
}
return inf.Lister().ByNamespace(ns).Get(n)
}