Skip to content

Commit

Permalink
feat: show owner (derailed#1747)
Browse files Browse the repository at this point in the history
  • Loading branch information
gitolicious committed Jan 19, 2024
1 parent e5cadf1 commit 7fba6d9
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 5 deletions.
4 changes: 2 additions & 2 deletions internal/view/help_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ func TestHelp(t *testing.T) {
v := view.NewHelp(app)

assert.Nil(t, v.Init(ctx))
assert.Equal(t, 28, v.GetRowCount())
assert.Equal(t, 8, v.GetColumnCount())
assert.Equal(t, 29, v.GetRowCount())
assert.Equal(t, 9, v.GetColumnCount())
assert.Equal(t, "<a>", strings.TrimSpace(v.GetCell(1, 0).Text))
assert.Equal(t, "Attach", strings.TrimSpace(v.GetCell(1, 1).Text))
}
133 changes: 133 additions & 0 deletions internal/view/owner_extender.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package view

import (
"errors"
"fmt"
"github.com/derailed/k9s/internal/client"
"github.com/derailed/k9s/internal/model"
"github.com/derailed/k9s/internal/ui"
"github.com/derailed/tcell/v2"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
)

// OwnerExtender adds log actions to a given viewer.
type OwnerExtender struct {
ResourceViewer
}

// NewOwnerExtender returns a new extender.
func NewOwnerExtender(v ResourceViewer) ResourceViewer {
o := OwnerExtender{
ResourceViewer: v,
}
o.AddBindKeysFn(o.bindKeys)

return &o
}

// BindKeys injects new menu actions.
func (o *OwnerExtender) bindKeys(aa ui.KeyActions) {
aa.Add(ui.KeyActions{
ui.KeyO: ui.NewKeyAction("Show Owner", o.ownerCmd(false), true),
})
}

func (o *OwnerExtender) ownerCmd(prev bool) func(evt *tcell.EventKey) *tcell.EventKey {
return func(evt *tcell.EventKey) *tcell.EventKey {
path := o.GetTable().GetSelectedItem()
if path == "" {
return nil
}
if !isResourcePath(path) {
path = o.GetTable().Path
}
o.showOwner(o.GetTable().GVR(), path, prev, evt)

return nil
}
}

func (o *OwnerExtender) showOwner(gvr client.GVR, path string, prev bool, evt *tcell.EventKey) {
var ownerReferences []v1.OwnerReference

r, err := o.App().factory.Get(gvr.String(), path, true, labels.Everything())
if err != nil {
o.App().Flash().Err(err)
return
}

u, ok := r.(*unstructured.Unstructured)
if !ok {
o.App().Flash().Err(errors.New("unable to parse resource"))
return
}

ownerReferences, err = o.extractOwnerReference(u)
if err != nil {
o.App().Flash().Err(err)
return
}

var owner model.Component
for _, ownerReference := range ownerReferences {
ownerPath := u.GetNamespace() + "/" + ownerReference.Name

switch ownerReference.Kind {
case "ReplicaSet":
rs := NewReplicaSet(client.NewGVR(ownerReference.APIVersion + "/replicasets"))
rs.SetInstance(ownerPath)
owner = rs
case "DaemonSet":
ds := NewDaemonSet(client.NewGVR(ownerReference.APIVersion + "/daemonsets"))
ds.SetInstance(ownerPath)
owner = ds
case "Deployment":
d := NewDeploy(client.NewGVR(ownerReference.APIVersion + "/deployments"))
d.SetInstance(ownerPath)
owner = d
}
}

if owner == nil {
o.App().Flash().Err(errors.New(fmt.Sprintf("unsupported owner kind")))
return
}

if err := o.App().inject(owner, false); err != nil {
o.App().Flash().Err(err)
}

return
}

// extractOwnerReference extracts the OwnerReferences from an unstructured object
func (o *OwnerExtender) extractOwnerReference(obj *unstructured.Unstructured) ([]v1.OwnerReference, error) {
ownerRef, found, err := unstructured.NestedSlice(obj.Object, "metadata", "ownerReferences")
if err != nil {
return nil, err
}
if !found {
return nil, nil
}

var ownerReferences []v1.OwnerReference
for _, ref := range ownerRef {
ownerReferenceMap, ok := ref.(map[string]interface{})
if !ok {
return nil, errors.New("could not extract ownerReference")
}

ownerReference := v1.OwnerReference{}
err := runtime.DefaultUnstructuredConverter.FromUnstructured(ownerReferenceMap, &ownerReference)
if err != nil {
return nil, err
}

ownerReferences = append(ownerReferences, ownerReference)
}

return ownerReferences, nil
}
6 changes: 5 additions & 1 deletion internal/view/pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,11 @@ func NewPod(gvr client.GVR) ResourceViewer {
p.ResourceViewer = NewPortForwardExtender(
NewVulnerabilityExtender(
NewImageExtender(
NewLogsExtender(NewBrowser(gvr), p.logOptions),
NewOwnerExtender(
NewLogsExtender(
NewBrowser(gvr),
p.logOptions),
),
),
),
)
Expand Down
2 changes: 1 addition & 1 deletion internal/view/pod_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func TestPodNew(t *testing.T) {

assert.Nil(t, po.Init(makeCtx()))
assert.Equal(t, "Pods", po.Name())
assert.Equal(t, 27, len(po.Hints()))
assert.Equal(t, 28, len(po.Hints()))
}

// Helpers...
Expand Down
6 changes: 5 additions & 1 deletion internal/view/rs.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@ type ReplicaSet struct {
// NewReplicaSet returns a new viewer.
func NewReplicaSet(gvr client.GVR) ResourceViewer {
r := ReplicaSet{
ResourceViewer: NewVulnerabilityExtender(NewBrowser(gvr)),
ResourceViewer: NewVulnerabilityExtender(
NewOwnerExtender(
NewBrowser(gvr),
),
),
}
r.AddBindKeysFn(r.bindKeys)
r.GetTable().SetEnterFn(r.showPods)
Expand Down

0 comments on commit 7fba6d9

Please sign in to comment.