Skip to content

Commit ef3162d

Browse files
committed
Use cli-runtime to parse resource/name structure
1 parent 4ade464 commit ef3162d

File tree

3 files changed

+42
-73
lines changed

3 files changed

+42
-73
lines changed

cmd/kubectl-tree/apioverrides.go

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

cmd/kubectl-tree/apis.go

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -121,19 +121,3 @@ func apiNames(a metav1.APIResource, gv schema.GroupVersion) []string {
121121
return out
122122
}
123123

124-
func figureOutKindName(args []string) (string, string, error) {
125-
if l := len(args); l == 0 || l > 2 {
126-
return "", "", fmt.Errorf("accepts between 1 and 2 arg(s), received %d", l)
127-
}
128-
if len(args) == 2 {
129-
return args[0], args[1], nil
130-
}
131-
seg := strings.Split(args[0], "/")
132-
if len(seg) < 2 {
133-
return "", "", fmt.Errorf("specify the kubernetes object in KIND NAME or KIND/NAME form")
134-
}
135-
if len(seg) > 2 {
136-
return "", "", fmt.Errorf("arguments in KIND/NAME form may not have more than one slash")
137-
}
138-
return seg[0], seg[1], nil
139-
}

cmd/kubectl-tree/rootcmd.go

Lines changed: 42 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,17 @@ import (
2020
"flag"
2121
"fmt"
2222
"os"
23-
"strings"
2423

2524
"github.com/fatih/color"
2625
"github.com/pkg/errors"
2726
"github.com/spf13/cobra"
2827
"github.com/spf13/pflag"
2928
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3029
"k8s.io/cli-runtime/pkg/genericclioptions"
30+
"k8s.io/cli-runtime/pkg/resource"
3131
"k8s.io/client-go/discovery"
3232
"k8s.io/client-go/dynamic"
33+
"k8s.io/client-go/kubernetes/scheme"
3334
_ "k8s.io/client-go/plugin/pkg/client/auth" // combined authprovider import
3435
"k8s.io/client-go/rest"
3536
"k8s.io/klog"
@@ -93,10 +94,6 @@ func run(command *cobra.Command, args []string) error {
9394
if err != nil {
9495
return err
9596
}
96-
if len(conditionTypes) == 0 {
97-
// Default to "Ready" if not specified
98-
conditionTypes = []string{"Ready"}
99-
}
10097

10198
restConfig, err := cf.ToRESTConfig()
10299
if err != nil {
@@ -120,44 +117,59 @@ func run(command *cobra.Command, args []string) error {
120117
}
121118
klog.V(3).Info("completed querying APIs list")
122119

123-
kind, name, err := figureOutKindName(args)
120+
// Use resource.Builder to resolve resource kind and name (kubectl-compatible)
121+
builder := resource.NewBuilder(cf)
122+
namespace := ""
123+
if cf.Namespace != nil {
124+
namespace = *cf.Namespace
125+
}
126+
127+
result := builder.
128+
WithScheme(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...).
129+
NamespaceParam(namespace).
130+
DefaultNamespace().
131+
ResourceTypeOrNameArgs(true, args...).
132+
Do()
133+
134+
infos, err := result.Infos()
124135
if err != nil {
125-
return err
136+
return fmt.Errorf("failed to resolve resource: %w", err)
137+
}
138+
if len(infos) == 0 {
139+
return fmt.Errorf("no resources found")
140+
}
141+
if len(infos) > 1 {
142+
return fmt.Errorf("multiple resources found, specify a single resource")
126143
}
127-
klog.V(3).Infof("parsed kind=%v name=%v", kind, name)
128144

129-
var api apiResource
130-
if k, ok := overrideType(kind, apis); ok {
131-
klog.V(2).Infof("kind=%s override found: %s", kind, k.GroupVersionResource())
132-
api = k
133-
} else {
134-
apiResults := apis.lookup(kind)
135-
klog.V(5).Infof("kind matches=%v", apiResults)
136-
if len(apiResults) == 0 {
137-
return fmt.Errorf("could not find api kind %q", kind)
138-
} else if len(apiResults) > 1 {
139-
names := make([]string, 0, len(apiResults))
140-
for _, a := range apiResults {
141-
names = append(names, fullAPIName(a))
142-
}
143-
return fmt.Errorf("ambiguous kind %q. use one of these as the KIND disambiguate: [%s]", kind,
144-
strings.Join(names, ", "))
145-
}
146-
api = apiResults[0]
145+
info := infos[0]
146+
gvr := info.Mapping.Resource
147+
name := info.Name
148+
klog.V(3).Infof("resolved resource: gvr=%v name=%v", gvr, name)
149+
150+
// Convert GVR to apiResource for compatibility with existing code
151+
// Check if resource is namespaced by comparing scope name
152+
isNamespaced := info.Mapping.Scope.Name() == "namespace"
153+
api := apiResource{
154+
r: metav1.APIResource{
155+
Name: gvr.Resource,
156+
Namespaced: isNamespaced,
157+
},
158+
gv: gvr.GroupVersion(),
147159
}
148160

149161
ns := getNamespace()
150162
klog.V(2).Infof("namespace=%s allNamespaces=%v", ns, allNs)
151163

152164
var ri dynamic.ResourceInterface
153165
if api.r.Namespaced {
154-
ri = dyn.Resource(api.GroupVersionResource()).Namespace(ns)
166+
ri = dyn.Resource(gvr).Namespace(ns)
155167
} else {
156-
ri = dyn.Resource(api.GroupVersionResource())
168+
ri = dyn.Resource(gvr)
157169
}
158170
obj, err := ri.Get(context.TODO(), name, metav1.GetOptions{})
159171
if err != nil {
160-
return fmt.Errorf("failed to get %s/%s: %w", kind, name, err)
172+
return fmt.Errorf("failed to get %s/%s: %w", gvr.Resource, name, err)
161173
}
162174

163175
klog.V(5).Infof("target parent object: %#v", obj)
@@ -194,7 +206,7 @@ func init() {
194206

195207
rootCmd.Flags().BoolP(allNamespacesFlag, "A", false, "query all objects in all API groups, both namespaced and non-namespaced")
196208
rootCmd.Flags().StringP(colorFlag, "c", "auto", "Enable or disable color output. This can be 'always', 'never', or 'auto' (default = use color only if using tty). The flag is overridden by the NO_COLOR env variable if set.")
197-
rootCmd.Flags().StringSlice(conditionTypesFlag, []string{}, "Comma-separated list of condition types to check (default: Ready). Example: Ready,Processed,Scheduled")
209+
rootCmd.Flags().StringSlice(conditionTypesFlag, []string{"Ready"}, "Comma-separated list of condition types to check (default: Ready). Example: Ready,Processed,Scheduled")
198210

199211
cf.AddFlags(rootCmd.Flags())
200212
if err := flag.Set("logtostderr", "true"); err != nil {

0 commit comments

Comments
 (0)