Skip to content
This repository was archived by the owner on Apr 17, 2025. It is now read-only.

Commit 31aefac

Browse files
committed
Add new subcommand for the kubectl-hns plugin
Add a subcommand to list resources by their parent namespace: kubectl hns get -n <parent ns> <resource>
1 parent 1b6a2f0 commit 31aefac

File tree

2 files changed

+124
-0
lines changed

2 files changed

+124
-0
lines changed

internal/kubectl/get.go

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package kubectl
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"os"
7+
8+
"github.com/spf13/cobra"
9+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10+
"k8s.io/cli-runtime/pkg/printers"
11+
"k8s.io/client-go/dynamic"
12+
"k8s.io/client-go/kubernetes/scheme"
13+
14+
api "sigs.k8s.io/hierarchical-namespaces/api/v1alpha2"
15+
)
16+
17+
var (
18+
watch bool
19+
parent string
20+
allNamespaces bool
21+
)
22+
23+
var getCmd = &cobra.Command{
24+
Use: "get",
25+
Short: "list resources",
26+
RunE: func(c *cobra.Command, args []string) error {
27+
if len(args) == 0 {
28+
return fmt.Errorf("not enough arguments to 'get'")
29+
}
30+
if len(args) > 1 {
31+
return fmt.Errorf("too many arguments to 'get'")
32+
}
33+
d := newDoer(args[0])
34+
rv, err := d.get(args[0])
35+
if err != nil {
36+
return err
37+
}
38+
if watch {
39+
return d.watch(args[0], rv)
40+
}
41+
return nil
42+
},
43+
}
44+
45+
func newGetCmd() *cobra.Command {
46+
return getCmd
47+
}
48+
49+
func init() {
50+
getCmd.Flags().BoolVarP(&watch, "watch", "w", false, "watch for changes")
51+
getCmd.PersistentFlags().StringVarP(&parent, "namespace", "n", "default", "parent namespace to scope request to")
52+
getCmd.PersistentFlags().BoolVarP(&allNamespaces, "all-namespaces", "A", false, "list across all namespaces (equivalent to kubectl get <resource> -A)")
53+
}
54+
55+
type doer struct {
56+
client dynamic.ResourceInterface
57+
printer printers.ResourcePrinter
58+
}
59+
60+
func newDoer(resource string) doer {
61+
client := getClient(resource)
62+
// See https://iximiuz.com/en/posts/kubernetes-api-go-cli/#pretty-print-kubernetes-object-as-yamljsontables for information on k8s printers
63+
printOpts := printers.PrintOptions{WithNamespace: true}
64+
return doer{
65+
client: client,
66+
printer: printers.NewTypeSetter(scheme.Scheme).ToPrinter(printers.NewTablePrinter(printOpts)),
67+
}
68+
}
69+
70+
func getClient(resource string) dynamic.ResourceInterface {
71+
gvr := api.ResourcesGroupVersion.WithResource(resource)
72+
gvr, _ = mapper.ResourceFor(gvr)
73+
resourceClient := dynamicClient.Resource(gvr)
74+
if allNamespaces {
75+
return resourceClient
76+
}
77+
return resourceClient.Namespace(parent)
78+
}
79+
80+
func (d doer) get(resource string) (string, error) {
81+
unst, err := d.client.List(context.TODO(), metav1.ListOptions{})
82+
if err != nil {
83+
return "", err
84+
}
85+
rv := unst.GetResourceVersion()
86+
if err = d.printer.PrintObj(unst, os.Stdout); err != nil {
87+
return rv, err
88+
}
89+
return rv, nil
90+
}
91+
92+
func (d doer) watch(resource, rv string) error {
93+
if rv == "" {
94+
rv = "0"
95+
}
96+
opts := metav1.ListOptions{
97+
ResourceVersion: rv,
98+
}
99+
watcher, err := d.client.Watch(context.TODO(), opts)
100+
if err != nil {
101+
return err
102+
}
103+
for event := range watcher.ResultChan() {
104+
if err = d.printer.PrintObj(event.Object, os.Stdout); err != nil {
105+
return err
106+
}
107+
}
108+
return nil
109+
}

internal/kubectl/root.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,12 @@ import (
2424

2525
"github.com/spf13/cobra"
2626
"k8s.io/apimachinery/pkg/api/errors"
27+
"k8s.io/apimachinery/pkg/api/meta"
2728
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2829
"k8s.io/apimachinery/pkg/runtime/serializer"
2930
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
3031
"k8s.io/cli-runtime/pkg/genericclioptions"
32+
"k8s.io/client-go/dynamic"
3133
"k8s.io/client-go/kubernetes"
3234
"k8s.io/client-go/kubernetes/scheme"
3335
_ "k8s.io/client-go/plugin/pkg/client/auth"
@@ -41,6 +43,8 @@ var k8sClient *kubernetes.Clientset
4143
var hncClient *rest.RESTClient
4244
var rootCmd *cobra.Command
4345
var client Client
46+
var dynamicClient dynamic.Interface
47+
var mapper meta.RESTMapper
4448

4549
type realClient struct{}
4650
type anchorStatus map[string]string
@@ -98,6 +102,16 @@ func init() {
98102
return err
99103
}
100104

105+
mapper, err = kubecfgFlags.ToRESTMapper()
106+
if err != nil {
107+
return err
108+
}
109+
110+
dynamicClient, err = dynamic.NewForConfig(config)
111+
if err != nil {
112+
return err
113+
}
114+
101115
return nil
102116
},
103117
}
@@ -111,6 +125,7 @@ func init() {
111125
rootCmd.AddCommand(newConfigCmd())
112126
rootCmd.AddCommand(newVersionCmd())
113127
rootCmd.AddCommand(newHrqCmd())
128+
rootCmd.AddCommand(newGetCmd())
114129
}
115130

116131
func Execute() {

0 commit comments

Comments
 (0)