File kubectl-images-0.6.3.obscpio of Package kubectl-images
07070100000000000041ED0000000000000000000000026489DE6B00000000000000000000000000000000000000000000001D00000000kubectl-images-0.6.3/.github07070100000001000041ED0000000000000000000000026489DE6B00000000000000000000000000000000000000000000002700000000kubectl-images-0.6.3/.github/workflows07070100000002000081A40000000000000000000000016489DE6B00000242000000000000000000000000000000000000003300000000kubectl-images-0.6.3/.github/workflows/release.ymlname: release
on:
push:
tags:
- 'v*.*.*'
jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@master
- name: Setup Go
uses: actions/setup-go@v1
with:
go-version: 1.16
- name: GoReleaser
uses: goreleaser/goreleaser-action@v1
with:
version: latest
args: release --rm-dist
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Update new version in krew-index
uses: rajatjindal/krew-release-bot@v0.0.39
07070100000003000081A40000000000000000000000016489DE6B000000EC000000000000000000000000000000000000002000000000kubectl-images-0.6.3/.gitignore# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# IDE
.idea/
.vscode/
.DS_Store
releases/
07070100000004000081A40000000000000000000000016489DE6B00000216000000000000000000000000000000000000002500000000kubectl-images-0.6.3/.goreleaser.ymlbuilds:
- id: kubectl-images
main: ./cmd
binary: kubectl-images
env:
- CGO_ENABLED=0
goos:
- darwin
- linux
- windows
goarch:
- amd64
- arm64
- arm
ignore:
- goos: windows
goarch: arm
- goos: windows
goarch: arm64
- goos: darwin
goarch: arm
archives:
- builds:
- kubectl-images
name_template: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}"
wrap_in_directory: false
format: tar.gz
files:
- LICENSE
07070100000005000081A40000000000000000000000016489DE6B0000099E000000000000000000000000000000000000002000000000kubectl-images-0.6.3/.krew.yamlapiVersion: krew.googlecontainertools.github.com/v1alpha2
kind: Plugin
metadata:
name: images
spec:
version: {{ .TagName }}
homepage: https://github.com/chenjiandongx/kubectl-images
shortDescription: Show container images used in the cluster.
description: |
This plugin shows container images used in the Kubernetes cluster in a
table view. You can show all images or show images used in a specified
namespace.
platforms:
- selector:
matchLabels:
os: darwin
arch: amd64
files:
- from: kubectl-images
to: .
- from: LICENSE
to: .
{{ addURIAndSha "https://github.com/chenjiandongx/kubectl-images/releases/download/{{ .TagName }}/kubectl-images_darwin_amd64.tar.gz" .TagName }}
bin: kubectl-images
- selector:
matchLabels:
os: darwin
arch: arm64
files:
- from: kubectl-images
to: .
- from: LICENSE
to: .
{{ addURIAndSha "https://github.com/chenjiandongx/kubectl-images/releases/download/{{ .TagName }}/kubectl-images_darwin_arm64.tar.gz" .TagName }}
bin: kubectl-images
- selector:
matchLabels:
os: linux
arch: amd64
files:
- from: kubectl-images
to: .
- from: LICENSE
to: .
{{ addURIAndSha "https://github.com/chenjiandongx/kubectl-images/releases/download/{{ .TagName }}/kubectl-images_linux_amd64.tar.gz" .TagName }}
bin: kubectl-images
- selector:
matchLabels:
os: linux
arch: arm64
files:
- from: kubectl-images
to: .
- from: LICENSE
to: .
{{ addURIAndSha "https://github.com/chenjiandongx/kubectl-images/releases/download/{{ .TagName }}/kubectl-images_linux_arm64.tar.gz" .TagName }}
bin: kubectl-images
- selector:
matchLabels:
os: linux
arch: arm
files:
- from: kubectl-images
to: .
- from: LICENSE
to: .
{{ addURIAndSha "https://github.com/chenjiandongx/kubectl-images/releases/download/{{ .TagName }}/kubectl-images_linux_arm.tar.gz" .TagName }}
bin: kubectl-images
- selector:
matchLabels:
os: windows
arch: amd64
files:
- from: kubectl-images.exe
to: .
- from: LICENSE
to: .
{{ addURIAndSha "https://github.com/chenjiandongx/kubectl-images/releases/download/{{ .TagName }}/kubectl-images_windows_amd64.tar.gz" .TagName }}
bin: kubectl-images.exe
07070100000006000081A40000000000000000000000016489DE6B00000432000000000000000000000000000000000000001D00000000kubectl-images-0.6.3/LICENSEMIT License
Copyright (c) 2020~now chenjiandongx
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
07070100000007000081A40000000000000000000000016489DE6B00001FC4000000000000000000000000000000000000001F00000000kubectl-images-0.6.3/README.md<h1 align="center">kubectl-images</h1>
<p align="center">
<em>๐ธ Show container images used in the cluster.</em>
</p>
kubectl-images makes use of the `kubectl` command. It first calls `kubectl get pods` to retrieve pods details and
filters out the container image information of each pod, then prints out the final result in a table/json/yaml view.
### ๐ฐ Installation
Krew
```shell
$ kubectl krew install images
Updated the local copy of plugin index.
Installing plugin: images
Installed plugin: images
\
| Use this plugin:
| kubectl images
| Documentation:
| https://github.com/chenjiandongx/kubectl-images
/
```
Build from source code
```shell
$ git clone https://github.com/chenjiandongx/kubectl-images.git
$ cd kubectl-images && go build -ldflags="-s -w" -o kubectl-images . && mv ./kubectl-images /usr/local/bin
$ kubectl images --help
```
Download the binary
```shell
# Refer to the link: https://github.com/chenjiandongx/kubectl-images/releases
# Download the binary and then...
$ chmod +x kubectl-images && mv kubectl-images /usr/local/bin/
$ kubectl images --help
```
### ๐ Usage
```shell
~ ๐ถ kubectl images --help
Show container images used in the cluster.
Usage:
kubectl-images [podname-regex] [flags]
Examples:
# display a table of all images in current namespace using podName/containerName/containerImage as columns.
kubectl images
# display images info in yaml format
kubectl images -oy
# display a table of images that match 'nginx' podname regex in 'dev' namespace using podName/containerImage as columns.
kubectl images -n dev nginx -c 1,2
Flags:
-A, --all-namespaces if present, list images in all namespaces.
-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")
-C, --context string The name of the kubeconfig context to use.
-h, --help help for kubectl-images
-k, --kubeconfig string path to the kubeconfig file to use for CLI requests.
-n, --namespace string if present, list images in the specified namespace only. Use current namespace as fallback.
-o, --output-format string output format. [json(j)|table(t)|yaml(y)] (default "table")
-u, --unique Unique images group by namespace/container/images/pullPolicy.
--version version for kubectl-images
```
### ๐ Glances
```shell
~ ๐ถ kubectl images -n kube-system -oy dns
- pod: coredns-78fcd69978-9pbjh
container: coredns
image: k8s.gcr.io/coredns/coredns:v1.8.4
- pod: coredns-78fcd69978-jh7m2
container: coredns
image: k8s.gcr.io/coredns/coredns:v1.8.4
~ ๐ถ kubectl images -A -c 0,1,3
[Summary]: 2 namespaces, 11 pods, 11 containers and 9 different images
+-------------+----------------------------------------+--------------------------------------------+
| Namespace | Pod | Image |
+-------------+----------------------------------------+--------------------------------------------+
| kube-system | coredns-78fcd69978-9pbjh | k8s.gcr.io/coredns/coredns:v1.8.4 |
+ +----------------------------------------+ +
| | coredns-78fcd69978-jh7m2 | |
+ +----------------------------------------+--------------------------------------------+
| | etcd-docker-desktop | k8s.gcr.io/etcd:3.5.0-0 |
+ +----------------------------------------+--------------------------------------------+
| | kube-apiserver-docker-desktop | k8s.gcr.io/kube-apiserver:v1.22.5 |
+ +----------------------------------------+--------------------------------------------+
| | kube-controller-manager-docker-desktop | k8s.gcr.io/kube-controller-manager:v1.22.5 |
+ +----------------------------------------+--------------------------------------------+
| | kube-proxy-vc7fv | k8s.gcr.io/kube-proxy:v1.22.5 |
+ +----------------------------------------+--------------------------------------------+
| | kube-scheduler-docker-desktop | k8s.gcr.io/kube-scheduler:v1.22.5 |
+ +----------------------------------------+--------------------------------------------+
| | storage-provisioner | docker/desktop-storage-provisioner:v2.0 |
+ +----------------------------------------+--------------------------------------------+
| | vpnkit-controller | docker/desktop-vpnkit-controller:v2.0 |
+-------------+----------------------------------------+--------------------------------------------+
| nginx | nginx-deployment-66b6c48dd5-s9wv5 | nginx:1.14.2 |
+ +----------------------------------------+ +
| | nginx-deployment-66b6c48dd5-wmn9x | |
+-------------+----------------------------------------+--------------------------------------------+
~ ๐ถ kubectl images -A -c 0,1,3 -u
[Summary]: 2 namespaces, 11 pods, 11 containers and 9 different images
+-------------+----------------------------------------+--------------------------------------------+
| Namespace | Pod | Image |
+-------------+----------------------------------------+--------------------------------------------+
| kube-system | coredns-78fcd69978-9pbjh | k8s.gcr.io/coredns/coredns:v1.8.4 | +
+ +----------------------------------------+--------------------------------------------+
| | etcd-docker-desktop | k8s.gcr.io/etcd:3.5.0-0 |
+ +----------------------------------------+--------------------------------------------+
| | kube-apiserver-docker-desktop | k8s.gcr.io/kube-apiserver:v1.22.5 |
+ +----------------------------------------+--------------------------------------------+
| | kube-controller-manager-docker-desktop | k8s.gcr.io/kube-controller-manager:v1.22.5 |
+ +----------------------------------------+--------------------------------------------+
| | kube-proxy-vc7fv | k8s.gcr.io/kube-proxy:v1.22.5 |
+ +----------------------------------------+--------------------------------------------+
| | kube-scheduler-docker-desktop | k8s.gcr.io/kube-scheduler:v1.22.5 |
+ +----------------------------------------+--------------------------------------------+
| | storage-provisioner | docker/desktop-storage-provisioner:v2.0 |
+ +----------------------------------------+--------------------------------------------+
| | vpnkit-controller | docker/desktop-vpnkit-controller:v2.0 |
+-------------+----------------------------------------+--------------------------------------------+
| nginx | nginx-deployment-66b6c48dd5-s9wv5 | nginx:1.14.2 |
+-------------+----------------------------------------+--------------------------------------------+
~ ๐ถ kubectl images -c 0,1,2,3,4 -n nginx -oj
[
{
"namespace": "nginx",
"pod": "nginx-deployment-66b6c48dd5-s9wv5",
"container": "nginx",
"image": "nginx:latest",
"imagePullPolicy": "IfNotPresent"
},
{
"namespace": "nginx",
"pod": "nginx-deployment-66b6c48dd5-wmn9x",
"container": "nginx",
"image": "nginx:latest",
"imagePullPolicy": "IfNotPresent"
}
]
```
### ๐ License
MIT [ยฉchenjiandongx](https://github.com/chenjiandongx)
07070100000008000041ED0000000000000000000000026489DE6B00000000000000000000000000000000000000000000001900000000kubectl-images-0.6.3/cmd07070100000009000081A40000000000000000000000016489DE6B00000A2D000000000000000000000000000000000000002100000000kubectl-images-0.6.3/cmd/main.gopackage main
import (
"fmt"
"os"
"regexp"
kubeimages "github.com/chenjiandongx/kubectl-images"
"github.com/spf13/cobra"
)
const version = "0.6.3"
var rootCmd *cobra.Command
func init() {
rootCmd = &cobra.Command{
Use: "kubectl-images [podname-regex]",
Short: "Show container images used in the cluster.",
Example: ` # display a table of all images in current namespace using podName/containerName/containerImage as columns.
kubectl images
# display images info in yaml format
kubectl images -oy
# display a table of images that match 'nginx' podname regex in 'dev' namespace using podName/containerImage as columns.
kubectl images -n dev nginx -c 1,2`,
Version: version,
Run: func(cmd *cobra.Command, args []string) {
var regx *regexp.Regexp
var err error
if len(args) > 0 {
if regx, err = regexp.Compile(args[0]); err != nil {
fmt.Fprintf(os.Stderr, "[Oh...] Invalid regex pattern (%q)", args[0])
return
}
}
namespace, _ := cmd.Flags().GetString("namespace")
columns, _ := cmd.Flags().GetString("columns")
format, _ := cmd.Flags().GetString("output-format")
allNamespace, _ := cmd.Flags().GetBool("all-namespaces")
kubeConfig, _ := cmd.Flags().GetString("kubeConfig")
context, _ := cmd.Flags().GetString("context")
unique, _ := cmd.Flags().GetBool("unique")
kubeImage := kubeimages.NewKubeImage(regx, kubeimages.Parameters{
AllNamespace: allNamespace,
Namespace: namespace,
Columns: columns,
KubeConfig: kubeConfig,
Context: context,
Unique: unique,
})
kubeImage.Render(format)
},
}
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, 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.")
rootCmd.Flags().BoolP("unique", "u", false, "Unique images group by namespace/container/images/pullPolicy.")
}
func main() {
if err := rootCmd.Execute(); err != nil {
fmt.Fprintf(os.Stderr, "[Oh...] Failed to exec command: %v", err)
}
}
0707010000000A000081A40000000000000000000000016489DE6B00000170000000000000000000000000000000000000001C00000000kubectl-images-0.6.3/go.modmodule github.com/chenjiandongx/kubectl-images
go 1.18
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
)
require (
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/mattn/go-runewidth v0.0.7 // indirect
github.com/spf13/pflag v1.0.3 // indirect
)
0707010000000B000081A40000000000000000000000016489DE6B00000F36000000000000000000000000000000000000001C00000000kubectl-images-0.6.3/go.sumgithub.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
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=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8=
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
0707010000000C000081A40000000000000000000000016489DE6B000028F7000000000000000000000000000000000000002700000000kubectl-images-0.6.3/kubectl_images.gopackage kubeimage
import (
"encoding/json"
"fmt"
"os"
"os/exec"
"path"
"regexp"
"strconv"
"strings"
"github.com/dustin/go-humanize"
"github.com/olekukonko/tablewriter"
"gopkg.in/yaml.v2"
)
const (
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 {
AllNamespace bool
Namespace string
Columns string
KubeConfig string
Context string
Unique bool
}
// KubeImage is the representation of a container image used in the cluster.
type KubeImage struct {
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 {
case "0":
names = append(names, labelNamespace)
case "1":
names = append(names, labelPod)
case "2":
names = append(names, labelContainer)
case "3":
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,
imageSize: make(map[string]int),
needNodeInfo: needNodeInfo,
}
}
// ImageEntity is the representation of an entity to be displayed.
type ImageEntity struct {
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
Pod string `json:"pod,omitempty" yaml:"pod,omitempty"`
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 {
result := make([]string, 0)
for _, c := range columns {
switch c {
case labelNamespace:
result = append(result, ie.Namespace)
case labelPod:
result = append(result, ie.Pod)
case labelContainer:
result = append(result, ie.Container)
case labelImage:
result = append(result, ie.Image)
case labelImagePullPolicy:
result = append(result, ie.ImagePullPolicy)
case labelImageSize:
result = append(result, ie.ImageSize)
}
}
return result
}
func (ie *ImageEntity) filterBy(columns []string) ImageEntity {
var entity ImageEntity
for _, c := range columns {
switch c {
case labelNamespace:
entity.Namespace = ie.Namespace
case labelPod:
entity.Pod = ie.Pod
case labelContainer:
entity.Container = ie.Container
case labelImage:
entity.Image = ie.Image
case labelImagePullPolicy:
entity.ImagePullPolicy = ie.ImagePullPolicy
case labelImageSize:
entity.ImageSize = ie.ImageSize
}
}
return entity
}
// Counter is a simple counter.
type Counter struct {
cnt int
items map[string]bool
}
// NewCounter creates a new Counter instance.
func NewCounter() *Counter {
return &Counter{items: make(map[string]bool)}
}
func (c *Counter) add(obj string) {
if !c.items[obj] {
c.cnt += 1
c.items[obj] = true
}
}
// Count returns current counter reading.
func (c *Counter) Count() int {
return c.cnt
}
func stringSplit(in, sep string) []string {
out := make([]string, 0)
for _, s := range strings.Split(in, sep) {
out = append(out, strings.TrimSpace(s))
}
return out
}
// 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)
}
if ki.params.Context != "" {
kubecfg = append(kubecfg, "--context", ki.params.Context)
}
if ki.params.AllNamespace {
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", podTemplate}, kubecfg...)
}
return append([]string{"get", "pods", "-o", podTemplate}, kubecfg...)
}
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) recordImageSize(image string, size int) {
ki.imageSize[image] = size
ki.imageSize[path.Base(image)] = size
}
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 2:
size, err := strconv.Atoi(items[1])
if err != nil {
continue
}
ki.recordImageSize(items[0], size)
parts := strings.Split(items[0], ":")
if len(parts) == 2 && parts[1] == "latest" {
ki.recordImageSize(parts[0], size)
}
case 3:
size, err := strconv.Atoi(items[2])
if err != nil {
continue
}
ki.recordImageSize(items[0], size)
ki.recordImageSize(items[1], size)
parts := strings.Split(items[1], ":")
if len(parts) == 2 && parts[1] == "latest" {
ki.recordImageSize(parts[0], 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 pods command error: %v, %s", err, string(bs))
os.Exit(1)
}
entities := make([]*ImageEntity, 0)
for _, line := range stringSplit(string(bs), "\n") {
items := stringSplit(line, ",")
entity := &ImageEntity{}
switch len(items) {
case 1:
continue
case 3:
entity.Container = items[0]
entity.Image = items[1]
entity.ImagePullPolicy = items[2]
case 5:
entity.Namespace = items[0]
entity.Pod = items[1]
entity.Container = items[2]
entity.Image = items[3]
entity.ImagePullPolicy = items[4]
}
entities = append(entities, entity)
}
for i := 0; i < len(entities); i++ {
if entities[i].Pod == "" && i > 0 {
entities[i].Namespace = entities[i-1].Namespace
entities[i].Pod = entities[i-1].Pod
}
}
for i := 0; i < len(entities); i++ {
if ki.regx == nil {
ki.entities = append(ki.entities, entities[i])
continue
}
if ki.regx.Match([]byte(entities[i].Pod)) {
ki.entities = append(ki.entities, entities[i])
}
}
}
func (ki *KubeImage) groupBy() []*ImageEntity {
if !ki.params.Unique {
return ki.entities
}
set := make(map[string]struct{})
entities := make([]*ImageEntity, 0)
for i, entity := range ki.entities {
k := fmt.Sprintf("%s/%s/%s/%s", entity.Namespace, entity.Container, entity.Image, entity.ImagePullPolicy)
if _, ok := set[k]; ok {
continue
}
set[k] = struct{}{}
entities = append(entities, ki.entities[i])
}
return entities
}
func (ki *KubeImage) summary() {
namespaceCnt := NewCounter()
podCnt := NewCounter()
imageCnt := NewCounter()
containerCnt := 0
for i := 0; i < len(ki.entities); i++ {
namespaceCnt.add(ki.entities[i].Namespace)
podCnt.add(ki.entities[i].Pod)
imageCnt.add(ki.entities[i].Image)
containerCnt += 1
}
fmt.Fprintf(os.Stdout, "[Summary]: %d namespaces, %d pods, %d containers and %d different images\n",
namespaceCnt.Count(), podCnt.Count(), containerCnt, imageCnt.Count(),
)
}
func (ki *KubeImage) tableRender() {
table := tablewriter.NewWriter(os.Stdout)
table.SetHeader(ki.columns)
table.SetAutoFormatHeaders(false)
table.SetAutoMergeCells(true)
table.SetRowLine(true)
entities := ki.getGroupByEntities()
for _, entity := range entities {
table.Append(entity)
}
table.Render()
}
func (ki *KubeImage) getGroupByEntities() [][]string {
set := make(map[string]struct{})
dst := make([][]string, 0)
for _, entity := range ki.groupBy() {
line := strings.Join(entity.selectBy(ki.columns), "||")
_, ok := set[line]
if !ok {
set[line] = struct{}{}
dst = append(dst, strings.Split(line, "||"))
}
}
return dst
}
func (ki *KubeImage) jsonRender() {
entities := ki.groupBy()
records := make([]ImageEntity, 0, len(entities))
for _, entity := range entities {
records = append(records, entity.filterBy(ki.columns))
}
output, err := json.MarshalIndent(records, "", " ")
if err != nil {
fmt.Fprintf(os.Stderr, "[Oh...] Failed to marshal JSON data, error: %v", err)
os.Exit(1)
}
fmt.Fprintln(os.Stdout, string(output))
}
func (ki *KubeImage) yamlRender() {
entities := ki.groupBy()
records := make([]ImageEntity, 0, len(entities))
for _, entity := range entities {
records = append(records, entity.filterBy(ki.columns))
}
output, err := yaml.Marshal(records)
if err != nil {
fmt.Fprintf(os.Stderr, "[Oh...] Failed to marshal YAML data, error: %v", err)
os.Exit(1)
}
fmt.Fprintln(os.Stdout, string(output))
}
// Render renders and displays the table output.
func (ki *KubeImage) Render(format string) {
ki.execPodCommand()
if ki.needNodeInfo {
ki.execNodeCommand()
}
if len(ki.entities) == 0 {
fmt.Fprintln(os.Stdout, "[Oh...] No images matched!")
return
}
switch format {
case "json", "j":
ki.jsonRender()
case "yaml", "y":
ki.yamlRender()
default: // table
ki.summary()
ki.tableRender()
}
}
07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!64 blocks