Skip to content

Commit b4f0307

Browse files
authored
Implement gwctl get gatewayclass (#2847)
1 parent efa7f51 commit b4f0307

File tree

3 files changed

+159
-7
lines changed

3 files changed

+159
-7
lines changed

gwctl/pkg/cmd/get/get.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ func NewGetCommand(params *utils.CmdParams) *cobra.Command {
3838
flags := &getFlags{}
3939

4040
cmd := &cobra.Command{
41-
Use: "get {gateways|policies|policycrds|httproutes}",
41+
Use: "get {gateways|gatewayclasses|policies|policycrds|httproutes}",
4242
Short: "Display one or many resources",
4343
Args: cobra.ExactArgs(1),
4444
Run: func(cmd *cobra.Command, args []string) {
@@ -64,7 +64,8 @@ func runGet(args []string, params *utils.CmdParams, flags *getFlags) {
6464
}
6565
realClock := clock.RealClock{}
6666
gwPrinter := &printer.GatewaysPrinter{Out: params.Out, Clock: realClock}
67-
policiesPrinter := &printer.PoliciesPrinter{Out: params.Out, Clock: realClock}
67+
gwcPrinter := &printer.GatewayClassesPrinter{Out: params.Out, Clock: realClock}
68+
policiesPrinter := &printer.PoliciesPrinter{Out: params.Out}
6869
httpRoutesPrinter := &printer.HTTPRoutesPrinter{Out: params.Out, Clock: realClock}
6970

7071
switch kind {
@@ -79,6 +80,18 @@ func runGet(args []string, params *utils.CmdParams, flags *getFlags) {
7980
}
8081
gwPrinter.Print(resourceModel)
8182

83+
case "gatewayclass", "gatewayclasses":
84+
filter := resourcediscovery.Filter{Namespace: ns}
85+
if len(args) > 1 {
86+
filter.Name = args[1]
87+
}
88+
resourceModel, err := discoverer.DiscoverResourcesForGatewayClass(filter)
89+
if err != nil {
90+
fmt.Fprintf(os.Stderr, "failed to discover GatewayClass resources: %v\n", err)
91+
os.Exit(1)
92+
}
93+
gwcPrinter.Print(resourceModel)
94+
8295
case "policy", "policies":
8396
list := params.PolicyManager.GetPolicies()
8497
policiesPrinter.Print(list)

gwctl/pkg/printer/gatewayclasses.go

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,21 @@ package printer
1919
import (
2020
"fmt"
2121
"io"
22-
23-
"sigs.k8s.io/yaml"
22+
"sort"
23+
"strings"
24+
"text/tabwriter"
2425

2526
"sigs.k8s.io/gateway-api/gwctl/pkg/policymanager"
2627
"sigs.k8s.io/gateway-api/gwctl/pkg/resourcediscovery"
28+
"sigs.k8s.io/yaml"
29+
30+
"k8s.io/apimachinery/pkg/util/duration"
31+
"k8s.io/utils/clock"
2732
)
2833

2934
type GatewayClassesPrinter struct {
30-
Out io.Writer
35+
Out io.Writer
36+
Clock clock.Clock
3137
}
3238

3339
type gatewayClassDescribeView struct {
@@ -39,6 +45,44 @@ type gatewayClassDescribeView struct {
3945
DirectlyAttachedPolicies []policymanager.ObjRef `json:",omitempty"`
4046
}
4147

48+
func (gcp *GatewayClassesPrinter) Print(model *resourcediscovery.ResourceModel) {
49+
tw := tabwriter.NewWriter(gcp.Out, 0, 0, 2, ' ', 0)
50+
row := []string{"NAME", "CONTROLLER", "ACCEPTED", "AGE"}
51+
tw.Write([]byte(strings.Join(row, "\t") + "\n"))
52+
53+
gatewayClassNodes := make([]*resourcediscovery.GatewayClassNode, 0, len(model.GatewayClasses))
54+
for _, gatewayClassNode := range model.GatewayClasses {
55+
gatewayClassNodes = append(gatewayClassNodes, gatewayClassNode)
56+
}
57+
58+
sort.Slice(gatewayClassNodes, func(i, j int) bool {
59+
if gatewayClassNodes[i].GatewayClass.GetName() != gatewayClassNodes[j].GatewayClass.GetName() {
60+
return gatewayClassNodes[i].GatewayClass.GetName() < gatewayClassNodes[j].GatewayClass.GetName()
61+
}
62+
return string(gatewayClassNodes[i].GatewayClass.Spec.ControllerName) < string(gatewayClassNodes[j].GatewayClass.Spec.ControllerName)
63+
})
64+
65+
for _, gatewayClassNode := range gatewayClassNodes {
66+
accepted := "Unknown"
67+
for _, condition := range gatewayClassNode.GatewayClass.Status.Conditions {
68+
if condition.Type == "Accepted" {
69+
accepted = string(condition.Status)
70+
}
71+
}
72+
73+
age := duration.HumanDuration(gcp.Clock.Since(gatewayClassNode.GatewayClass.GetCreationTimestamp().Time))
74+
75+
row := []string{
76+
gatewayClassNode.GatewayClass.GetName(),
77+
string(gatewayClassNode.GatewayClass.Spec.ControllerName),
78+
accepted,
79+
age,
80+
}
81+
tw.Write([]byte(strings.Join(row, "\t") + "\n"))
82+
}
83+
tw.Flush()
84+
}
85+
4286
func (gcp *GatewayClassesPrinter) PrintDescribeView(resourceModel *resourcediscovery.ResourceModel) {
4387
index := 0
4488
for _, gatewayClassNode := range resourceModel.GatewayClasses {

gwctl/pkg/printer/gatewayclasses_test.go

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,115 @@ package printer
1919
import (
2020
"bytes"
2121
"testing"
22+
"time"
2223

2324
"github.com/google/go-cmp/cmp"
25+
2426
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
2527
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2628
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2729
"k8s.io/apimachinery/pkg/runtime"
30+
testingclock "k8s.io/utils/clock/testing"
31+
2832
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
2933
gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
30-
3134
"sigs.k8s.io/gateway-api/gwctl/pkg/cmd/utils"
3235
"sigs.k8s.io/gateway-api/gwctl/pkg/common"
3336
"sigs.k8s.io/gateway-api/gwctl/pkg/resourcediscovery"
3437
)
3538

39+
func TestGatewayClassesPrinter_Print(t *testing.T) {
40+
fakeClock := testingclock.NewFakeClock(time.Now())
41+
objects := []runtime.Object{
42+
&gatewayv1.GatewayClass{
43+
ObjectMeta: metav1.ObjectMeta{
44+
Name: "bar-com-internal-gateway-class",
45+
CreationTimestamp: metav1.Time{
46+
Time: fakeClock.Now().Add(-365 * 24 * time.Hour),
47+
},
48+
},
49+
Spec: gatewayv1.GatewayClassSpec{
50+
ControllerName: "bar.baz/internal-gateway-class",
51+
},
52+
Status: gatewayv1.GatewayClassStatus{
53+
Conditions: []metav1.Condition{
54+
{
55+
Type: "Accepted",
56+
Status: "True",
57+
},
58+
},
59+
},
60+
},
61+
&gatewayv1.GatewayClass{
62+
ObjectMeta: metav1.ObjectMeta{
63+
Name: "foo-com-external-gateway-class",
64+
CreationTimestamp: metav1.Time{
65+
Time: fakeClock.Now().Add(-100 * 24 * time.Hour),
66+
},
67+
},
68+
Spec: gatewayv1.GatewayClassSpec{
69+
ControllerName: "foo.com/external-gateway-class",
70+
},
71+
Status: gatewayv1.GatewayClassStatus{
72+
Conditions: []metav1.Condition{
73+
{
74+
Type: "Accepted",
75+
Status: "False",
76+
},
77+
},
78+
},
79+
},
80+
&gatewayv1.GatewayClass{
81+
ObjectMeta: metav1.ObjectMeta{
82+
Name: "foo-com-internal-gateway-class",
83+
CreationTimestamp: metav1.Time{
84+
Time: fakeClock.Now().Add(-24 * time.Minute),
85+
},
86+
},
87+
Spec: gatewayv1.GatewayClassSpec{
88+
ControllerName: "foo.com/internal-gateway-class",
89+
},
90+
Status: gatewayv1.GatewayClassStatus{
91+
Conditions: []metav1.Condition{
92+
{
93+
Type: "Accepted",
94+
Status: "Unknown",
95+
},
96+
},
97+
},
98+
},
99+
}
100+
101+
params := utils.MustParamsForTest(t, common.MustClientsForTest(t, objects...))
102+
discoverer := resourcediscovery.Discoverer{
103+
K8sClients: params.K8sClients,
104+
PolicyManager: params.PolicyManager,
105+
}
106+
resourceModel, err := discoverer.DiscoverResourcesForGatewayClass(resourcediscovery.Filter{})
107+
if err != nil {
108+
t.Fatalf("Failed to construct resourceModel: %v", resourceModel)
109+
}
110+
111+
gcp := &GatewayClassesPrinter{
112+
Out: params.Out,
113+
Clock: fakeClock,
114+
}
115+
gcp.Print(resourceModel)
116+
117+
got := params.Out.(*bytes.Buffer).String()
118+
want := `
119+
NAME CONTROLLER ACCEPTED AGE
120+
bar-com-internal-gateway-class bar.baz/internal-gateway-class True 365d
121+
foo-com-external-gateway-class foo.com/external-gateway-class False 100d
122+
foo-com-internal-gateway-class foo.com/internal-gateway-class Unknown 24m
123+
`
124+
if diff := cmp.Diff(common.YamlString(want), common.YamlString(got), common.YamlStringTransformer); diff != "" {
125+
t.Errorf("Unexpected diff\ngot=\n%v\nwant=\n%v\ndiff (-want +got)=\n%v", got, want, diff)
126+
}
127+
}
128+
36129
func TestGatewayClassesPrinter_PrintDescribeView(t *testing.T) {
130+
fakeClock := testingclock.NewFakeClock(time.Now())
37131
objects := []runtime.Object{
38132
&gatewayv1.GatewayClass{
39133
ObjectMeta: metav1.ObjectMeta{
@@ -89,7 +183,8 @@ func TestGatewayClassesPrinter_PrintDescribeView(t *testing.T) {
89183
}
90184

91185
gcp := &GatewayClassesPrinter{
92-
Out: params.Out,
186+
Out: params.Out,
187+
Clock: fakeClock,
93188
}
94189
gcp.PrintDescribeView(resourceModel)
95190

0 commit comments

Comments
 (0)