Skip to content

Commit

Permalink
restructure folders, added create from file-content, added brief outp…
Browse files Browse the repository at this point in the history
…ut in compare, added invert filter in compare
  • Loading branch information
Hans Brinck committed Jun 8, 2021
1 parent 7c2bc96 commit 00e9536
Show file tree
Hide file tree
Showing 18 changed files with 173 additions and 317 deletions.
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@

build:
go build -o vpa .
go build -o vpa .

install:
go install .
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ or using the kubectl-plugin-behavior
kubectl vpa ...
```

### Quick-start
This will create a VPA-resource for all runnings pods that dont yet have one (with UpdateMode = Off)
```sh
kubectl-vpa compare -A -! -b | kubectl-vpa create -f - | kubectl apply -f -
```

### Help and options
All command have their own help. Example:
```sh
Expand Down
Binary file added bin/kubectl-vpa
Binary file not shown.
3 changes: 0 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ require (
github.com/mickep76/encoding v0.0.0-20191112132937-4a810d6b3199
github.com/ninlil/ansi v1.1.0
github.com/ninlil/columns v1.0.0
github.com/ninlil/kubectl-vpa/vpa_v1 v0.0.0
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c // indirect
golang.org/x/sys v0.0.0-20210603125802-9665404d3644 // indirect
golang.org/x/term v0.0.0-20210503060354-a79de5458b56 // indirect
Expand All @@ -22,6 +21,4 @@ require (
k8s.io/utils v0.0.0-20210527160623-6fdb442a123b // indirect
)

replace github.com/ninlil/kubectl-vpa/vpa_v1 => ./vpa_v1

replace github.com/ninlil/columns => ../columns
7 changes: 7 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,12 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
Expand Down Expand Up @@ -158,6 +160,7 @@ github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
Expand Down Expand Up @@ -292,6 +295,7 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7 h1:OgUuv8lsRpBibGNbSizVwKWlysjaNzmC9gYMhPVfqFM=
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5 h1:wjuX4b5yYQnEQHzd+CBcrcC6OVR2J1CN6mUy0oSxIPo=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
Expand Down Expand Up @@ -355,6 +359,7 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
Expand Down Expand Up @@ -525,6 +530,7 @@ k8s.io/client-go v0.21.1 h1:bhblWYLZKUu+pm50plvQF8WpY6TXdRRtcS/K9WauOj4=
k8s.io/client-go v0.21.1/go.mod h1:/kEw4RgW+3xnBGzvp9IWxKSNA+lXn3A7AuH3gdOAzLs=
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
k8s.io/klog/v2 v2.8.0 h1:Q3gmuM9hKEjefWFFYF0Mat+YyFJvsUyYuwyNNJ5C9Ts=
k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec=
k8s.io/klog/v2 v2.9.0 h1:D7HV+n1V57XeZ0m6tdRkfknthUaM06VFbWldOFh8kzM=
k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec=
Expand All @@ -536,6 +542,7 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
sigs.k8s.io/structured-merge-diff/v4 v4.1.0 h1:C4r9BgJ98vrKnnVCjwCSXcWjWe0NKcUQkmzDXZXGwH8=
sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
sigs.k8s.io/structured-merge-diff/v4 v4.1.1 h1:nYqY2A6oy37sKLYuSBXuQhbj4JVclzJK13BOIvJG5XU=
sigs.k8s.io/structured-merge-diff/v4 v4.1.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
Expand Down
25 changes: 11 additions & 14 deletions args.go → internal/app/args.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package main
package app

import (
"fmt"
Expand All @@ -25,29 +25,26 @@ type cmdArgs struct {
Create *createArgs `arg:"subcommand:create" help:"Create a VPA-YAML from a pod"`
}

type compareFilter struct {
filter bool
showOff bool
showInitial bool
showAuto bool
}

type modeEnum int

const (
modeOff modeEnum = iota + 1
modeInitial
modeAuto

modeOffText = "Off"
modeInitialText = "Initial"
modeAutoText = "Auto"
)

func (mode modeEnum) String() string {
switch mode {
case modeInitial:
return "Initial"
return modeInitialText
case modeAuto:
return "Auto"
return modeAutoText
default:
return "Off"
return modeOffText
}
}

Expand All @@ -56,7 +53,7 @@ func (mode *modeEnum) UnmarshalText(b []byte) error {
switch s {
case "off":
*mode = modeOff
case "initial":
case "initial", "init":
*mode = modeInitial
case "auto":
*mode = modeAuto
Expand All @@ -67,10 +64,10 @@ func (mode *modeEnum) UnmarshalText(b []byte) error {
}

func (cmdArgs) Version() string {
return "vpa 0.5.0"
return "vpa 0.7.0"
}

func parseArgs() (subcommand, *cmdArgs, bool) {
func ParseArgs() (subcommand, *cmdArgs, bool) {
var args cmdArgs
pa := arg.MustParse(&args)
if pa == nil {
Expand Down
120 changes: 81 additions & 39 deletions compare.go → internal/app/compare.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package main
package app

import (
"context"
Expand All @@ -16,13 +16,22 @@ import (
)

type compareArgs struct {
AllPods bool `arg:"-l,--all-pods" help:"all pods, even those without a VPA"`
Modes []modeEnum `arg:"-m,--mode,separate" help:"filter only VPAs with specified mode(s)" placeholder:"MODE"`
Head int `arg:"-h,--head" help:"only print N first lines" default:"-1"`
Tail int `arg:"-t,--tail" help:"only print N last lines" default:"-1"`
Sort []int `arg:"-s,--sort,separate" help:"sort by column N (negative sorts descending)"`
Sum bool `arg:"-z,--sum" help:"add sums to relevant value columns"`
filter compareFilter `arg:"-"`
AllPods bool `arg:"-l,--all-pods" help:"all pods, even those without a VPA"`
Modes []modeEnum `arg:"-m,--mode,separate" help:"filter only VPAs with specified mode(s)" placeholder:"MODE"`
InvertFilter bool `arg:"-!,--invert" help:"invert the mode-filter"`
Brief bool `arg:"-b,--brief" help:"Show in brief format (namespace/vpa_name)"`
Head int `arg:"-h,--head" help:"only print N first lines" default:"-1"`
Tail int `arg:"-t,--tail" help:"only print N last lines" default:"-1"`
Sort []int `arg:"-s,--sort,separate" help:"sort by column N (negative sorts descending)"`
Sum bool `arg:"-z,--sum" help:"add sums to relevant value columns"`
filter compareFilter `arg:"-"`
}

type compareFilter struct {
filter bool
showOff bool
showInitial bool
showAuto bool
}

func (comp *compareArgs) Verify() error {
Expand All @@ -39,6 +48,12 @@ func (comp *compareArgs) Verify() error {
comp.filter.showAuto = true
}
}
if comp.InvertFilter && !comp.filter.filter {
comp.filter.filter = true
comp.filter.showOff = true
comp.filter.showInitial = true
comp.filter.showAuto = true
}
return nil
}

Expand Down Expand Up @@ -134,19 +149,23 @@ func (comp *compareArgs) Exec(k8 *k8client, args *cmdArgs) {
}
}

cw := columns.New(os.Stdout, "< < < < > > > > > > >")
cw.Headers("Namespace", "Name", "Mode", "Container", "Req-CPU", "VPA-CPU", "CPU diff%", "Req-RAM", "VPA-RAM", "Mem. diff%", "sum(Δ)")
cw.HeaderSeparator = true
if comp.Sum {
cw.Footer(5, columns.Sum(0))
cw.Footer(6, columns.Sum(0))
cw.Footer(8, columns.Sum(0))
cw.Footer(9, columns.Sum(0))
var cw *columns.Writer
if !comp.Brief {
cw = columns.New(os.Stdout, "< < < < > > > > > > >")
cw.Headers("Namespace", "Name", "Mode", "Container", "Req-CPU", "VPA-CPU", "CPU diff%", "Req-RAM", "VPA-RAM", "Mem. diff%", "sum(Δ)")
cw.HeaderSeparator = true
if comp.Sum {
cw.Footer(5, columns.Sum(0))
cw.Footer(6, columns.Sum(0))
cw.Footer(8, columns.Sum(0))
cw.Footer(9, columns.Sum(0))
}
}

diffStyle := columns.NewStyle().Suffix("%").ColorFunc(colorDiff)

var haveVPA bool
var printed map[string]bool
for _, pod := range podList {

for cname, c := range pod.containers {
Expand Down Expand Up @@ -174,40 +193,63 @@ func (comp *compareArgs) Exec(k8 *k8client, args *cmdArgs) {
} else {
cols = append(cols, "---", cname, c.cpu, nil, nil, mem2mb(c.memory), nil, nil)
}
if args.Compare.AllPods || haveVPA {
if args.Compare.AllPods || haveVPA || args.Compare.InvertFilter {
show := false
if args.Compare.filter.filter && pod.vpa != nil {
if args.Compare.filter.showOff && pod.vpa.mode == "Off" {
show = true
}
if args.Compare.filter.showInitial && pod.vpa.mode == "Initial" {
show = true
}
if args.Compare.filter.showAuto && pod.vpa.mode == "Auto" {
show = true
if args.Compare.filter.filter {
if pod.vpa != nil {
if args.Compare.filter.showOff && pod.vpa.mode == modeOffText {
show = true
}
if args.Compare.filter.showInitial && pod.vpa.mode == modeInitialText {
show = true
}
if args.Compare.filter.showAuto && pod.vpa.mode == modeAutoText {
show = true
}
}
} else {
show = true
}
if show {
cw.Write(cols...)
if show != args.Compare.InvertFilter {
var brief string
if comp.Brief {
switch true {
case pod.vpa != nil:
brief = fmt.Sprintf("%s/%s", pod.namespace, pod.vpa.name)
case pod.ownerName != "":
brief = fmt.Sprintf("%s/%s", pod.namespace, pod.ownerName)
default:
brief = fmt.Sprintf("%s/%s", pod.namespace, pod.name)
}
if printed == nil {
printed = make(map[string]bool)
}
if !printed[brief] {
fmt.Println(brief)
printed[brief] = true
}
} else {
cw.Write(cols...)
}
}
}
}
}

if args.Compare.Head >= 0 {
cw.Head(args.Compare.Head)
}
if args.Compare.Tail >= 0 {
cw.Tail(args.Compare.Tail)
}
if len(args.Compare.Sort) > 0 {
cw.Sort(args.Compare.Sort...)
} else {
cw.Sort(1, 2, 4)
if !comp.Brief {
if args.Compare.Head >= 0 {
cw.Head(args.Compare.Head)
}
if args.Compare.Tail >= 0 {
cw.Tail(args.Compare.Tail)
}
if len(args.Compare.Sort) > 0 {
cw.Sort(args.Compare.Sort...)
} else {
cw.Sort(1, 2, 4)
}
cw.Flush()
}
cw.Flush()
}

func colorDiff(o interface{}) (ansi.Style, bool) {
Expand Down
46 changes: 41 additions & 5 deletions create.go → internal/app/create.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main
package app

import (
"bufio"
"fmt"
"log"
"os"
Expand All @@ -12,13 +13,14 @@ import (
)

type createArgs struct {
Names []string `arg:"positional,required" help:"Pod-name(s)to create VPA for" placeholder:"NAME"`
Mode modeEnum `arg:"-m,--mode" help:"Assign the VPA mode to the output"`
Format formatEnum `arg:"-o,--output-format" help:"Select output format (yaml [default], json, toml)"`
Names []string `arg:"positional" help:"Pod-name(s)to create VPA for" placeholder:"NAME"`
Mode modeEnum `arg:"-m,--mode" help:"Assign the VPA mode to the output"`
Filenames []string `arg:"-f,--filename,separate" help:"Read names from input file (or '-' for stdin)"`
Format formatEnum `arg:"-o,--output-format" help:"Select output format (yaml [default], json, toml)"`
}

func (cr *createArgs) Verify() error {
if len(cr.Names) == 0 {
if len(cr.Names) == 0 && len(cr.Filenames) == 0 {
return fmt.Errorf("no names specified")
}
return nil
Expand All @@ -36,6 +38,10 @@ func (cr *createArgs) Exec(k8 *k8client, args *cmdArgs) {
return
}

for _, filename := range cr.Filenames {
cr.Names = append(cr.Names, linesFromFile(filename)...)
}

for _, input := range cr.Names {
ns, name := args.getParts(input)

Expand All @@ -52,6 +58,36 @@ func (cr *createArgs) Exec(k8 *k8client, args *cmdArgs) {
}
}

func linesFromFile(filename string) []string {
var lines []string

var file *os.File
var err error
if filename == "-" {
file = os.Stdin
} else {
file, err = os.Open(filename)
if err != nil {
log.Fatal(err)
}
defer file.Close()
}

scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
if len(line) > 0 {
lines = append(lines, line)
}
}

if err := scanner.Err(); err != nil {
log.Fatal(err)
}

return lines
}

type vpaRoot struct {
APIVersion string `yaml:"apiVersion"`
Kind string `yaml:"kind"`
Expand Down
Loading

0 comments on commit 00e9536

Please sign in to comment.