Skip to content

Commit

Permalink
Refactor ReplicationController printer
Browse files Browse the repository at this point in the history
Signed-off-by: GuessWhoSamFoo <[email protected]>
  • Loading branch information
GuessWhoSamFoo committed Sep 17, 2019
1 parent 7ff1d56 commit bcea2bc
Show file tree
Hide file tree
Showing 2 changed files with 260 additions and 37 deletions.
149 changes: 117 additions & 32 deletions internal/modules/overview/printer/replicationcontroller.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
"github.com/pkg/errors"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"

"github.com/vmware/octant/pkg/store"
"github.com/vmware/octant/pkg/view/component"
Expand Down Expand Up @@ -60,57 +62,47 @@ func ReplicationControllerListHandler(ctx context.Context, list *corev1.Replicat
// ReplicationControllerHandler is a printFunc that prints a ReplicationController
func ReplicationControllerHandler(ctx context.Context, rc *corev1.ReplicationController, options Options) (component.Component, error) {
o := NewObject(rc)
o.EnableEvents()

objectStore := options.DashConfig.ObjectStore()

rcConfigGen := NewReplicationControllerConfiguration(rc)
configSummary, err := rcConfigGen.Create(options)
rch, err := newReplicationControllerHandler(rc, o)
if err != nil {
return nil, err
}
o.RegisterConfig(configSummary)

rcSummaryGen := NewReplicationControllerStatus(rc)
o.RegisterItems(ItemDescriptor{
Width: component.WidthQuarter,
Func: func() (component.Component, error) {
return rcSummaryGen.Create(ctx, objectStore)
},
})

o.RegisterItems(ItemDescriptor{
Func: func() (component.Component, error) {
return createPodListView(ctx, rc, options)
},
Width: component.WidthFull,
})
if err := rch.Config(options); err != nil {
return nil, errors.Wrap(err, "print replicationcontroller configuration")
}

o.EnablePodTemplate(*rc.Spec.Template)
if err := rch.Status(ctx, options); err != nil {
return nil, errors.Wrap(err, "print replicationcontroller status")
}

o.EnableEvents()
if err := rch.Pods(ctx, rc, options); err != nil {
return nil, errors.Wrap(err, "print replicationcontroller pods")
}

return o.ToComponent(ctx, options)
}

// ReplicationControllerConfiguration generates a replicationcontroller configuration
type ReplicationControllerConfiguration struct {
replicationcontroller *corev1.ReplicationController
replicationController *corev1.ReplicationController
}

// NewReplicationControllerConfiguration creates an instance of ReplicationControllerConfiguration
func NewReplicationControllerConfiguration(rc *corev1.ReplicationController) *ReplicationControllerConfiguration {
return &ReplicationControllerConfiguration{
replicationcontroller: rc,
replicationController: rc,
}
}

// Create generates a replicationcontroller configuration summary
func (rcc *ReplicationControllerConfiguration) Create(options Options) (*component.Summary, error) {
if rcc == nil || rcc.replicationcontroller == nil {
if rcc == nil || rcc.replicationController == nil {
return nil, errors.New("replicationcontroller is nil")
}

replicationController := rcc.replicationcontroller
replicationController := rcc.replicationController

sections := component.SummarySections{}

Expand Down Expand Up @@ -143,27 +135,35 @@ func (rcc *ReplicationControllerConfiguration) Create(options Options) (*compone

// ReplicationControllerStatus generates a replication controller status
type ReplicationControllerStatus struct {
replicationcontroller *corev1.ReplicationController
context context.Context
namespace string
selector map[string]string
uid types.UID
objectStore store.Store
}

// NewReplicationControllerStatus creates an instance of ReplicationControllerStatus
func NewReplicationControllerStatus(replicationController *corev1.ReplicationController) *ReplicationControllerStatus {
func NewReplicationControllerStatus(ctx context.Context, replicationController *corev1.ReplicationController, options Options) *ReplicationControllerStatus {
return &ReplicationControllerStatus{
replicationcontroller: replicationController,
context: ctx,
namespace: replicationController.ObjectMeta.Namespace,
selector: replicationController.Spec.Selector,
uid: replicationController.GetUID(),
objectStore: options.DashConfig.ObjectStore(),
}
}

// Create generates a replicaset status quadrant
func (replicationController *ReplicationControllerStatus) Create(ctx context.Context, o store.Store) (*component.Quadrant, error) {
if replicationController.replicationcontroller == nil {
func (rcs *ReplicationControllerStatus) Create() (*component.Quadrant, error) {
if rcs == nil {
return nil, errors.New("replicationcontroller is nil")
}

selectors := metav1.LabelSelector{
MatchLabels: replicationController.replicationcontroller.Spec.Selector,
MatchLabels: rcs.selector,
}

pods, err := listPods(ctx, replicationController.replicationcontroller.Namespace, &selectors, replicationController.replicationcontroller.GetUID(), o)
pods, err := listPods(rcs.context, rcs.namespace, &selectors, rcs.uid, rcs.objectStore)
if err != nil {
return nil, err
}
Expand All @@ -186,3 +186,88 @@ func (replicationController *ReplicationControllerStatus) Create(ctx context.Con

return quadrant, nil
}

type replicationControllerObject interface {
Config(options Options) error
Status(ctx context.Context, options Options) error
Pods(ctx context.Context, object runtime.Object, options Options) error
}

type replicationControllerHandler struct {
replicationController *corev1.ReplicationController
configFunc func(*corev1.ReplicationController, Options) (*component.Summary, error)
statusFunc func(context.Context, *corev1.ReplicationController, Options) (*component.Quadrant, error)
podFunc func(context.Context, runtime.Object, Options) (component.Component, error)
object *Object
}

var _ replicationControllerObject = (*replicaSetHandler)(nil)

func newReplicationControllerHandler(replicationController *corev1.ReplicationController, object *Object) (*replicationControllerHandler, error) {
if replicationController == nil {
return nil, errors.New("can't print a nil replicationcontroller")
}

if object == nil {
return nil, errors.New("can't print a replicationcontroller using a nil object printer")
}

rch := &replicationControllerHandler{
replicationController: replicationController,
configFunc: defaultReplicationControllerConfig,
statusFunc: defaultReplicationControllerStatus,
podFunc: defaultReplicationControllerPods,
object: object,
}

return rch, nil
}

func (r *replicationControllerHandler) Config(options Options) error {
out, err := r.configFunc(r.replicationController, options)
if err != nil {
return err
}
r.object.RegisterConfig(out)
return nil
}

func defaultReplicationControllerConfig(replicationController *corev1.ReplicationController, options Options) (*component.Summary, error) {
return NewReplicationControllerConfiguration(replicationController).Create(options)
}

func (r *replicationControllerHandler) Status(ctx context.Context, options Options) error {
if r.replicationController == nil {
return errors.New("can't display status for nil replicationcontroller")
}

r.object.RegisterItems(ItemDescriptor{
Width: component.WidthQuarter,
Func: func() (component.Component, error) {
return r.statusFunc(ctx, r.replicationController, options)
},
})

return nil
}

func defaultReplicationControllerStatus(ctx context.Context, replicationController *corev1.ReplicationController, options Options) (*component.Quadrant, error) {
return NewReplicationControllerStatus(ctx, replicationController, options).Create()
}

func (r *replicationControllerHandler) Pods(ctx context.Context, object runtime.Object, options Options) error {
r.object.EnablePodTemplate(*r.replicationController.Spec.Template)

r.object.RegisterItems(ItemDescriptor{
Width: component.WidthFull,
Func: func() (component.Component, error) {
return r.podFunc(ctx, object, options)
},
})

return nil
}

func defaultReplicationControllerPods(ctx context.Context, object runtime.Object, options Options) (component.Component, error) {
return createPodListView(ctx, object, options)
}
148 changes: 143 additions & 5 deletions internal/modules/overview/printer/replicationcontroller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (

"github.com/vmware/octant/internal/testutil"
"github.com/vmware/octant/pkg/store"
storefake "github.com/vmware/octant/pkg/store/fake"
"github.com/vmware/octant/pkg/view/component"
)

Expand Down Expand Up @@ -98,11 +97,71 @@ func Test_ReplicationControllerListHandler(t *testing.T) {
component.AssertEqual(t, expected, got)
}

func Test_ReplicationControllerConfiguration(t *testing.T) {
var replicas int32 = 3

rc := testutil.CreateReplicationController("rc")
rc.Spec.Replicas = &replicas
rc.Status = corev1.ReplicationControllerStatus{
ReadyReplicas: 3,
Replicas: 3,
}

cases := []struct {
name string
replicationController *corev1.ReplicationController
isErr bool
expected *component.Summary
}{
{
name: "replicationcontroller",
replicationController: rc,
expected: component.NewSummary("Configuration", []component.SummarySection{
{
Header: "Replica Status",
Content: component.NewText("Current 3 / Desired 3"),
},
{
Header: "Replicas",
Content: component.NewText("3"),
},
}...),
},
{
name: "replicationcontroller is nil",
replicationController: nil,
isErr: true,
},
}

for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
controller := gomock.NewController(t)
defer controller.Finish()

tpo := newTestPrinterOptions(controller)
printOptions := tpo.ToOptions()

rcc := NewReplicationControllerConfiguration(tc.replicationController)

summary, err := rcc.Create(printOptions)
if tc.isErr {
require.Error(t, err)
return
}
require.NoError(t, err)

component.AssertEqual(t, tc.expected, summary)
})
}
}

func TestReplicationControllerStatus(t *testing.T) {
controller := gomock.NewController(t)
defer controller.Finish()

o := storefake.NewMockStore(controller)
tpo := newTestPrinterOptions(controller)
printOptions := tpo.ToOptions()

replicationController := testutil.CreateReplicationController("rc")
replicationController.Labels = map[string]string{
Expand Down Expand Up @@ -145,10 +204,11 @@ func TestReplicationControllerStatus(t *testing.T) {
Kind: "Pod",
}

o.EXPECT().List(gomock.Any(), gomock.Eq(key)).Return(podList, false, nil)
rcs := NewReplicationControllerStatus(replicationController)
tpo.objectStore.EXPECT().List(gomock.Any(), gomock.Eq(key)).Return(podList, false, nil)

ctx := context.Background()
got, err := rcs.Create(ctx, o)
rcs := NewReplicationControllerStatus(ctx, replicationController, printOptions)
got, err := rcs.Create()
require.NoError(t, err)

expected := component.NewQuadrant("Status")
Expand All @@ -159,3 +219,81 @@ func TestReplicationControllerStatus(t *testing.T) {

assert.Equal(t, expected, got)
}

func Test_ReplicationControllerPods(t *testing.T) {
controller := gomock.NewController(t)
defer controller.Finish()

tpo := newTestPrinterOptions(controller)

ctx := context.Background()

now := testutil.Time()

nodeLink := component.NewLink("", "node", "/node")
tpo.link.EXPECT().
ForGVK("", "v1", "Node", "node", "node").
Return(nodeLink, nil).AnyTimes()

rc := testutil.CreateReplicationController("replicationcontroller")

pod := testutil.CreatePod("nginx-hv4qs")
pod.SetOwnerReferences(testutil.ToOwnerReferences(t, rc))
pod.CreationTimestamp = metav1.Time{Time: now}
pod.Spec.Containers = []corev1.Container{
{
Name: "nginx",
Image: "nginx:1.15",
},
}
pod.Spec.NodeName = "node"
pod.Status = corev1.PodStatus{
Phase: "Pending",
ContainerStatuses: []corev1.ContainerStatus{
{
Name: "nginx",
Image: "nginx:1.15",
RestartCount: 0,
Ready: false,
},
},
}

pods := &corev1.PodList{
Items: []corev1.Pod{*pod},
}

tpo.PathForObject(pod, pod.Name, "/pod")

podList := &unstructured.UnstructuredList{}
for _, p := range pods.Items {
podList.Items = append(podList.Items, *testutil.ToUnstructured(t, &p))
}
key := store.Key{
Namespace: "namespace",
APIVersion: "v1",
Kind: "Pod",
}

tpo.objectStore.EXPECT().List(gomock.Any(), gomock.Eq(key)).Return(podList, false, nil)

printOptions := tpo.ToOptions()
printOptions.DisableLabels = false

got, err := createPodListView(ctx, rc, printOptions)
require.NoError(t, err)

cols := component.NewTableCols("Name", "Ready", "Phase", "Restarts", "Node", "Age")
expected := component.NewTable("Pods", "We couldn't find any pods!", cols)
expected.Add(component.TableRow{
"Name": component.NewLink("", "nginx-hv4qs", "/pod"),
"Ready": component.NewText("0/1"),
"Phase": component.NewText("Pending"),
"Restarts": component.NewText("0"),
"Node": nodeLink,
"Age": component.NewTimestamp(now),
})
addPodTableFilters(expected)

component.AssertEqual(t, expected, got)
}

0 comments on commit bcea2bc

Please sign in to comment.