Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
feature: display the size of images
  • Loading branch information
mandochen committed May 31, 2023
commit c702756ababbf815c1cdc6c2886df2978d0102d6
4 changes: 2 additions & 2 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"github.com/spf13/cobra"
)

const version = "0.5.2"
const version = "0.6.0"

var rootCmd *cobra.Command

Expand Down Expand Up @@ -55,7 +55,7 @@ func init() {
}
rootCmd.Flags().BoolP("all-namespaces", "A", false, "if present, list images in all namespaces.")
rootCmd.Flags().StringP("namespace", "n", "", "if present, list images in the specified namespace only. Use current namespace as fallback.")
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]")
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]")
rootCmd.Flags().StringP("kubeconfig", "k", "", "path to the kubeconfig file to use for CLI requests.")
rootCmd.Flags().StringP("output-format", "o", "table", "output format. [json(j)|table(t)|yaml(y)]")
rootCmd.Flags().StringP("context", "C", "", "The name of the kubeconfig context to use.")
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/chenjiandongx/kubectl-images
go 1.13

require (
github.com/dustin/go-humanize v1.0.1
github.com/olekukonko/tablewriter v0.0.4
github.com/spf13/cobra v0.0.5
gopkg.in/yaml.v2 v2.2.8
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8Nz
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
Expand Down
96 changes: 79 additions & 17 deletions kubectl_images.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,24 @@ import (
"os"
"os/exec"
"regexp"
"strconv"
"strings"

"github.com/dustin/go-humanize"
"github.com/olekukonko/tablewriter"
"gopkg.in/yaml.v2"
)

const (
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}}`
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}}`
nodeTemplate = `go-template={{range .items}} {{range .status.images}} {{range .names}} {{.}} {{","}} {{end}} {{.sizeBytes}} {{"\n"}} {{end}} {{end}}`

labelNamespace = "Namespace"
labelPod = "Pod"
labelContainer = "Container"
labelImage = "Image"
labelImagePullPolicy = "ImagePullPolicy"
labelImageSize = "ImageSize"
)

type Parameters struct {
Expand All @@ -33,14 +37,17 @@ type Parameters struct {

// KubeImage is the representation of a container image used in the cluster.
type KubeImage struct {
entities []*ImageEntity
columns []string
regx *regexp.Regexp
params Parameters
entities []*ImageEntity
columns []string
regx *regexp.Regexp
params Parameters
imageSize map[string]int
needNodeInfo bool
}

// NewKubeImage creates a new KubeImage instance.
func NewKubeImage(regx *regexp.Regexp, params Parameters) *KubeImage {
var needNodeInfo bool
names := make([]string, 0)
for _, c := range stringSplit(params.Columns, ",") {
switch c {
Expand All @@ -54,13 +61,18 @@ func NewKubeImage(regx *regexp.Regexp, params Parameters) *KubeImage {
names = append(names, labelImage)
case "4":
names = append(names, labelImagePullPolicy)
case "5":
names = append(names, labelImageSize)
needNodeInfo = true
}
}

return &KubeImage{
columns: names,
params: params,
regx: regx,
columns: names,
params: params,
regx: regx,
imageSize: make(map[string]int),
needNodeInfo: needNodeInfo,
}
}

Expand All @@ -71,6 +83,7 @@ type ImageEntity struct {
Container string `json:"container,omitempty" yaml:"container,omitempty"`
Image string `json:"image,omitempty" yaml:"image,omitempty"`
ImagePullPolicy string `json:"imagePullPolicy,omitempty" yaml:"imagePullPolicy,omitempty"`
ImageSize string `json:"imageSize,omitempty" yaml:"imageSize,omitempty"`
}

func (ie *ImageEntity) selectBy(columns []string) []string {
Expand All @@ -87,6 +100,8 @@ func (ie *ImageEntity) selectBy(columns []string) []string {
result = append(result, ie.Image)
case labelImagePullPolicy:
result = append(result, ie.ImagePullPolicy)
case labelImageSize:
result = append(result, ie.ImageSize)
}
}
return result
Expand All @@ -106,6 +121,8 @@ func (ie *ImageEntity) filterBy(columns []string) ImageEntity {
entity.Image = ie.Image
case labelImagePullPolicy:
entity.ImagePullPolicy = ie.ImagePullPolicy
case labelImageSize:
entity.ImageSize = ie.ImageSize
}
}
return entity
Expand Down Expand Up @@ -142,8 +159,8 @@ func stringSplit(in, sep string) []string {
return out
}

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

if ki.params.AllNamespace {
return append([]string{"get", "pods", "--all-namespaces", "-o", gotemplate}, kubecfg...)
return append([]string{"get", "pods", "--all-namespaces", "-o", podTemplate}, kubecfg...)
} else if ki.params.Namespace != "" {
return append([]string{"get", "pods", "-n", ki.params.Namespace, "-o", gotemplate}, kubecfg...)
return append([]string{"get", "pods", "-n", ki.params.Namespace, "-o", podTemplate}, kubecfg...)
}
return append([]string{"get", "pods", "-o", gotemplate}, kubecfg...)
return append([]string{"get", "pods", "-o", podTemplate}, kubecfg...)
}

func (ki *KubeImage) exec() {
process := exec.Command("kubectl", ki.Commands()...)
func (ki *KubeImage) nodeCommands() []string {
kubecfg := make([]string, 0)
if ki.params.KubeConfig != "" {
kubecfg = append(kubecfg, "--kubeconfig", ki.params.KubeConfig)
}

if ki.params.Context != "" {
kubecfg = append(kubecfg, "--context", ki.params.Context)
}

return append([]string{"get", "nodes", "-o", nodeTemplate}, kubecfg...)
}

func (ki *KubeImage) execNodeCommand() {
process := exec.Command("kubectl", ki.nodeCommands()...)
bs, err := process.CombinedOutput()
if err != nil {
fmt.Fprintf(os.Stderr, "[Oh...] Execute nodes command error: %v, %s", err, string(bs))
os.Exit(1)
}

for _, line := range stringSplit(string(bs), "\n") {
items := stringSplit(line, ",")
switch len(items) {
case 3:
size, err := strconv.Atoi(items[2])
if err != nil {
continue
}
ki.imageSize[items[0]] = size
ki.imageSize[items[1]] = size
}
}

for _, entity := range ki.entities {
size, ok := ki.imageSize[entity.Image]
if ok {
entity.ImageSize = humanize.IBytes(uint64(size))
}
}
}

func (ki *KubeImage) execPodCommand() {
process := exec.Command("kubectl", ki.podCommands()...)
bs, err := process.CombinedOutput()
if err != nil {
fmt.Fprintf(os.Stderr, "[Oh...] Execute command error: %v, %s", err, string(bs))
fmt.Fprintf(os.Stderr, "[Oh...] Execute pods command error: %v, %s", err, string(bs))
os.Exit(1)
}

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

// Render renders and displays the table output.
func (ki *KubeImage) Render(format string) {
ki.exec()
ki.execPodCommand()
if ki.needNodeInfo {
ki.execNodeCommand()
}

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