Skip to content
This repository has been archived by the owner on Jan 19, 2023. It is now read-only.

Fix panic for standalone pod in applications view #2676

Merged
merged 1 commit into from
Jul 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelogs/unreleased/2650-GuessWhoSamFoo
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed panic when viewing objects with no owner reference in applications view
15 changes: 13 additions & 2 deletions internal/modules/workloads/detail_describer.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,19 @@ _%s_
return objects[i].GetName() < objects[j].GetName()
})

selection := objects[0].GetOwnerReferences()[0]
rv, err := resourceviewer.Create(ctx, options.Dash, options.Queryer, fmt.Sprintf("%s pods", selection.Name), objects...)
var selection string
for _, obj := range objects {
if len(obj.GetOwnerReferences()) > 0 {
for _, ref := range obj.GetOwnerReferences() {
selection = fmt.Sprintf("%s pods", ref.Name)
continue
}
} else {
selection = string(obj.GetUID())
}
}

rv, err := resourceviewer.Create(ctx, options.Dash, options.Queryer, selection, objects...)
if err != nil {
cr := d.createResponse(
component.NewError(component.TitleFromString("Unable to create resource viewer"), err),
Expand Down
106 changes: 106 additions & 0 deletions internal/modules/workloads/detail_describer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package workloads

import (
"context"
"testing"

"github.com/golang/mock/gomock"
"github.com/stretchr/testify/require"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"

clusterFake "github.com/vmware-tanzu/octant/internal/cluster/fake"
configFake "github.com/vmware-tanzu/octant/internal/config/fake"
"github.com/vmware-tanzu/octant/internal/describer"
"github.com/vmware-tanzu/octant/internal/queryer"
queryerFake "github.com/vmware-tanzu/octant/internal/queryer/fake"
"github.com/vmware-tanzu/octant/internal/testutil"
"github.com/vmware-tanzu/octant/pkg/plugin"
pluginFake "github.com/vmware-tanzu/octant/pkg/plugin/fake"
"github.com/vmware-tanzu/octant/pkg/store"
objectStoreFake "github.com/vmware-tanzu/octant/pkg/store/fake"
"github.com/vmware-tanzu/octant/pkg/view/component"
)

func TestDetailDescriber_Describe(t *testing.T) {
controller := gomock.NewController(t)
defer controller.Finish()
ctx := context.Background()

dd, err := NewDetailDescriber()
require.NoError(t, err)

tdo := newTestDescriberOptions(t, controller)
describerOptions := tdo.ToOptions()

result, err := dd.Describe(ctx, "namespace", describerOptions)
require.NoError(t, err)

for _, c := range result.Components {
f, ok := c.(*component.FlexLayout)
require.Equal(t, true, ok)
require.Equal(t, component.TitleFromString("Workload layout"), f.Title)
require.Equal(t, 2, len(f.Config.Sections))
}
}

type testDescriberOptions struct {
dashConfig *configFake.MockDash
queryer queryer.Queryer
}

func newTestDescriberOptions(t *testing.T, controller *gomock.Controller) *testDescriberOptions {
dashConfig := configFake.NewMockDash(controller)

clusterClient := clusterFake.NewMockClientInterface(controller)
objectStore := objectStoreFake.NewMockStore(controller)
discoveryInterface := clusterFake.NewMockDiscoveryInterface(controller)
pluginManager := pluginFake.NewMockManagerInterface(controller)

podKey := store.Key{
Namespace: "namespace",
APIVersion: "v1",
Kind: "Pod",
}

pod := testutil.CreatePod("pod")
u := testutil.ToUnstructured(t, pod)
objectStore.EXPECT().List(gomock.Any(), podKey).Return(testutil.ToUnstructuredList(t, pod), false, nil).AnyTimes()

clusterClient.EXPECT().DiscoveryClient().Return(discoveryInterface, nil).AnyTimes()
discoveryInterface.EXPECT().ServerPreferredNamespacedResources().AnyTimes()
dashConfig.EXPECT().ClusterClient().Return(clusterClient).AnyTimes()
dashConfig.EXPECT().ObjectStore().Return(objectStore).AnyTimes()
dashConfig.EXPECT().PluginManager().Return(pluginManager).AnyTimes()

queryer := queryerFake.NewMockQueryer(controller)
queryer.EXPECT().PersistentVolumeClaimsForPod(gomock.Any(), pod)
queryer.EXPECT().ConfigMapsForPod(gomock.Any(), pod)
queryer.EXPECT().SecretsForPod(gomock.Any(), pod)
queryer.EXPECT().ServicesForPod(gomock.Any(), pod)
queryer.EXPECT().OwnerReference(gomock.Any(), u)
queryer.EXPECT().Children(gomock.Any(), u).Return(&unstructured.UnstructuredList{}, nil)

dashConfig.EXPECT().ObjectPath(pod.Namespace, pod.APIVersion, pod.Kind, pod.Name)
dashConfig.EXPECT().ObjectPath(pod.Namespace, "v1", "ServiceAccount", "")
eventKey := store.Key{
Namespace: "namespace",
APIVersion: "v1",
Kind: "Event",
}
objectStore.EXPECT().List(gomock.Any(), eventKey).Return(&unstructured.UnstructuredList{}, false, nil)
pluginManager.EXPECT().ObjectStatus(gomock.Any(), u).Return(&plugin.ObjectStatusResponse{}, nil)

tdo := &testDescriberOptions{
dashConfig: dashConfig,
queryer: queryer,
}
return tdo
}

func (o *testDescriberOptions) ToOptions() describer.Options {
return describer.Options{
Dash: o.dashConfig,
Fields: map[string]string{"name": "pod"},
Queryer: o.queryer,
}
}