Skip to content

Commit 1ba825b

Browse files
authored
gwctl - reorganize and improve error handling (#2825)
* improve error handling Signed-off-by: Navendu Pottekkat <[email protected]> * add file header Signed-off-by: Navendu Pottekkat <[email protected]> * update docs, use local flags Signed-off-by: Navendu Pottekkat <[email protected]> * include logging flags Signed-off-by: Navendu Pottekkat <[email protected]> * add klog flags Signed-off-by: Navendu Pottekkat <[email protected]> --------- Signed-off-by: Navendu Pottekkat <[email protected]>
1 parent b4f0307 commit 1ba825b

16 files changed

+203
-116
lines changed

gwctl/pkg/cmd/describe/describe.go renamed to gwctl/cmd/describe.go

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,48 +14,58 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
package describe
17+
package cmd
1818

1919
import (
2020
"fmt"
2121
"os"
2222

2323
"github.com/spf13/cobra"
2424

25-
"sigs.k8s.io/gateway-api/gwctl/pkg/cmd/utils"
2625
"sigs.k8s.io/gateway-api/gwctl/pkg/policymanager"
2726
"sigs.k8s.io/gateway-api/gwctl/pkg/printer"
2827
"sigs.k8s.io/gateway-api/gwctl/pkg/resourcediscovery"
28+
"sigs.k8s.io/gateway-api/gwctl/pkg/utils"
2929

3030
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3131
)
3232

33-
type describeFlags struct {
34-
namespace string
35-
allNamespaces bool
36-
}
33+
func NewDescribeCommand() *cobra.Command {
3734

38-
func NewDescribeCommand(params *utils.CmdParams) *cobra.Command {
39-
flags := &describeFlags{}
35+
var namespaceFlag string
36+
var allNamespacesFlag bool
4037

4138
cmd := &cobra.Command{
4239
Use: "describe {policies|httproutes|gateways|gatewayclasses|backends} RESOURCE_NAME",
4340
Short: "Show details of a specific resource or group of resources",
4441
Args: cobra.RangeArgs(1, 2),
4542
Run: func(cmd *cobra.Command, args []string) {
46-
runDescribe(args, params, flags)
43+
params := getParams(kubeConfigPath)
44+
runDescribe(cmd, args, params)
4745
},
4846
}
49-
cmd.Flags().StringVarP(&flags.namespace, "namespace", "n", "default", "")
50-
cmd.Flags().BoolVarP(&flags.allNamespaces, "all-namespaces", "A", false, "If present, list requested resources from all namespaces.")
47+
cmd.Flags().StringVarP(&namespaceFlag, "namespace", "n", "default", "")
48+
cmd.Flags().BoolVarP(&allNamespacesFlag, "all-namespaces", "A", false, "If present, list requested resources from all namespaces.")
5149

5250
return cmd
5351
}
5452

55-
func runDescribe(args []string, params *utils.CmdParams, flags *describeFlags) {
53+
func runDescribe(cmd *cobra.Command, args []string, params *utils.CmdParams) {
5654
kind := args[0]
57-
ns := flags.namespace
58-
if flags.allNamespaces {
55+
56+
ns, err := cmd.Flags().GetString("namespace")
57+
if err != nil {
58+
fmt.Fprintf(os.Stderr, "failed to read flag \"namespace\": %v\n", err)
59+
os.Exit(1)
60+
}
61+
62+
allNs, err := cmd.Flags().GetBool("all-namespaces")
63+
if err != nil {
64+
fmt.Fprintf(os.Stderr, "failed to read flag \"all-namespaces\": %v\n", err)
65+
os.Exit(1)
66+
}
67+
68+
if allNs {
5969
ns = metav1.NamespaceAll
6070
}
6171

@@ -93,7 +103,8 @@ func runDescribe(args []string, params *utils.CmdParams, flags *describeFlags) {
93103
}
94104
resourceModel, err := discoverer.DiscoverResourcesForHTTPRoute(filter)
95105
if err != nil {
96-
panic(err)
106+
fmt.Fprintf(os.Stderr, "failed to discover HTTPRoute resources: %v\n", err)
107+
os.Exit(1)
97108
}
98109
httpRoutesPrinter.PrintDescribeView(resourceModel)
99110

@@ -104,7 +115,8 @@ func runDescribe(args []string, params *utils.CmdParams, flags *describeFlags) {
104115
}
105116
resourceModel, err := discoverer.DiscoverResourcesForGateway(filter)
106117
if err != nil {
107-
panic(err)
118+
fmt.Fprintf(os.Stderr, "failed to discover Gateway resources: %v\n", err)
119+
os.Exit(1)
108120
}
109121
gwPrinter.PrintDescribeView(resourceModel)
110122

@@ -115,7 +127,8 @@ func runDescribe(args []string, params *utils.CmdParams, flags *describeFlags) {
115127
}
116128
resourceModel, err := discoverer.DiscoverResourcesForGatewayClass(filter)
117129
if err != nil {
118-
panic(err)
130+
fmt.Fprintf(os.Stderr, "failed to discover GatewayClass resources: %v\n", err)
131+
os.Exit(1)
119132
}
120133
gwcPrinter.PrintDescribeView(resourceModel)
121134

@@ -128,7 +141,8 @@ func runDescribe(args []string, params *utils.CmdParams, flags *describeFlags) {
128141
}
129142
resourceModel, err := discoverer.DiscoverResourcesForBackend(filter)
130143
if err != nil {
131-
panic(err)
144+
fmt.Fprintf(os.Stderr, "failed to discover resources related to Backend: %v\n", err)
145+
os.Exit(1)
132146
}
133147
backendsPrinter.PrintDescribeView(resourceModel)
134148

gwctl/pkg/cmd/get/get.go renamed to gwctl/cmd/get.go

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
package get
17+
package cmd
1818

1919
import (
2020
"fmt"
@@ -24,37 +24,46 @@ import (
2424

2525
"k8s.io/utils/clock"
2626

27-
"sigs.k8s.io/gateway-api/gwctl/pkg/cmd/utils"
2827
"sigs.k8s.io/gateway-api/gwctl/pkg/printer"
2928
"sigs.k8s.io/gateway-api/gwctl/pkg/resourcediscovery"
29+
"sigs.k8s.io/gateway-api/gwctl/pkg/utils"
3030
)
3131

32-
type getFlags struct {
33-
namespace string
34-
allNamespaces bool
35-
}
32+
func NewGetCommand() *cobra.Command {
3633

37-
func NewGetCommand(params *utils.CmdParams) *cobra.Command {
38-
flags := &getFlags{}
34+
var namespaceFlag string
35+
var allNamespacesFlag bool
3936

4037
cmd := &cobra.Command{
4138
Use: "get {gateways|gatewayclasses|policies|policycrds|httproutes}",
4239
Short: "Display one or many resources",
4340
Args: cobra.ExactArgs(1),
4441
Run: func(cmd *cobra.Command, args []string) {
45-
runGet(args, params, flags)
42+
params := getParams(kubeConfigPath)
43+
runGet(cmd, args, params)
4644
},
4745
}
48-
cmd.Flags().StringVarP(&flags.namespace, "namespace", "n", "default", "")
49-
cmd.Flags().BoolVarP(&flags.allNamespaces, "all-namespaces", "A", false, "If present, list requested resources from all namespaces.")
46+
cmd.Flags().StringVarP(&namespaceFlag, "namespace", "n", "default", "")
47+
cmd.Flags().BoolVarP(&allNamespacesFlag, "all-namespaces", "A", false, "If present, list requested resources from all namespaces.")
5048

5149
return cmd
5250
}
5351

54-
func runGet(args []string, params *utils.CmdParams, flags *getFlags) {
52+
func runGet(cmd *cobra.Command, args []string, params *utils.CmdParams) {
5553
kind := args[0]
56-
ns := flags.namespace
57-
if flags.allNamespaces {
54+
ns, err := cmd.Flags().GetString("namespace")
55+
if err != nil {
56+
fmt.Fprintf(os.Stderr, "failed to read flag \"namespace\": %v\n", err)
57+
os.Exit(1)
58+
}
59+
60+
allNs, err := cmd.Flags().GetBool("all-namespaces")
61+
if err != nil {
62+
fmt.Fprintf(os.Stderr, "failed to read flag \"all-namespaces\": %v\n", err)
63+
os.Exit(1)
64+
}
65+
66+
if allNs {
5867
ns = ""
5968
}
6069

@@ -76,7 +85,8 @@ func runGet(args []string, params *utils.CmdParams, flags *getFlags) {
7685
}
7786
resourceModel, err := discoverer.DiscoverResourcesForGateway(filter)
7887
if err != nil {
79-
panic(err)
88+
fmt.Fprintf(os.Stderr, "failed to discover Gateway resources: %v\n", err)
89+
os.Exit(1)
8090
}
8191
gwPrinter.Print(resourceModel)
8292

@@ -107,7 +117,8 @@ func runGet(args []string, params *utils.CmdParams, flags *getFlags) {
107117
}
108118
resourceModel, err := discoverer.DiscoverResourcesForHTTPRoute(filter)
109119
if err != nil {
110-
panic(err)
120+
fmt.Fprintf(os.Stderr, "failed to discover HTTPRoute resources: %v\n", err)
121+
os.Exit(1)
111122
}
112123
httpRoutesPrinter.Print(resourceModel)
113124

gwctl/cmd/main.go

Lines changed: 0 additions & 71 deletions
This file was deleted.

gwctl/cmd/root.go

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
Copyright 2023 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package cmd
18+
19+
import (
20+
"context"
21+
"flag"
22+
"fmt"
23+
"os"
24+
"path"
25+
26+
"github.com/spf13/cobra"
27+
"k8s.io/klog/v2"
28+
29+
"sigs.k8s.io/gateway-api/gwctl/pkg/common"
30+
"sigs.k8s.io/gateway-api/gwctl/pkg/policymanager"
31+
cmdutils "sigs.k8s.io/gateway-api/gwctl/pkg/utils"
32+
)
33+
34+
var (
35+
kubeConfigPath string
36+
)
37+
38+
func newRootCmd() *cobra.Command {
39+
rootCmd := &cobra.Command{
40+
Use: "gwctl",
41+
Short: "gwctl is a command-line tool for exploring Gateway API resources.",
42+
Long: `gwctl provides a familiar kubectl-like interface for navigating the Kubernetes Gateway API's multi-resource model, offering visibility into resource relationships and the policies that affect them.`,
43+
}
44+
cobra.OnInitialize(initConfig)
45+
rootCmd.PersistentFlags().StringVar(&kubeConfigPath, "kubeconfig", "", "path to kubeconfig file (default is the KUBECONFIG environment variable and if it isn't set, falls back to $HOME/.kube/config)")
46+
47+
// initialize logging flags in a new flag set
48+
// otherwise it conflicts with cobra's flags
49+
klogFlags := flag.NewFlagSet("klog", flag.ExitOnError)
50+
klog.InitFlags(klogFlags)
51+
52+
rootCmd.PersistentFlags().AddGoFlagSet(klogFlags)
53+
54+
rootCmd.AddCommand(NewGetCommand())
55+
rootCmd.AddCommand(NewDescribeCommand())
56+
57+
return rootCmd
58+
}
59+
60+
func Execute() {
61+
rootCmd := newRootCmd()
62+
err := rootCmd.Execute()
63+
if err != nil {
64+
fmt.Fprintf(os.Stderr, "failed to execute command: %v\n", err)
65+
os.Exit(1)
66+
}
67+
}
68+
69+
func initConfig() {
70+
if kubeConfigPath == "" {
71+
kubeConfigPath = os.Getenv("KUBECONFIG")
72+
if kubeConfigPath == "" {
73+
kubeConfigPath = path.Join(os.Getenv("HOME"), ".kube/config")
74+
}
75+
}
76+
}
77+
78+
func getParams(path string) *cmdutils.CmdParams {
79+
k8sClients, err := common.NewK8sClients(path)
80+
if err != nil {
81+
fmt.Fprintf(os.Stderr, "failed to create k8s clients: %v\n", err)
82+
os.Exit(1)
83+
}
84+
85+
policyManager := policymanager.New(k8sClients.DC)
86+
if err := policyManager.Init(context.Background()); err != nil {
87+
fmt.Fprintf(os.Stderr, "failed to initialize policy manager: %v\n", err)
88+
os.Exit(1)
89+
}
90+
91+
params := &cmdutils.CmdParams{
92+
K8sClients: k8sClients,
93+
PolicyManager: policyManager,
94+
Out: os.Stdout,
95+
}
96+
97+
return params
98+
}

gwctl/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ require (
66
github.com/evanphx/json-patch v5.9.0+incompatible
77
github.com/google/go-cmp v0.6.0
88
github.com/spf13/cobra v1.8.0
9-
github.com/spf13/pflag v1.0.5
109
k8s.io/api v0.29.2
1110
k8s.io/apiextensions-apiserver v0.29.2
1211
k8s.io/apimachinery v0.29.2
@@ -41,6 +40,7 @@ require (
4140
github.com/modern-go/reflect2 v1.0.2 // indirect
4241
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
4342
github.com/pkg/errors v0.9.1 // indirect
43+
github.com/spf13/pflag v1.0.5 // indirect
4444
golang.org/x/net v0.20.0 // indirect
4545
golang.org/x/oauth2 v0.16.0 // indirect
4646
golang.org/x/sys v0.16.0 // indirect

0 commit comments

Comments
 (0)