Browse code

oc: enhance the deploymentconfig describer

Add autoscaling info, reorganize other information, factor out custom
describer interfaces.

kargakis authored on 2016/03/15 00:00:52
Showing 5 changed files
... ...
@@ -222,7 +222,7 @@ func (o *RollbackOptions) Run() error {
222 222
 
223 223
 	// If this is a dry run, print and exit.
224 224
 	if o.DryRun {
225
-		describer := describe.NewDeploymentConfigDescriberForConfig(o.oc, o.kc, newConfig)
225
+		describer := describe.NewDeploymentConfigDescriber(o.oc, o.kc, newConfig)
226 226
 		description, err := describer.Describe(newConfig.Namespace, newConfig.Name)
227 227
 		if err != nil {
228 228
 			return err
... ...
@@ -8,14 +8,16 @@ import (
8 8
 	"strings"
9 9
 	"text/tabwriter"
10 10
 
11
-	"github.com/openshift/origin/pkg/api/graph"
12
-
13 11
 	kapi "k8s.io/kubernetes/pkg/api"
14 12
 	kerrors "k8s.io/kubernetes/pkg/api/errors"
13
+	"k8s.io/kubernetes/pkg/api/unversioned"
14
+	"k8s.io/kubernetes/pkg/apis/extensions"
15 15
 	kclient "k8s.io/kubernetes/pkg/client/unversioned"
16
+	rcutils "k8s.io/kubernetes/pkg/controller/replication"
16 17
 	kctl "k8s.io/kubernetes/pkg/kubectl"
17 18
 	"k8s.io/kubernetes/pkg/labels"
18 19
 
20
+	"github.com/openshift/origin/pkg/api/graph"
19 21
 	kubegraph "github.com/openshift/origin/pkg/api/kubegraph/nodes"
20 22
 	"github.com/openshift/origin/pkg/client"
21 23
 	deployapi "github.com/openshift/origin/pkg/deploy/api"
... ...
@@ -27,101 +29,34 @@ import (
27 27
 
28 28
 // DeploymentConfigDescriber generates information about a DeploymentConfig
29 29
 type DeploymentConfigDescriber struct {
30
-	client deploymentDescriberClient
31
-}
32
-
33
-type deploymentDescriberClient interface {
34
-	getDeploymentConfig(namespace, name string) (*deployapi.DeploymentConfig, error)
35
-	getDeployment(namespace, name string) (*kapi.ReplicationController, error)
36
-	listDeployments(namespace string, selector labels.Selector) (*kapi.ReplicationControllerList, error)
37
-	listPods(namespace string, selector labels.Selector) (*kapi.PodList, error)
38
-	listEvents(deploymentConfig *deployapi.DeploymentConfig) (*kapi.EventList, error)
39
-}
40
-
41
-type genericDeploymentDescriberClient struct {
42
-	getDeploymentConfigFunc func(namespace, name string) (*deployapi.DeploymentConfig, error)
43
-	getDeploymentFunc       func(namespace, name string) (*kapi.ReplicationController, error)
44
-	listDeploymentsFunc     func(namespace string, selector labels.Selector) (*kapi.ReplicationControllerList, error)
45
-	listPodsFunc            func(namespace string, selector labels.Selector) (*kapi.PodList, error)
46
-	listEventsFunc          func(deploymentConfig *deployapi.DeploymentConfig) (*kapi.EventList, error)
47
-}
48
-
49
-func (c *genericDeploymentDescriberClient) getDeploymentConfig(namespace, name string) (*deployapi.DeploymentConfig, error) {
50
-	return c.getDeploymentConfigFunc(namespace, name)
51
-}
52
-
53
-func (c *genericDeploymentDescriberClient) getDeployment(namespace, name string) (*kapi.ReplicationController, error) {
54
-	return c.getDeploymentFunc(namespace, name)
55
-}
30
+	osClient   client.Interface
31
+	kubeClient kclient.Interface
56 32
 
57
-func (c *genericDeploymentDescriberClient) listDeployments(namespace string, selector labels.Selector) (*kapi.ReplicationControllerList, error) {
58
-	return c.listDeploymentsFunc(namespace, selector)
59
-}
60
-
61
-func (c *genericDeploymentDescriberClient) listPods(namespace string, selector labels.Selector) (*kapi.PodList, error) {
62
-	return c.listPodsFunc(namespace, selector)
63
-}
64
-
65
-func (c *genericDeploymentDescriberClient) listEvents(deploymentConfig *deployapi.DeploymentConfig) (*kapi.EventList, error) {
66
-	return c.listEventsFunc(deploymentConfig)
67
-}
68
-
69
-// NewDeploymentConfigDescriberForConfig returns a new DeploymentConfigDescriber
70
-// for a DeploymentConfig
71
-func NewDeploymentConfigDescriberForConfig(client client.Interface, kclient kclient.Interface, config *deployapi.DeploymentConfig) *DeploymentConfigDescriber {
72
-	return &DeploymentConfigDescriber{
73
-		client: &genericDeploymentDescriberClient{
74
-			getDeploymentConfigFunc: func(namespace, name string) (*deployapi.DeploymentConfig, error) {
75
-				return config, nil
76
-			},
77
-			getDeploymentFunc: func(namespace, name string) (*kapi.ReplicationController, error) {
78
-				return nil, kerrors.NewNotFound(kapi.Resource("replicatoncontroller"), name)
79
-			},
80
-			listDeploymentsFunc: func(namespace string, selector labels.Selector) (*kapi.ReplicationControllerList, error) {
81
-				return nil, kerrors.NewNotFound(kapi.Resource("replicationcontrollerlist"), fmt.Sprintf("%v", selector))
82
-			},
83
-			listPodsFunc: func(namespace string, selector labels.Selector) (*kapi.PodList, error) {
84
-				return nil, kerrors.NewNotFound(kapi.Resource("podlist"), fmt.Sprintf("%v", selector))
85
-			},
86
-			listEventsFunc: func(deploymentConfig *deployapi.DeploymentConfig) (*kapi.EventList, error) {
87
-				return kclient.Events(config.Namespace).Search(config)
88
-			},
89
-		},
90
-	}
33
+	config *deployapi.DeploymentConfig
91 34
 }
92 35
 
93 36
 // NewDeploymentConfigDescriber returns a new DeploymentConfigDescriber
94
-func NewDeploymentConfigDescriber(client client.Interface, kclient kclient.Interface) *DeploymentConfigDescriber {
37
+func NewDeploymentConfigDescriber(client client.Interface, kclient kclient.Interface, config *deployapi.DeploymentConfig) *DeploymentConfigDescriber {
95 38
 	return &DeploymentConfigDescriber{
96
-		client: &genericDeploymentDescriberClient{
97
-			getDeploymentConfigFunc: func(namespace, name string) (*deployapi.DeploymentConfig, error) {
98
-				return client.DeploymentConfigs(namespace).Get(name)
99
-			},
100
-			getDeploymentFunc: func(namespace, name string) (*kapi.ReplicationController, error) {
101
-				return kclient.ReplicationControllers(namespace).Get(name)
102
-			},
103
-			listDeploymentsFunc: func(namespace string, selector labels.Selector) (*kapi.ReplicationControllerList, error) {
104
-				return kclient.ReplicationControllers(namespace).List(kapi.ListOptions{LabelSelector: selector})
105
-			},
106
-			listPodsFunc: func(namespace string, selector labels.Selector) (*kapi.PodList, error) {
107
-				return kclient.Pods(namespace).List(kapi.ListOptions{LabelSelector: selector})
108
-			},
109
-			listEventsFunc: func(deploymentConfig *deployapi.DeploymentConfig) (*kapi.EventList, error) {
110
-				return kclient.Events(deploymentConfig.Namespace).Search(deploymentConfig)
111
-			},
112
-		},
39
+		osClient:   client,
40
+		kubeClient: kclient,
41
+		config:     config,
113 42
 	}
114 43
 }
115 44
 
116 45
 // Describe returns the description of a DeploymentConfig
117 46
 func (d *DeploymentConfigDescriber) Describe(namespace, name string) (string, error) {
118
-	deploymentConfig, err := d.client.getDeploymentConfig(namespace, name)
119
-	if err != nil {
120
-		return "", err
121
-	}
122
-	events, err := d.client.listEvents(deploymentConfig)
123
-	if err != nil {
124
-		return "", err
47
+	var deploymentConfig *deployapi.DeploymentConfig
48
+	if d.config != nil {
49
+		// If a deployment config is already provided use that.
50
+		// This is used by `oc rollback --dry-run`.
51
+		deploymentConfig = d.config
52
+	} else {
53
+		var err error
54
+		deploymentConfig, err = d.osClient.DeploymentConfigs(namespace).Get(name)
55
+		if err != nil {
56
+			return "", err
57
+		}
125 58
 	}
126 59
 
127 60
 	return tabbedString(func(out *tabwriter.Writer) error {
... ...
@@ -133,14 +68,15 @@ func (d *DeploymentConfigDescriber) Describe(namespace, name string) (string, er
133 133
 			formatString(out, "Latest Version", strconv.Itoa(deploymentConfig.Status.LatestVersion))
134 134
 		}
135 135
 
136
-		printDeploymentConfigSpec(deploymentConfig.Spec, out)
136
+		printDeploymentConfigSpec(d.kubeClient, *deploymentConfig, out)
137 137
 		fmt.Fprintln(out)
138 138
 
139 139
 		if deploymentConfig.Status.Details != nil && len(deploymentConfig.Status.Details.Message) > 0 {
140 140
 			fmt.Fprintf(out, "Warning:\t%s\n", deploymentConfig.Status.Details.Message)
141 141
 		}
142
+
142 143
 		deploymentName := deployutil.LatestDeploymentNameForConfig(deploymentConfig)
143
-		deployment, err := d.client.getDeployment(namespace, deploymentName)
144
+		deployment, err := d.kubeClient.ReplicationControllers(namespace).Get(deploymentName)
144 145
 		if err != nil {
145 146
 			if kerrors.IsNotFound(err) {
146 147
 				formatString(out, "Latest Deployment", "<none>")
... ...
@@ -149,22 +85,25 @@ func (d *DeploymentConfigDescriber) Describe(namespace, name string) (string, er
149 149
 			}
150 150
 		} else {
151 151
 			header := fmt.Sprintf("Deployment #%d (latest)", deployutil.DeploymentVersionFor(deployment))
152
-			printDeploymentRc(deployment, d.client, out, header, true)
152
+			printDeploymentRc(deployment, d.kubeClient, out, header, true)
153 153
 		}
154
-		deploymentsHistory, err := d.client.listDeployments(namespace, labels.Everything())
155
-		if err == nil {
156
-			sorted := rcSorter{}
157
-			sorted = append(sorted, deploymentsHistory.Items...)
158
-			sort.Sort(sorted)
159
-			for _, item := range sorted {
160
-				if item.Name != deploymentName && deploymentConfig.Name == deployutil.DeploymentConfigNameFor(&item) {
161
-					header := fmt.Sprintf("Deployment #%d", deployutil.DeploymentVersionFor(&item))
162
-					printDeploymentRc(&item, d.client, out, header, false)
154
+		// We don't show the deployment history when running `oc rollback --dry-run`.
155
+		if d.config == nil {
156
+			deploymentsHistory, err := d.kubeClient.ReplicationControllers(namespace).List(kapi.ListOptions{LabelSelector: labels.Everything()})
157
+			if err == nil {
158
+				sorted := deploymentsHistory.Items
159
+				sort.Sort(sort.Reverse(rcutils.OverlappingControllers(sorted)))
160
+				for _, item := range sorted {
161
+					if item.Name != deploymentName && deploymentConfig.Name == deployutil.DeploymentConfigNameFor(&item) {
162
+						header := fmt.Sprintf("Deployment #%d", deployutil.DeploymentVersionFor(&item))
163
+						printDeploymentRc(&item, d.kubeClient, out, header, false)
164
+					}
163 165
 				}
164 166
 			}
165 167
 		}
166 168
 
167
-		if events != nil {
169
+		// Events
170
+		if events, err := d.kubeClient.Events(deploymentConfig.Namespace).Search(deploymentConfig); err == nil && events != nil {
168 171
 			fmt.Fprintln(out)
169 172
 			kctl.DescribeEvents(events, out)
170 173
 		}
... ...
@@ -271,7 +210,8 @@ func printTriggers(triggers []deployapi.DeploymentTriggerPolicy, w *tabwriter.Wr
271 271
 	formatString(w, "Triggers", desc)
272 272
 }
273 273
 
274
-func printDeploymentConfigSpec(spec deployapi.DeploymentConfigSpec, w *tabwriter.Writer) error {
274
+func printDeploymentConfigSpec(kc kclient.Interface, dc deployapi.DeploymentConfig, w *tabwriter.Writer) error {
275
+	spec := dc.Spec
275 276
 	// Selector
276 277
 	formatString(w, "Selector", formatLabels(spec.Selector))
277 278
 
... ...
@@ -282,6 +222,9 @@ func printDeploymentConfigSpec(spec deployapi.DeploymentConfigSpec, w *tabwriter
282 282
 	}
283 283
 	formatString(w, "Replicas", fmt.Sprintf("%d%s", spec.Replicas, test))
284 284
 
285
+	// Autoscaling info
286
+	printAutoscalingInfo(deployapi.Resource("DeploymentConfig"), dc.Namespace, dc.Name, kc, w)
287
+
285 288
 	// Triggers
286 289
 	printTriggers(spec.Triggers, w)
287 290
 
... ...
@@ -296,7 +239,33 @@ func printDeploymentConfigSpec(spec deployapi.DeploymentConfigSpec, w *tabwriter
296 296
 	return nil
297 297
 }
298 298
 
299
-func printDeploymentRc(deployment *kapi.ReplicationController, client deploymentDescriberClient, w io.Writer, header string, verbose bool) error {
299
+// TODO: Move this upstream
300
+func printAutoscalingInfo(res unversioned.GroupResource, namespace, name string, kclient kclient.Interface, w *tabwriter.Writer) {
301
+	hpaList, err := kclient.Extensions().HorizontalPodAutoscalers(namespace).List(kapi.ListOptions{LabelSelector: labels.Everything()})
302
+	if err != nil {
303
+		return
304
+	}
305
+
306
+	scaledBy := []extensions.HorizontalPodAutoscaler{}
307
+	for _, hpa := range hpaList.Items {
308
+		if hpa.Spec.ScaleRef.Name == name && hpa.Spec.ScaleRef.Kind == res.String() {
309
+			scaledBy = append(scaledBy, hpa)
310
+		}
311
+	}
312
+
313
+	for _, hpa := range scaledBy {
314
+		cpuUtil := ""
315
+		if hpa.Spec.CPUUtilization != nil {
316
+			cpuUtil = fmt.Sprintf(", triggered at %d%% CPU usage", hpa.Spec.CPUUtilization.TargetPercentage)
317
+		}
318
+		fmt.Fprintf(w, "Autoscaling:\tbetween %d and %d replicas%s\n", *hpa.Spec.MinReplicas, hpa.Spec.MaxReplicas, cpuUtil)
319
+		// TODO: Print a warning in case of multiple hpas.
320
+		// Related oc status PR: https://github.com/openshift/origin/pull/7799
321
+		break
322
+	}
323
+}
324
+
325
+func printDeploymentRc(deployment *kapi.ReplicationController, kubeClient kclient.Interface, w io.Writer, header string, verbose bool) error {
300 326
 	if len(header) > 0 {
301 327
 		fmt.Fprintf(w, "%v:\n", header)
302 328
 	}
... ...
@@ -312,7 +281,7 @@ func printDeploymentRc(deployment *kapi.ReplicationController, client deployment
312 312
 	if verbose {
313 313
 		fmt.Fprintf(w, "\tSelector:\t%s\n", formatLabels(deployment.Spec.Selector))
314 314
 		fmt.Fprintf(w, "\tLabels:\t%s\n", formatLabels(deployment.Labels))
315
-		running, waiting, succeeded, failed, err := getPodStatusForDeployment(deployment, client)
315
+		running, waiting, succeeded, failed, err := getPodStatusForDeployment(deployment, kubeClient)
316 316
 		if err != nil {
317 317
 			return err
318 318
 		}
... ...
@@ -322,8 +291,8 @@ func printDeploymentRc(deployment *kapi.ReplicationController, client deployment
322 322
 	return nil
323 323
 }
324 324
 
325
-func getPodStatusForDeployment(deployment *kapi.ReplicationController, client deploymentDescriberClient) (running, waiting, succeeded, failed int, err error) {
326
-	rcPods, err := client.listPods(deployment.Namespace, labels.SelectorFromSet(deployment.Spec.Selector))
325
+func getPodStatusForDeployment(deployment *kapi.ReplicationController, kubeClient kclient.Interface) (running, waiting, succeeded, failed int, err error) {
326
+	rcPods, err := kubeClient.Pods(deployment.Namespace).List(kapi.ListOptions{LabelSelector: labels.Set(deployment.Spec.Selector).AsSelector()})
327 327
 	if err != nil {
328 328
 		return
329 329
 	}
... ...
@@ -343,31 +312,17 @@ func getPodStatusForDeployment(deployment *kapi.ReplicationController, client de
343 343
 }
344 344
 
345 345
 type LatestDeploymentsDescriber struct {
346
-	count  int
347
-	client deploymentDescriberClient
346
+	count      int
347
+	osClient   client.Interface
348
+	kubeClient kclient.Interface
348 349
 }
349 350
 
350 351
 // NewLatestDeploymentsDescriber lists the latest deployments limited to "count". In case count == -1, list back to the last successful.
351 352
 func NewLatestDeploymentsDescriber(client client.Interface, kclient kclient.Interface, count int) *LatestDeploymentsDescriber {
352 353
 	return &LatestDeploymentsDescriber{
353
-		count: count,
354
-		client: &genericDeploymentDescriberClient{
355
-			getDeploymentConfigFunc: func(namespace, name string) (*deployapi.DeploymentConfig, error) {
356
-				return client.DeploymentConfigs(namespace).Get(name)
357
-			},
358
-			getDeploymentFunc: func(namespace, name string) (*kapi.ReplicationController, error) {
359
-				return kclient.ReplicationControllers(namespace).Get(name)
360
-			},
361
-			listDeploymentsFunc: func(namespace string, selector labels.Selector) (*kapi.ReplicationControllerList, error) {
362
-				return kclient.ReplicationControllers(namespace).List(kapi.ListOptions{LabelSelector: selector})
363
-			},
364
-			listPodsFunc: func(namespace string, selector labels.Selector) (*kapi.PodList, error) {
365
-				return kclient.Pods(namespace).List(kapi.ListOptions{LabelSelector: selector})
366
-			},
367
-			listEventsFunc: func(deploymentConfig *deployapi.DeploymentConfig) (*kapi.EventList, error) {
368
-				return kclient.Events(deploymentConfig.Namespace).Search(deploymentConfig)
369
-			},
370
-		},
354
+		count:      count,
355
+		osClient:   client,
356
+		kubeClient: kclient,
371 357
 	}
372 358
 }
373 359
 
... ...
@@ -375,21 +330,21 @@ func NewLatestDeploymentsDescriber(client client.Interface, kclient kclient.Inte
375 375
 func (d *LatestDeploymentsDescriber) Describe(namespace, name string) (string, error) {
376 376
 	var f formatter
377 377
 
378
-	config, err := d.client.getDeploymentConfig(namespace, name)
378
+	config, err := d.osClient.DeploymentConfigs(namespace).Get(name)
379 379
 	if err != nil {
380 380
 		return "", err
381 381
 	}
382 382
 
383 383
 	var deployments []kapi.ReplicationController
384 384
 	if d.count == -1 || d.count > 1 {
385
-		list, err := d.client.listDeployments(namespace, labels.Everything())
385
+		list, err := d.kubeClient.ReplicationControllers(namespace).List(kapi.ListOptions{LabelSelector: labels.Set(config.Spec.Selector).AsSelector()})
386 386
 		if err != nil && !kerrors.IsNotFound(err) {
387 387
 			return "", err
388 388
 		}
389 389
 		deployments = list.Items
390 390
 	} else {
391 391
 		deploymentName := deployutil.LatestDeploymentNameForConfig(config)
392
-		deployment, err := d.client.getDeployment(config.Namespace, deploymentName)
392
+		deployment, err := d.kubeClient.ReplicationControllers(config.Namespace).Get(deploymentName)
393 393
 		if err != nil && !kerrors.IsNotFound(err) {
394 394
 			return "", err
395 395
 		}
... ...
@@ -416,15 +371,3 @@ func (d *LatestDeploymentsDescriber) Describe(namespace, name string) (string, e
416 416
 		return nil
417 417
 	})
418 418
 }
419
-
420
-type rcSorter []kapi.ReplicationController
421
-
422
-func (s rcSorter) Len() int {
423
-	return len(s)
424
-}
425
-func (s rcSorter) Less(i, j int) bool {
426
-	return s[i].CreationTimestamp.Unix() > s[j].CreationTimestamp.Unix()
427
-}
428
-func (s rcSorter) Swap(i, j int) {
429
-	s[i], s[j] = s[j], s[i]
430
-}
... ...
@@ -37,7 +37,7 @@ func describerMap(c *client.Client, kclient kclient.Interface, host string) map[
37 37
 	m := map[unversioned.GroupKind]kctl.Describer{
38 38
 		buildapi.Kind("Build"):                        &BuildDescriber{c, kclient},
39 39
 		buildapi.Kind("BuildConfig"):                  &BuildConfigDescriber{c, host},
40
-		deployapi.Kind("DeploymentConfig"):            NewDeploymentConfigDescriber(c, kclient),
40
+		deployapi.Kind("DeploymentConfig"):            &DeploymentConfigDescriber{c, kclient, nil},
41 41
 		authorizationapi.Kind("Identity"):             &IdentityDescriber{c},
42 42
 		imageapi.Kind("Image"):                        &ImageDescriber{c},
43 43
 		imageapi.Kind("ImageStream"):                  &ImageStreamDescriber{c},
... ...
@@ -13,7 +13,7 @@ import (
13 13
 	"k8s.io/kubernetes/pkg/api/unversioned"
14 14
 	ktestclient "k8s.io/kubernetes/pkg/client/unversioned/testclient"
15 15
 	"k8s.io/kubernetes/pkg/kubectl"
16
-	"k8s.io/kubernetes/pkg/labels"
16
+	"k8s.io/kubernetes/pkg/runtime"
17 17
 
18 18
 	api "github.com/openshift/origin/pkg/api"
19 19
 	authorizationapi "github.com/openshift/origin/pkg/authorization/api"
... ...
@@ -147,27 +147,28 @@ func TestDeploymentConfigDescriber(t *testing.T) {
147 147
 	config := deployapitest.OkDeploymentConfig(1)
148 148
 	deployment, _ := deployutil.MakeDeployment(config, kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion))
149 149
 	podList := &kapi.PodList{}
150
-	eventList := &kapi.EventList{}
151
-	deploymentList := &kapi.ReplicationControllerList{}
150
+
151
+	fake := &testclient.Fake{}
152
+	fake.PrependReactor("get", "deploymentconfigs", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
153
+		return true, config, nil
154
+	})
155
+	kFake := &ktestclient.Fake{}
156
+	kFake.PrependReactor("get", "replicationcontrollers", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
157
+		return true, deployment, nil
158
+	})
159
+	kFake.PrependReactor("list", "replicationcontrollers", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
160
+		return true, &kapi.ReplicationControllerList{}, nil
161
+	})
162
+	kFake.PrependReactor("list", "pods", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
163
+		return true, podList, nil
164
+	})
165
+	kFake.PrependReactor("list", "events", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
166
+		return true, &kapi.EventList{}, nil
167
+	})
152 168
 
153 169
 	d := &DeploymentConfigDescriber{
154
-		client: &genericDeploymentDescriberClient{
155
-			getDeploymentConfigFunc: func(namespace, name string) (*deployapi.DeploymentConfig, error) {
156
-				return config, nil
157
-			},
158
-			getDeploymentFunc: func(namespace, name string) (*kapi.ReplicationController, error) {
159
-				return deployment, nil
160
-			},
161
-			listDeploymentsFunc: func(namespace string, selector labels.Selector) (*kapi.ReplicationControllerList, error) {
162
-				return deploymentList, nil
163
-			},
164
-			listPodsFunc: func(namespace string, selector labels.Selector) (*kapi.PodList, error) {
165
-				return podList, nil
166
-			},
167
-			listEventsFunc: func(deploymentConfig *deployapi.DeploymentConfig) (*kapi.EventList, error) {
168
-				return eventList, nil
169
-			},
170
-		},
170
+		osClient:   fake,
171
+		kubeClient: kFake,
171 172
 	}
172 173
 
173 174
 	describe := func() {
... ...
@@ -129,6 +129,7 @@ func FormatRelativeTime(t time.Time) string {
129 129
 
130 130
 func formatMeta(out *tabwriter.Writer, m api.ObjectMeta) {
131 131
 	formatString(out, "Name", m.Name)
132
+	formatString(out, "Namespace", m.Namespace)
132 133
 	if !m.CreationTimestamp.IsZero() {
133 134
 		formatTime(out, "Created", m.CreationTimestamp.Time)
134 135
 	}