Skip to content

Commit 1a3163e

Browse files
chenjiandongxmandochen
andauthored
feature: display the size of images (#25)
* feature: display the size of images * docs update * minor: upgrade gomod version --------- Co-authored-by: mandochen <mandochen@tencent.com>
1 parent 4ba9f51 commit 1a3163e

File tree

5 files changed

+92
-21
lines changed

5 files changed

+92
-21
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ Examples:
6161

6262
Flags:
6363
-A, --all-namespaces if present, list images in all namespaces.
64-
-c, --columns string specify the columns to display, separated by comma. [0:Namespace, 1:PodName, 2:ContainerName, 3:ContainerImage, 4:ImagePullPolicy] (default "1,2,3")
64+
-c, --columns string specify the columns to display, separated by comma. [0:Namespace, 1:PodName, 2:ContainerName, 3:ContainerImage, 4:ImagePullPolicy, 5:ImageSize] (default "1,2,3")
6565
-C, --context string The name of the kubeconfig context to use.
6666
-h, --help help for kubectl-images
6767
-k, --kubeconfig string path to the kubeconfig file to use for CLI requests.

cmd/main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
"github.com/spf13/cobra"
1010
)
1111

12-
const version = "0.5.2"
12+
const version = "0.6.0"
1313

1414
var rootCmd *cobra.Command
1515

@@ -55,7 +55,7 @@ func init() {
5555
}
5656
rootCmd.Flags().BoolP("all-namespaces", "A", false, "if present, list images in all namespaces.")
5757
rootCmd.Flags().StringP("namespace", "n", "", "if present, list images in the specified namespace only. Use current namespace as fallback.")
58-
rootCmd.Flags().StringP("columns", "c", "1,2,3", "specify the columns to display, separated by comma. [0:Namespace, 1:PodName, 2:ContainerName, 3:ContainerImage, 4:ImagePullPolicy]")
58+
rootCmd.Flags().StringP("columns", "c", "1,2,3", "specify the columns to display, separated by comma. [0:Namespace, 1:PodName, 2:ContainerName, 3:ContainerImage, 4:ImagePullPolicy, 5:ImageSize]")
5959
rootCmd.Flags().StringP("kubeconfig", "k", "", "path to the kubeconfig file to use for CLI requests.")
6060
rootCmd.Flags().StringP("output-format", "o", "table", "output format. [json(j)|table(t)|yaml(y)]")
6161
rootCmd.Flags().StringP("context", "C", "", "The name of the kubeconfig context to use.")

go.mod

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
module github.com/chenjiandongx/kubectl-images
22

3-
go 1.13
3+
go 1.18
44

55
require (
6+
github.com/dustin/go-humanize v1.0.1
67
github.com/olekukonko/tablewriter v0.0.4
78
github.com/spf13/cobra v0.0.5
89
gopkg.in/yaml.v2 v2.2.8
910
)
11+
12+
require (
13+
github.com/inconshreveable/mousetrap v1.0.0 // indirect
14+
github.com/mattn/go-runewidth v0.0.7 // indirect
15+
github.com/spf13/pflag v1.0.3 // indirect
16+
)

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8Nz
55
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
66
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
77
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
8+
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
9+
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
810
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
911
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
1012
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=

kubectl_images.go

Lines changed: 79 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,24 @@ import (
66
"os"
77
"os/exec"
88
"regexp"
9+
"strconv"
910
"strings"
1011

12+
"github.com/dustin/go-humanize"
1113
"github.com/olekukonko/tablewriter"
1214
"gopkg.in/yaml.v2"
1315
)
1416

1517
const (
16-
gotemplate = `go-template={{range .items}} {{.metadata.namespace}} {{","}} {{.metadata.name}} {{","}} {{range .spec.containers}} {{.name}} {{","}} {{.image}} {{","}} {{.imagePullPolicy}} {{"\n"}} {{end}} {{range .spec.initContainers}} {{"(init)"}} {{.name}} {{","}} {{.image}} {{","}} {{.imagePullPolicy}} {{"\n"}} {{end}} {{end}}`
18+
podTemplate = `go-template={{range .items}} {{.metadata.namespace}} {{","}} {{.metadata.name}} {{","}} {{range .spec.containers}} {{.name}} {{","}} {{.image}} {{","}} {{.imagePullPolicy}} {{"\n"}} {{end}} {{range .spec.initContainers}} {{"(init)"}} {{.name}} {{","}} {{.image}} {{","}} {{.imagePullPolicy}} {{"\n"}} {{end}} {{end}}`
19+
nodeTemplate = `go-template={{range .items}} {{range .status.images}} {{range .names}} {{.}} {{","}} {{end}} {{.sizeBytes}} {{"\n"}} {{end}} {{end}}`
1720

1821
labelNamespace = "Namespace"
1922
labelPod = "Pod"
2023
labelContainer = "Container"
2124
labelImage = "Image"
2225
labelImagePullPolicy = "ImagePullPolicy"
26+
labelImageSize = "ImageSize"
2327
)
2428

2529
type Parameters struct {
@@ -33,14 +37,17 @@ type Parameters struct {
3337

3438
// KubeImage is the representation of a container image used in the cluster.
3539
type KubeImage struct {
36-
entities []*ImageEntity
37-
columns []string
38-
regx *regexp.Regexp
39-
params Parameters
40+
entities []*ImageEntity
41+
columns []string
42+
regx *regexp.Regexp
43+
params Parameters
44+
imageSize map[string]int
45+
needNodeInfo bool
4046
}
4147

4248
// NewKubeImage creates a new KubeImage instance.
4349
func NewKubeImage(regx *regexp.Regexp, params Parameters) *KubeImage {
50+
var needNodeInfo bool
4451
names := make([]string, 0)
4552
for _, c := range stringSplit(params.Columns, ",") {
4653
switch c {
@@ -54,13 +61,18 @@ func NewKubeImage(regx *regexp.Regexp, params Parameters) *KubeImage {
5461
names = append(names, labelImage)
5562
case "4":
5663
names = append(names, labelImagePullPolicy)
64+
case "5":
65+
names = append(names, labelImageSize)
66+
needNodeInfo = true
5767
}
5868
}
5969

6070
return &KubeImage{
61-
columns: names,
62-
params: params,
63-
regx: regx,
71+
columns: names,
72+
params: params,
73+
regx: regx,
74+
imageSize: make(map[string]int),
75+
needNodeInfo: needNodeInfo,
6476
}
6577
}
6678

@@ -71,6 +83,7 @@ type ImageEntity struct {
7183
Container string `json:"container,omitempty" yaml:"container,omitempty"`
7284
Image string `json:"image,omitempty" yaml:"image,omitempty"`
7385
ImagePullPolicy string `json:"imagePullPolicy,omitempty" yaml:"imagePullPolicy,omitempty"`
86+
ImageSize string `json:"imageSize,omitempty" yaml:"imageSize,omitempty"`
7487
}
7588

7689
func (ie *ImageEntity) selectBy(columns []string) []string {
@@ -87,6 +100,8 @@ func (ie *ImageEntity) selectBy(columns []string) []string {
87100
result = append(result, ie.Image)
88101
case labelImagePullPolicy:
89102
result = append(result, ie.ImagePullPolicy)
103+
case labelImageSize:
104+
result = append(result, ie.ImageSize)
90105
}
91106
}
92107
return result
@@ -106,6 +121,8 @@ func (ie *ImageEntity) filterBy(columns []string) ImageEntity {
106121
entity.Image = ie.Image
107122
case labelImagePullPolicy:
108123
entity.ImagePullPolicy = ie.ImagePullPolicy
124+
case labelImageSize:
125+
entity.ImageSize = ie.ImageSize
109126
}
110127
}
111128
return entity
@@ -142,8 +159,8 @@ func stringSplit(in, sep string) []string {
142159
return out
143160
}
144161

145-
// Commands builds the command to be executed based on user input.
146-
func (ki *KubeImage) Commands() []string {
162+
// podCommands builds the command to be executed based on user input.
163+
func (ki *KubeImage) podCommands() []string {
147164
kubecfg := make([]string, 0)
148165
if ki.params.KubeConfig != "" {
149166
kubecfg = append(kubecfg, "--kubeconfig", ki.params.KubeConfig)
@@ -154,18 +171,60 @@ func (ki *KubeImage) Commands() []string {
154171
}
155172

156173
if ki.params.AllNamespace {
157-
return append([]string{"get", "pods", "--all-namespaces", "-o", gotemplate}, kubecfg...)
174+
return append([]string{"get", "pods", "--all-namespaces", "-o", podTemplate}, kubecfg...)
158175
} else if ki.params.Namespace != "" {
159-
return append([]string{"get", "pods", "-n", ki.params.Namespace, "-o", gotemplate}, kubecfg...)
176+
return append([]string{"get", "pods", "-n", ki.params.Namespace, "-o", podTemplate}, kubecfg...)
160177
}
161-
return append([]string{"get", "pods", "-o", gotemplate}, kubecfg...)
178+
return append([]string{"get", "pods", "-o", podTemplate}, kubecfg...)
162179
}
163180

164-
func (ki *KubeImage) exec() {
165-
process := exec.Command("kubectl", ki.Commands()...)
181+
func (ki *KubeImage) nodeCommands() []string {
182+
kubecfg := make([]string, 0)
183+
if ki.params.KubeConfig != "" {
184+
kubecfg = append(kubecfg, "--kubeconfig", ki.params.KubeConfig)
185+
}
186+
187+
if ki.params.Context != "" {
188+
kubecfg = append(kubecfg, "--context", ki.params.Context)
189+
}
190+
191+
return append([]string{"get", "nodes", "-o", nodeTemplate}, kubecfg...)
192+
}
193+
194+
func (ki *KubeImage) execNodeCommand() {
195+
process := exec.Command("kubectl", ki.nodeCommands()...)
196+
bs, err := process.CombinedOutput()
197+
if err != nil {
198+
fmt.Fprintf(os.Stderr, "[Oh...] Execute nodes command error: %v, %s", err, string(bs))
199+
os.Exit(1)
200+
}
201+
202+
for _, line := range stringSplit(string(bs), "\n") {
203+
items := stringSplit(line, ",")
204+
switch len(items) {
205+
case 3:
206+
size, err := strconv.Atoi(items[2])
207+
if err != nil {
208+
continue
209+
}
210+
ki.imageSize[items[0]] = size
211+
ki.imageSize[items[1]] = size
212+
}
213+
}
214+
215+
for _, entity := range ki.entities {
216+
size, ok := ki.imageSize[entity.Image]
217+
if ok {
218+
entity.ImageSize = humanize.IBytes(uint64(size))
219+
}
220+
}
221+
}
222+
223+
func (ki *KubeImage) execPodCommand() {
224+
process := exec.Command("kubectl", ki.podCommands()...)
166225
bs, err := process.CombinedOutput()
167226
if err != nil {
168-
fmt.Fprintf(os.Stderr, "[Oh...] Execute command error: %v, %s", err, string(bs))
227+
fmt.Fprintf(os.Stderr, "[Oh...] Execute pods command error: %v, %s", err, string(bs))
169228
os.Exit(1)
170229
}
171230

@@ -293,7 +352,10 @@ func (ki *KubeImage) yamlRender() {
293352

294353
// Render renders and displays the table output.
295354
func (ki *KubeImage) Render(format string) {
296-
ki.exec()
355+
ki.execPodCommand()
356+
if ki.needNodeInfo {
357+
ki.execNodeCommand()
358+
}
297359

298360
if len(ki.entities) == 0 {
299361
fmt.Fprintln(os.Stdout, "[Oh...] No images matched!")

0 commit comments

Comments
 (0)