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
openSUSE Build Service is sponsored by