Skip to content

Commit d02abe6

Browse files
authored
Merge pull request #2782 from jongwooo/implement-gwctl-get-gateways
Implement `gwctl get gateways`
2 parents e854f36 + 8929ad7 commit d02abe6

File tree

3 files changed

+140
-6
lines changed

3 files changed

+140
-6
lines changed

gwctl/pkg/cmd/get/get.go

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ func NewGetCommand(params *utils.CmdParams) *cobra.Command {
3636
flags := &getFlags{}
3737

3838
cmd := &cobra.Command{
39-
Use: "get {policies|policycrds|httproutes}",
39+
Use: "get {gateways|policies|policycrds|httproutes}",
4040
Short: "Display one or many resources",
4141
Args: cobra.ExactArgs(1),
4242
Run: func(cmd *cobra.Command, args []string) {
@@ -56,10 +56,26 @@ func runGet(args []string, params *utils.CmdParams, flags *getFlags) {
5656
ns = ""
5757
}
5858

59+
discoverer := resourcediscovery.Discoverer{
60+
K8sClients: params.K8sClients,
61+
PolicyManager: params.PolicyManager,
62+
}
63+
gwPrinter := &printer.GatewaysPrinter{Out: params.Out}
5964
policiesPrinter := &printer.PoliciesPrinter{Out: params.Out}
6065
httpRoutesPrinter := &printer.HTTPRoutesPrinter{Out: params.Out}
6166

6267
switch kind {
68+
case "gateway", "gateways":
69+
filter := resourcediscovery.Filter{Namespace: ns}
70+
if len(args) > 1 {
71+
filter.Name = args[1]
72+
}
73+
resourceModel, err := discoverer.DiscoverResourcesForGateway(filter)
74+
if err != nil {
75+
panic(err)
76+
}
77+
gwPrinter.Print(resourceModel)
78+
6379
case "policy", "policies":
6480
list := params.PolicyManager.GetPolicies()
6581
policiesPrinter.Print(list)
@@ -69,10 +85,6 @@ func runGet(args []string, params *utils.CmdParams, flags *getFlags) {
6985
policiesPrinter.PrintCRDs(list)
7086

7187
case "httproute", "httproutes":
72-
discoverer := resourcediscovery.Discoverer{
73-
K8sClients: params.K8sClients,
74-
PolicyManager: params.PolicyManager,
75-
}
7688
filter := resourcediscovery.Filter{Namespace: ns}
7789
if len(args) > 1 {
7890
filter.Name = args[1]

gwctl/pkg/printer/gateways.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,17 @@ package printer
1919
import (
2020
"fmt"
2121
"io"
22+
"strconv"
23+
"strings"
24+
"text/tabwriter"
25+
"time"
2226

2327
"sigs.k8s.io/yaml"
2428

2529
"sigs.k8s.io/gateway-api/gwctl/pkg/policymanager"
2630
"sigs.k8s.io/gateway-api/gwctl/pkg/resourcediscovery"
31+
32+
"k8s.io/apimachinery/pkg/util/duration"
2733
)
2834

2935
type GatewaysPrinter struct {
@@ -40,6 +46,50 @@ type gatewayDescribeView struct {
4046
EffectivePolicies map[policymanager.PolicyCrdID]policymanager.Policy `json:",omitempty"`
4147
}
4248

49+
func (gp *GatewaysPrinter) Print(resourceModel *resourcediscovery.ResourceModel) {
50+
tw := tabwriter.NewWriter(gp.Out, 0, 0, 2, ' ', 0)
51+
row := []string{"NAME", "CLASS", "ADDRESSES", "PORTS", "PROGRAMMED", "AGE"}
52+
tw.Write([]byte(strings.Join(row, "\t") + "\n"))
53+
54+
for _, gatewayNode := range resourceModel.Gateways {
55+
var addresses []string
56+
for _, address := range gatewayNode.Gateway.Status.Addresses {
57+
addresses = append(addresses, address.Value)
58+
}
59+
addressesOutput := strings.Join(addresses, ",")
60+
if cnt := len(addresses); cnt > 2 {
61+
addressesOutput = fmt.Sprintf("%v + %v more", strings.Join(addresses[:2], ","), cnt-2)
62+
}
63+
64+
var ports []string
65+
for _, listener := range gatewayNode.Gateway.Spec.Listeners {
66+
ports = append(ports, strconv.Itoa(int(listener.Port)))
67+
}
68+
portsOutput := strings.Join(ports, ",")
69+
70+
programmedStatus := "Unknown"
71+
for _, condition := range gatewayNode.Gateway.Status.Conditions {
72+
if condition.Type == "Programmed" {
73+
programmedStatus = string(condition.Status)
74+
break
75+
}
76+
}
77+
78+
age := duration.HumanDuration(time.Since(gatewayNode.Gateway.GetCreationTimestamp().Time))
79+
80+
row := []string{
81+
gatewayNode.Gateway.GetName(),
82+
string(gatewayNode.Gateway.Spec.GatewayClassName),
83+
addressesOutput,
84+
portsOutput,
85+
programmedStatus,
86+
age,
87+
}
88+
tw.Write([]byte(strings.Join(row, "\t") + "\n"))
89+
}
90+
tw.Flush()
91+
}
92+
4393
func (gp *GatewaysPrinter) PrintDescribeView(resourceModel *resourcediscovery.ResourceModel) {
4494
index := 0
4595
for _, gatewayNode := range resourceModel.Gateways {

gwctl/pkg/printer/gateways_test.go

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,92 @@ package printer
1919
import (
2020
"bytes"
2121
"testing"
22+
"time"
2223

2324
"github.com/google/go-cmp/cmp"
2425
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
2526
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2627
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2728
"k8s.io/apimachinery/pkg/runtime"
29+
2830
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
2931
gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
30-
3132
"sigs.k8s.io/gateway-api/gwctl/pkg/cmd/utils"
3233
"sigs.k8s.io/gateway-api/gwctl/pkg/common"
3334
"sigs.k8s.io/gateway-api/gwctl/pkg/resourcediscovery"
3435
)
3536

37+
func TestGatewaysPrinter_Print(t *testing.T) {
38+
objects := []runtime.Object{
39+
&gatewayv1.GatewayClass{
40+
ObjectMeta: metav1.ObjectMeta{
41+
Name: "foo-gatewayclass",
42+
},
43+
Spec: gatewayv1.GatewayClassSpec{
44+
ControllerName: "example.net/gateway-controller",
45+
Description: common.PtrTo("random"),
46+
},
47+
},
48+
49+
&gatewayv1.Gateway{
50+
ObjectMeta: metav1.ObjectMeta{
51+
Name: "foo-gateway",
52+
CreationTimestamp: metav1.Time{
53+
Time: time.Now().Add(-time.Second),
54+
},
55+
},
56+
Spec: gatewayv1.GatewaySpec{
57+
GatewayClassName: "foo-gatewayclass",
58+
Listeners: []gatewayv1.Listener{
59+
{
60+
Name: gatewayv1.SectionName("http-1"),
61+
Protocol: gatewayv1.HTTPProtocolType,
62+
Port: gatewayv1.PortNumber(80),
63+
},
64+
},
65+
},
66+
Status: gatewayv1.GatewayStatus{
67+
Addresses: []gatewayv1.GatewayStatusAddress{
68+
{
69+
Value: "10.0.0.1",
70+
},
71+
},
72+
Conditions: []metav1.Condition{
73+
{
74+
Type: "Programmed",
75+
Status: metav1.ConditionTrue,
76+
},
77+
},
78+
},
79+
},
80+
}
81+
82+
params := utils.MustParamsForTest(t, common.MustClientsForTest(t, objects...))
83+
discoverer := resourcediscovery.Discoverer{
84+
K8sClients: params.K8sClients,
85+
PolicyManager: params.PolicyManager,
86+
}
87+
resourceModel, err := discoverer.DiscoverResourcesForGateway(resourcediscovery.Filter{})
88+
if err != nil {
89+
t.Fatalf("Failed to construct resourceModel: %v", resourceModel)
90+
}
91+
92+
gp := &GatewaysPrinter{
93+
Out: params.Out,
94+
}
95+
gp.Print(resourceModel)
96+
97+
got := params.Out.(*bytes.Buffer).String()
98+
want := `
99+
NAME CLASS ADDRESSES PORTS PROGRAMMED AGE
100+
foo-gateway foo-gatewayclass 10.0.0.1 80 True 1s
101+
`
102+
103+
if diff := cmp.Diff(common.YamlString(want), common.YamlString(got), common.YamlStringTransformer); diff != "" {
104+
t.Errorf("Unexpected diff\ngot=\n%v\nwant=\n%v\ndiff (-want +got)=\n%v", got, want, diff)
105+
}
106+
}
107+
36108
func TestGatewaysPrinter_PrintDescribeView(t *testing.T) {
37109
objects := []runtime.Object{
38110
&gatewayv1.GatewayClass{

0 commit comments

Comments
 (0)