Skip to content

Commit 9787352

Browse files
authored
Support wide output format for get commands (-o wide) (#3129)
* Support wide output format for get commands (-o wide) * Add a case statement for OutputFormatWide type * Move REFERRED BY ROUTES to wide format * Move REFERRED BY ROUTES to wide format
1 parent e1521e5 commit 9787352

14 files changed

+378
-47
lines changed

gwctl/cmd/subcommand.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ func runGetOrDescribeBackends(f cmdutils.Factory, o *getOrDescribeOptions) {
349349
realClock := clock.RealClock{}
350350
backendsPrinter := &printer.BackendsPrinter{Writer: o.out, Clock: realClock}
351351
if o.cmdName == commandNameGet {
352-
backendsPrinter.Print(resourceModel)
352+
printer.Print(backendsPrinter, resourceModel, o.outputFormat)
353353
} else {
354354
backendsPrinter.PrintDescribeView(resourceModel)
355355
}

gwctl/pkg/printer/backends.go

+35-24
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,20 @@ type BackendsPrinter struct {
3434
Clock clock.Clock
3535
}
3636

37-
func (bp *BackendsPrinter) Print(resourceModel *resourcediscovery.ResourceModel) {
37+
func (bp *BackendsPrinter) GetPrintableNodes(resourceModel *resourcediscovery.ResourceModel) []NodeResource {
38+
return NodeResources(maps.Values(resourceModel.GatewayClasses))
39+
}
40+
41+
func (bp *BackendsPrinter) PrintTable(resourceModel *resourcediscovery.ResourceModel, wide bool) {
42+
var columnNames []string
43+
if wide {
44+
columnNames = []string{"NAMESPACE", "NAME", "TYPE", "AGE", "REFERRED BY ROUTES", "POLICIES"}
45+
} else {
46+
columnNames = []string{"NAMESPACE", "NAME", "TYPE", "AGE"}
47+
}
48+
3849
table := &Table{
39-
ColumnNames: []string{"NAMESPACE", "NAME", "TYPE", "REFERRED BY ROUTES", "AGE", "POLICIES"},
50+
ColumnNames: columnNames,
4051
UseSeparator: false,
4152
}
4253

@@ -50,38 +61,38 @@ func (bp *BackendsPrinter) Print(resourceModel *resourcediscovery.ResourceModel)
5061
sortedHTTPRouteNodes := SortByString(httpRouteNodes)
5162
totalRoutes := len(sortedHTTPRouteNodes)
5263

53-
var referredByRoutes string
54-
if totalRoutes == 0 {
55-
referredByRoutes = "None"
56-
} else {
57-
var routes []string
58-
for i, httpRouteNode := range sortedHTTPRouteNodes {
59-
if i < 2 {
60-
namespacedName := client.ObjectKeyFromObject(httpRouteNode.HTTPRoute).String()
61-
routes = append(routes, namespacedName)
62-
} else {
63-
break
64-
}
65-
}
66-
referredByRoutes = strings.Join(routes, ", ")
67-
if totalRoutes > 2 {
68-
referredByRoutes += fmt.Sprintf(" + %d more", totalRoutes-2)
69-
}
70-
}
71-
7264
namespace := backend.GetNamespace()
7365
name := backend.GetName()
7466
backendType := backend.GetKind()
7567
age := duration.HumanDuration(bp.Clock.Since(backend.GetCreationTimestamp().Time))
76-
policiesCount := fmt.Sprintf("%d", len(backendNode.Policies))
7768

7869
row := []string{
7970
namespace,
8071
name,
8172
backendType,
82-
referredByRoutes,
8373
age,
84-
policiesCount,
74+
}
75+
if wide {
76+
var referredByRoutes string
77+
if totalRoutes == 0 {
78+
referredByRoutes = "None"
79+
} else {
80+
var routes []string
81+
for i, httpRouteNode := range sortedHTTPRouteNodes {
82+
if i < 2 {
83+
namespacedName := client.ObjectKeyFromObject(httpRouteNode.HTTPRoute).String()
84+
routes = append(routes, namespacedName)
85+
} else {
86+
break
87+
}
88+
}
89+
referredByRoutes = strings.Join(routes, ", ")
90+
if totalRoutes > 2 {
91+
referredByRoutes += fmt.Sprintf(" + %d more", totalRoutes-2)
92+
}
93+
}
94+
policiesCount := fmt.Sprintf("%d", len(backendNode.Policies))
95+
row = append(row, referredByRoutes, policiesCount)
8596
}
8697
table.Rows = append(table.Rows, row)
8798
}

gwctl/pkg/printer/backends_test.go

+21-4
Original file line numberDiff line numberDiff line change
@@ -196,15 +196,32 @@ func TestBackendsPrinter_Print(t *testing.T) {
196196
Clock: fakeClock,
197197
}
198198

199-
bp.Print(resourceModel)
199+
bp.PrintTable(resourceModel, false)
200200

201201
got := buff.String()
202202
want := `
203-
NAMESPACE NAME TYPE REFERRED BY ROUTES AGE POLICIES
204-
ns1 foo-svc-1 Service ns1/foo-httproute-1 3d 1
205-
ns1 foo-svc-2 Service ns1/foo-httproute-2, ns1/foo-httproute-3 + 2 more 2d 0
203+
NAMESPACE NAME TYPE AGE
204+
ns1 foo-svc-1 Service 3d
205+
ns1 foo-svc-2 Service 2d
206206
`
207207
if diff := cmp.Diff(common.YamlString(want), common.YamlString(got), common.YamlStringTransformer); diff != "" {
208208
t.Errorf("Unexpected diff\ngot=\n%v\nwant=\n%v\ndiff (-want +got)=\n%v", got, want, diff)
209209
}
210+
211+
buff.Reset()
212+
nsp2 := &BackendsPrinter{
213+
Writer: buff,
214+
Clock: fakeClock,
215+
}
216+
nsp2.PrintTable(resourceModel, true)
217+
218+
got2 := buff.String()
219+
want2 := `
220+
NAMESPACE NAME TYPE AGE REFERRED BY ROUTES POLICIES
221+
ns1 foo-svc-1 Service 3d ns1/foo-httproute-1 1
222+
ns1 foo-svc-2 Service 2d ns1/foo-httproute-2, ns1/foo-httproute-3 + 2 more 0
223+
`
224+
if diff := cmp.Diff(common.YamlString(want2), common.YamlString(got2), common.YamlStringTransformer); diff != "" {
225+
t.Errorf("Unexpected diff\ngot=\n%v\nwant=\n%v\ndiff (-want +got)=\n%v", got2, want2, diff)
226+
}
210227
}

gwctl/pkg/printer/gatewayclasses.go

+12-2
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,15 @@ func (gcp *GatewayClassesPrinter) GetPrintableNodes(resourceModel *resourcedisco
3838
return NodeResources(maps.Values(resourceModel.GatewayClasses))
3939
}
4040

41-
func (gcp *GatewayClassesPrinter) PrintTable(resourceModel *resourcediscovery.ResourceModel) {
41+
func (gcp *GatewayClassesPrinter) PrintTable(resourceModel *resourcediscovery.ResourceModel, wide bool) {
42+
var columnNames []string
43+
if wide {
44+
columnNames = []string{"NAME", "CONTROLLER", "ACCEPTED", "AGE", "GATEWAYS"}
45+
} else {
46+
columnNames = []string{"NAME", "CONTROLLER", "ACCEPTED", "AGE"}
47+
}
4248
table := &Table{
43-
ColumnNames: []string{"NAME", "CONTROLLER", "ACCEPTED", "AGE"},
49+
ColumnNames: columnNames,
4450
UseSeparator: false,
4551
}
4652

@@ -62,6 +68,10 @@ func (gcp *GatewayClassesPrinter) PrintTable(resourceModel *resourcediscovery.Re
6268
accepted,
6369
age,
6470
}
71+
if wide {
72+
gatewayCount := fmt.Sprintf("%d", len(gatewayClassNode.Gateways))
73+
row = append(row, gatewayCount)
74+
}
6575
table.Rows = append(table.Rows, row)
6676
}
6777

gwctl/pkg/printer/gatewayclasses_test.go

+49-1
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,37 @@ func TestGatewayClassesPrinter_PrintTable(t *testing.T) {
9999
},
100100
},
101101
},
102+
&gatewayv1.Gateway{
103+
ObjectMeta: metav1.ObjectMeta{
104+
Name: "bar-gateway",
105+
CreationTimestamp: metav1.Time{
106+
Time: fakeClock.Now().Add(-3 * time.Second),
107+
},
108+
},
109+
Spec: gatewayv1.GatewaySpec{
110+
GatewayClassName: "bar-com-internal-gateway-class",
111+
Listeners: []gatewayv1.Listener{
112+
{
113+
Name: gatewayv1.SectionName("http-8443"),
114+
Protocol: gatewayv1.HTTPProtocolType,
115+
Port: gatewayv1.PortNumber(8443),
116+
},
117+
},
118+
},
119+
Status: gatewayv1.GatewayStatus{
120+
Addresses: []gatewayv1.GatewayStatusAddress{
121+
{
122+
Value: "10.11.12.13",
123+
},
124+
},
125+
Conditions: []metav1.Condition{
126+
{
127+
Type: "Programmed",
128+
Status: "Unknown",
129+
},
130+
},
131+
},
132+
},
102133
}
103134

104135
k8sClients := common.MustClientsForTest(t, objects...)
@@ -117,7 +148,7 @@ func TestGatewayClassesPrinter_PrintTable(t *testing.T) {
117148
Writer: buff,
118149
Clock: fakeClock,
119150
}
120-
Print(gcp, resourceModel, utils.OutputFormatTable)
151+
gcp.PrintTable(resourceModel, false)
121152

122153
got := buff.String()
123154
want := `
@@ -129,6 +160,23 @@ foo-com-internal-gateway-class foo.com/internal-gateway-class Unknown 24m
129160
if diff := cmp.Diff(common.YamlString(want), common.YamlString(got), common.YamlStringTransformer); diff != "" {
130161
t.Errorf("Unexpected diff\ngot=\n%v\nwant=\n%v\ndiff (-want +got)=\n%v", got, want, diff)
131162
}
163+
buff.Reset()
164+
gcp2 := &GatewayClassesPrinter{
165+
Writer: buff,
166+
Clock: fakeClock,
167+
}
168+
gcp2.PrintTable(resourceModel, true)
169+
170+
got2 := buff.String()
171+
want2 := `
172+
NAME CONTROLLER ACCEPTED AGE GATEWAYS
173+
bar-com-internal-gateway-class bar.baz/internal-gateway-class True 365d 1
174+
foo-com-external-gateway-class foo.com/external-gateway-class False 100d 0
175+
foo-com-internal-gateway-class foo.com/internal-gateway-class Unknown 24m 0
176+
`
177+
if diff := cmp.Diff(common.YamlString(want2), common.YamlString(got2), common.YamlStringTransformer); diff != "" {
178+
t.Errorf("Unexpected diff\ngot=\n%v\nwant=\n%v\ndiff (-want +got)=\n%v", got2, want2, diff)
179+
}
132180
}
133181

134182
func TestGatewayClassesPrinter_PrintDescribeView(t *testing.T) {

gwctl/pkg/printer/gateways.go

+13-2
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,15 @@ func (gp *GatewaysPrinter) GetPrintableNodes(resourceModel *resourcediscovery.Re
3939
return NodeResources(maps.Values(resourceModel.Gateways))
4040
}
4141

42-
func (gp *GatewaysPrinter) PrintTable(resourceModel *resourcediscovery.ResourceModel) {
42+
func (gp *GatewaysPrinter) PrintTable(resourceModel *resourcediscovery.ResourceModel, wide bool) {
43+
var columnNames []string
44+
if wide {
45+
columnNames = []string{"NAMESPACE", "NAME", "CLASS", "ADDRESSES", "PORTS", "PROGRAMMED", "AGE", "POLICIES", "HTTPROUTES"}
46+
} else {
47+
columnNames = []string{"NAMESPACE", "NAME", "CLASS", "ADDRESSES", "PORTS", "PROGRAMMED", "AGE"}
48+
}
4349
table := &Table{
44-
ColumnNames: []string{"NAMESPACE", "NAME", "CLASS", "ADDRESSES", "PORTS", "PROGRAMMED", "AGE"},
50+
ColumnNames: columnNames,
4551
UseSeparator: false,
4652
}
4753

@@ -82,6 +88,11 @@ func (gp *GatewaysPrinter) PrintTable(resourceModel *resourcediscovery.ResourceM
8288
programmedStatus,
8389
age,
8490
}
91+
if wide {
92+
policiesCount := fmt.Sprintf("%d", len(gatewayNode.Policies))
93+
httpRoutesCount := fmt.Sprintf("%d", len(gatewayNode.HTTPRoutes))
94+
row = append(row, policiesCount, httpRoutesCount)
95+
}
8596
table.Rows = append(table.Rows, row)
8697
}
8798

gwctl/pkg/printer/gateways_test.go

+103-1
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,90 @@ func TestGatewaysPrinter_PrintTable(t *testing.T) {
176176
},
177177
},
178178
},
179+
&gatewayv1.HTTPRoute{
180+
TypeMeta: metav1.TypeMeta{
181+
Kind: "HTTPRoute",
182+
},
183+
ObjectMeta: metav1.ObjectMeta{
184+
Name: "foo-httproute",
185+
},
186+
Spec: gatewayv1.HTTPRouteSpec{
187+
CommonRouteSpec: gatewayv1.CommonRouteSpec{
188+
ParentRefs: []gatewayv1.ParentReference{{
189+
Kind: common.PtrTo(gatewayv1.Kind("Gateway")),
190+
Group: common.PtrTo(gatewayv1.Group("gateway.networking.k8s.io")),
191+
Name: "abc-gateway-12345",
192+
}},
193+
},
194+
},
195+
},
196+
197+
&apiextensionsv1.CustomResourceDefinition{
198+
ObjectMeta: metav1.ObjectMeta{
199+
Name: "healthcheckpolicies.foo.com",
200+
Labels: map[string]string{
201+
gatewayv1alpha2.PolicyLabelKey: "inherited",
202+
},
203+
},
204+
Spec: apiextensionsv1.CustomResourceDefinitionSpec{
205+
Scope: apiextensionsv1.ClusterScoped,
206+
Group: "foo.com",
207+
Versions: []apiextensionsv1.CustomResourceDefinitionVersion{{Name: "v1"}},
208+
Names: apiextensionsv1.CustomResourceDefinitionNames{
209+
Plural: "healthcheckpolicies",
210+
Kind: "HealthCheckPolicy",
211+
},
212+
},
213+
},
214+
&unstructured.Unstructured{
215+
Object: map[string]interface{}{
216+
"apiVersion": "foo.com/v1",
217+
"kind": "HealthCheckPolicy",
218+
"metadata": map[string]interface{}{
219+
"name": "health-check-gatewayclass",
220+
},
221+
"spec": map[string]interface{}{
222+
"override": map[string]interface{}{
223+
"key1": "value-parent-1",
224+
"key3": "value-parent-3",
225+
"key5": "value-parent-5",
226+
},
227+
"default": map[string]interface{}{
228+
"key2": "value-parent-2",
229+
"key4": "value-parent-4",
230+
},
231+
"targetRef": map[string]interface{}{
232+
"group": "gateway.networking.k8s.io",
233+
"kind": "GatewayClass",
234+
"name": "regional-internal-class",
235+
},
236+
},
237+
},
238+
},
239+
&unstructured.Unstructured{
240+
Object: map[string]interface{}{
241+
"apiVersion": "foo.com/v1",
242+
"kind": "HealthCheckPolicy",
243+
"metadata": map[string]interface{}{
244+
"name": "health-check-gateway",
245+
},
246+
"spec": map[string]interface{}{
247+
"override": map[string]interface{}{
248+
"key1": "value-child-1",
249+
},
250+
"default": map[string]interface{}{
251+
"key2": "value-child-2",
252+
"key5": "value-child-5",
253+
},
254+
"targetRef": map[string]interface{}{
255+
"group": "gateway.networking.k8s.io",
256+
"kind": "Gateway",
257+
"name": "random-gateway",
258+
"namespace": "default",
259+
},
260+
},
261+
},
262+
},
179263
}
180264

181265
k8sClients := common.MustClientsForTest(t, objects...)
@@ -194,7 +278,7 @@ func TestGatewaysPrinter_PrintTable(t *testing.T) {
194278
Writer: buff,
195279
Clock: fakeClock,
196280
}
197-
gp.PrintTable(resourceModel)
281+
gp.PrintTable(resourceModel, false)
198282

199283
got := buff.String()
200284
want := `
@@ -207,6 +291,24 @@ default random-gateway regional-internal-class 10.11.12.13
207291
if diff := cmp.Diff(common.YamlString(want), common.YamlString(got), common.YamlStringTransformer); diff != "" {
208292
t.Errorf("Unexpected diff\ngot=\n%v\nwant=\n%v\ndiff (-want +got)=\n%v", got, want, diff)
209293
}
294+
295+
buff.Reset()
296+
nsp2 := &GatewaysPrinter{
297+
Writer: buff,
298+
Clock: fakeClock,
299+
}
300+
nsp2.PrintTable(resourceModel, true)
301+
302+
got2 := buff.String()
303+
want2 := `
304+
NAMESPACE NAME CLASS ADDRESSES PORTS PROGRAMMED AGE POLICIES HTTPROUTES
305+
default abc-gateway-12345 internal-class 192.168.100.5 443,8080 False 20d 0 1
306+
default demo-gateway-2 external-class 10.0.0.1,10.0.0.2 + 1 more 80 True 5d 0 0
307+
default random-gateway regional-internal-class 10.11.12.13 8443 Unknown 3s 1 0
308+
`
309+
if diff := cmp.Diff(common.YamlString(want2), common.YamlString(got2), common.YamlStringTransformer); diff != "" {
310+
t.Errorf("Unexpected diff\ngot=\n%v\nwant=\n%v\ndiff (-want +got)=\n%v", got2, want2, diff)
311+
}
210312
}
211313

212314
func TestGatewaysPrinter_PrintDescribeView(t *testing.T) {

0 commit comments

Comments
 (0)