Skip to content

Commit cff5d04

Browse files
committed
working cli example for pod list, pod add and resources
Signed-off-by: Ken Sipe <[email protected]>
1 parent 977d774 commit cff5d04

File tree

10 files changed

+292
-19
lines changed

10 files changed

+292
-19
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,5 @@
1313

1414
# Dependency directories (remove the comment below to include it)
1515
# vendor/
16+
.DS_Store
17+
.idea/

Makefile

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,6 @@ endif
3737
download:
3838
go mod download
3939

40-
.PHONY: prebuild
41-
prebuild: generate lint
42-
4340

4441
.PHONY: cli-fast
4542
# Build CLI but don't lint or run code generation first.
@@ -48,7 +45,7 @@ cli-fast:
4845

4946
.PHONY: cli
5047
# Build CLI
51-
cli: prebuild cli-fast
48+
cli: cli-fast
5249

5350
.PHONY: cli-clean
5451
# Clean CLI build

go.mod

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@ require (
77
github.com/go-bindata/go-bindata v3.1.2+incompatible
88
github.com/gogo/protobuf v1.3.1 // indirect
99
github.com/googleapis/gnostic v0.3.1 // indirect
10+
github.com/gosuri/uitable v0.0.4
1011
github.com/imdario/mergo v0.3.7 // indirect
1112
github.com/mattn/go-colorable v0.1.4 // indirect
1213
github.com/mattn/go-isatty v0.0.10 // indirect
14+
github.com/mattn/go-runewidth v0.0.8 // indirect
1315
github.com/onsi/ginkgo v1.10.1 // indirect
1416
github.com/onsi/gomega v1.7.1 // indirect
1517
github.com/spf13/cobra v0.0.5
@@ -23,8 +25,10 @@ require (
2325
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
2426
gopkg.in/yaml.v2 v2.2.7 // indirect
2527
gopkg.in/yaml.v3 v3.0.0-20191106092431-e228e37189d3 // indirect
28+
k8s.io/api v0.0.0-20191016110408-35e52d86657a
2629
k8s.io/apiextensions-apiserver v0.0.0-20191016113550-5357c4baaf65
27-
k8s.io/apimachinery v0.0.0-20191028221656-72ed19daf4bb // indirect
30+
k8s.io/apimachinery v0.0.0-20191028221656-72ed19daf4bb
31+
k8s.io/apiserver v0.0.0-20191016112112-5190913f932d
2832
k8s.io/client-go v11.0.0+incompatible
2933
k8s.io/code-generator v0.18.0-alpha.1.0.20191220033320-6b257a9d6f46
3034
sigs.k8s.io/controller-tools v0.2.4

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,8 @@ github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1a
179179
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
180180
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
181181
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
182+
github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY=
183+
github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo=
182184
github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7 h1:6TSoaYExHper8PYsJu23GWVNOyYRCSnIFyxKgLSZ54w=
183185
github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
184186
github.com/grpc-ecosystem/go-grpc-middleware v0.0.0-20190222133341-cfaf5686ec79 h1:lR9ssWAqp9qL0bALxqEEkuudiP1eweOdv9jsRK3e7lE=
@@ -239,6 +241,8 @@ github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE
239241
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
240242
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
241243
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
244+
github.com/mattn/go-runewidth v0.0.8 h1:3tS41NlGYSmhhe/8fhGRzc+z3AYCw1Fe1WAyLuujKs0=
245+
github.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
242246
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
243247
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
244248
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=

pkg/example/cmd/pod.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ This command consists of multiple sub-commands to interact with Pods.
1111
`
1212

1313
const podExamples = ` kubectl example pod list [flags]
14+
kubectl example pod list2 [flags]
1415
kubectl example pod add [name] [flags]
1516
`
1617

@@ -25,6 +26,7 @@ func newPodCmd(out io.Writer) *cobra.Command {
2526

2627
cmd.AddCommand(newPodAddCmd(out))
2728
cmd.AddCommand(newPodListCmd(out))
29+
cmd.AddCommand(newPodList2Cmd(out))
2830

2931
return cmd
3032
}

pkg/example/cmd/pod_add.go

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,14 @@ package cmd
22

33
import (
44
"errors"
5+
"fmt"
56
"io"
67

78
"github.com/spf13/cobra"
9+
apiv1 "k8s.io/api/core/v1"
10+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
11+
12+
"github.com/codementor/k8s-cli/pkg/example/env"
813
)
914

1015
const (
@@ -15,14 +20,14 @@ const (
1520
)
1621

1722
type podAddCmd struct {
18-
interactive bool
19-
out io.Writer
23+
image string
24+
out io.Writer
2025
}
2126

2227
// newPodAddCmd adds a pod to the cluster
2328
func newPodAddCmd(out io.Writer) *cobra.Command {
2429

25-
pkg := &podAddCmd{out: out}
30+
p := &podAddCmd{out: out}
2631
cmd := &cobra.Command{
2732
Use: "add",
2833
Short: "adds a pod to the cluster",
@@ -32,26 +37,53 @@ func newPodAddCmd(out io.Writer) *cobra.Command {
3237
if err := validateArgs(args); err != nil {
3338
return err
3439
}
35-
if err := pkg.run(args); err != nil {
40+
if err := p.run(args[0]); err != nil {
3641
return err
3742
}
3843
return nil
3944
},
4045
}
4146

4247
f := cmd.Flags()
43-
f.BoolVarP(&pkg.interactive, "interactive", "i", false, "Interactive mode.")
48+
f.StringVar(&p.image, "image", "nginx", "image to be used in creation of pod")
4449
return cmd
4550
}
4651

4752
func validateArgs(args []string) error {
48-
if len(args) == 1 {
49-
return errors.New("expecting 1 argument - name of pod`")
53+
if len(args) != 1 {
54+
return errors.New("expecting 1 argument - name of pod")
5055
}
5156
return nil
57+
5258
}
5359

5460
// run returns the errors associated with cmd env
55-
func (pkg *podAddCmd) run(args []string) error {
61+
func (p *podAddCmd) run(name string) error {
62+
client := env.NewClientSet(&Settings)
63+
64+
podsClient := client.CoreV1().Pods(apiv1.NamespaceDefault)
65+
66+
pod := &apiv1.Pod{
67+
TypeMeta: metav1.TypeMeta{},
68+
ObjectMeta: metav1.ObjectMeta{
69+
Name: name,
70+
Labels: map[string]string{"app": "demo"},
71+
},
72+
Spec: apiv1.PodSpec{
73+
Containers: []apiv1.Container{
74+
{
75+
Name: name,
76+
Image: p.image,
77+
},
78+
},
79+
},
80+
}
81+
82+
pp, err := podsClient.Create(pod)
83+
if err != nil {
84+
return err
85+
}
86+
87+
fmt.Fprintf(p.out, "Pod %v created with rev: %v\n", pp.Name, pp.ResourceVersion)
5688
return nil
5789
}

pkg/example/cmd/pod_list.go

Lines changed: 85 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
package cmd
22

33
import (
4+
"fmt"
45
"io"
56

67
"github.com/spf13/cobra"
8+
apiv1 "k8s.io/api/core/v1"
9+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10+
v1 "k8s.io/apiserver/pkg/apis/example/v1"
11+
12+
"github.com/codementor/k8s-cli/pkg/example/env"
713
)
814

915
const (
@@ -14,8 +20,8 @@ const (
1420
)
1521

1622
type podListCmd struct {
17-
interactive bool
18-
out io.Writer
23+
status bool
24+
out io.Writer
1925
}
2026

2127
// newPodListCmd lists pods
@@ -27,20 +33,93 @@ func newPodListCmd(out io.Writer) *cobra.Command {
2733
Short: podListDesc,
2834
Example: podListExample,
2935
RunE: func(cmd *cobra.Command, args []string) error {
30-
if err := pkg.run(args); err != nil {
36+
if err := pkg.run(); err != nil {
37+
return err
38+
}
39+
return nil
40+
},
41+
}
42+
43+
f := cmd.Flags()
44+
f.BoolVarP(&pkg.status, "status", "i", true, "display status info")
45+
return cmd
46+
}
47+
48+
// newPodList2Cmd lists pods
49+
func newPodList2Cmd(out io.Writer) *cobra.Command {
50+
51+
pkg := &podListCmd{out: out}
52+
cmd := &cobra.Command{
53+
Use: "list2",
54+
Short: podListDesc,
55+
Example: podListExample,
56+
RunE: func(cmd *cobra.Command, args []string) error {
57+
if err := pkg.run2(); err != nil {
3158
return err
3259
}
3360
return nil
3461
},
3562
}
3663

3764
f := cmd.Flags()
38-
f.BoolVarP(&pkg.interactive, "interactive", "i", false, "Interactive mode.")
65+
f.BoolVarP(&pkg.status, "status", "i", true, "display status info")
3966
return cmd
4067
}
4168

69+
// run 1st approach at list pods
70+
func (p *podListCmd) run() error {
4271

43-
// run returns the errors associated with cmd env
44-
func (pkg *podListCmd) run(args []string) error {
72+
client := env.NewClientSet(&Settings)
73+
podsClient := client.CoreV1().Pods(apiv1.NamespaceDefault)
74+
75+
list, err := podsClient.List(metav1.ListOptions{})
76+
if err != nil {
77+
return err
78+
}
79+
80+
if len(list.Items) == 0 {
81+
fmt.Printf("no pods discovered\n")
82+
return nil
83+
}
84+
for _, item := range list.Items {
85+
if p.status {
86+
fmt.Fprintf(p.out, "pod %v in namespace: %v, status: %v\n", item.Name, item.Namespace, item.Status.Phase)
87+
88+
} else {
89+
fmt.Fprintf(p.out, "pod %v in namespace: %v\n", item.Name, item.Namespace)
90+
91+
}
92+
}
93+
return nil
94+
}
95+
96+
// run2 2nd approach at list pods
97+
func (p *podListCmd) run2() error {
98+
99+
//REST Client approach
100+
101+
client := env.NewRestClient(&Settings)
102+
result := &v1.PodList{}
103+
104+
err := client.Get().
105+
Namespace(apiv1.NamespaceDefault).
106+
Resource("pods").
107+
Do().
108+
Into(result)
109+
if err != nil {
110+
return err
111+
}
112+
if len(result.Items) == 0 {
113+
fmt.Printf("no pods discovered\n")
114+
return nil
115+
}
116+
for _, item := range result.Items {
117+
if p.status {
118+
fmt.Fprintf(p.out, "pod %v in namespace: %v, status: %v\n", item.Name, item.Namespace, item.Status.Phase)
119+
120+
} else {
121+
fmt.Fprintf(p.out, "pod %v in namespace: %v\n", item.Name, item.Namespace)
122+
}
123+
}
45124
return nil
46125
}

pkg/example/cmd/resources.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/gosuri/uitable"
7+
"github.com/spf13/cobra"
8+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
9+
10+
"github.com/codementor/k8s-cli/pkg/example/env"
11+
)
12+
13+
var (
14+
resourceExample = ` # Print the current api resources
15+
kubectl example resources`
16+
)
17+
18+
// newResourcesCmd returns list of kubernetes api-resources
19+
func newResourcesCmd() *cobra.Command {
20+
versionCmd := &cobra.Command{
21+
Use: "resources",
22+
Short: "List Kubernetes API Resources",
23+
Example: resourceExample,
24+
RunE: ResourcesCmd,
25+
}
26+
27+
return versionCmd
28+
}
29+
30+
// ResourcesCmd list api resources
31+
func ResourcesCmd(cmd *cobra.Command, args []string) error {
32+
client := env.NewClientSet(&Settings)
33+
lists, err := client.Discovery().ServerPreferredResources()
34+
if err != nil {
35+
return err
36+
}
37+
38+
resources := []metav1.APIResource{}
39+
for _, item := range lists {
40+
if len(item.APIResources) == 0 {
41+
continue
42+
}
43+
if err != nil {
44+
continue
45+
}
46+
47+
resources = append(resources, item.APIResources...)
48+
}
49+
table := uitable.New()
50+
table.AddRow("Name", "Namespaced", "Kind")
51+
for _, resource := range resources {
52+
table.AddRow(resource.Name, resource.Namespaced, resource.Kind)
53+
}
54+
fmt.Print(table)
55+
return nil
56+
}

pkg/example/cmd/root.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,15 @@ import (
66
"github.com/spf13/cobra"
77

88
"github.com/codementor/k8s-cli/pkg/example/clog"
9+
"github.com/codementor/k8s-cli/pkg/example/env"
910
"github.com/codementor/k8s-cli/pkg/version"
1011
)
1112

13+
var (
14+
// Settings defines global flags and settings
15+
Settings env.Settings
16+
)
17+
1218
// NewExampleCmd creates a new root command for example CLI
1319
func NewExampleCmd() *cobra.Command {
1420
cmd := &cobra.Command{
@@ -34,6 +40,7 @@ func NewExampleCmd() *cobra.Command {
3440
// get api-resources
3541
// get CRD?
3642
cmd.AddCommand(newPodCmd(cmd.OutOrStdout()))
43+
cmd.AddCommand(newResourcesCmd())
3744
cmd.AddCommand(newVersionCmd())
3845

3946
initGlobalFlags(cmd, cmd.OutOrStdout())
@@ -43,5 +50,6 @@ func NewExampleCmd() *cobra.Command {
4350

4451
func initGlobalFlags(cmd *cobra.Command, out io.Writer) {
4552
flags := cmd.PersistentFlags()
53+
Settings.AddFlags(flags)
4654
clog.InitWithFlags(flags, out)
4755
}

0 commit comments

Comments
 (0)