fix config reloads, added filter history + bug fixes
parent
e231f18a79
commit
7d8277dfe9
|
|
@ -13,7 +13,7 @@ builds:
|
|||
- darwin
|
||||
- windows
|
||||
goarch:
|
||||
- 386
|
||||
# - 386
|
||||
- amd64
|
||||
- arm64
|
||||
- arm
|
||||
|
|
@ -32,7 +32,7 @@ archives:
|
|||
bit: Arm
|
||||
bitv6: Arm6
|
||||
bitv7: Arm7
|
||||
386: i386
|
||||
# 386: i386
|
||||
amd64: x86_64
|
||||
checksum:
|
||||
name_template: "checksums.txt"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,70 @@
|
|||
<img src="https://raw.githubusercontent.com/derailed/k9s/master/assets/k9s_small.png" align="right" width="200" height="auto"/>
|
||||
|
||||
# Release v0.19.3
|
||||
|
||||
## Notes
|
||||
|
||||
Thank you to all that contributed with flushing out issues and enhancements for K9s! I'll try to mark some of these issues as fixed. But if you don't mind grab the latest rev and see if we're happier with some of the fixes! If you've filed an issue please help me verify and close. Your support, kindness and awesome suggestions to make K9s better is as ever very much noticed and appreciated!
|
||||
|
||||
Also if you dig this tool, consider joining our [sponsorhip program](https://github.com/sponsors/derailed) and/or make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
|
||||
|
||||
On Slack? Please join us [K9slackers](https://join.slack.com/t/k9sers/shared_invite/enQtOTA5MDEyNzI5MTU0LWQ1ZGI3MzliYzZhZWEyNzYxYzA3NjE0YTk1YmFmNzViZjIyNzhkZGI0MmJjYzhlNjdlMGJhYzE2ZGU1NjkyNTM)
|
||||
|
||||
---
|
||||
|
||||
## Look Who Is Back?
|
||||
|
||||
Thanks to the good Helm folks, we're now back on par with the Helm charts support feature. As you may recall, when we've updated to K8s v1.18, the Helm feature took one for the team ;( as they had yet to upgrade to the latest k8s rev. So K9s Helm chart feature is back in this drop! On that note, we've added new aliases to allow you to view your currently installed Helm charts aka `helm` | `hm` | `chart` | `charts`.
|
||||
|
||||
## Boh-Bye Windows 386!
|
||||
|
||||
As of this drop, I've decided to axe Windows 386 support. Our good friend [Guy Barrette](https://github.com/guybarrette) reported K9s Windows-386 binary is triping his virus scanner. After double checking my installed shas/binaries/dependencies/etc... and performing vulnerabily scans on various win-i386 K9s binaries, I just could not figure out which dependencies are causing the exec to bomb on the scans??
|
||||
|
||||
Note: This does not necessary entails that there is a deliberate or malicious intent with the software, but likely a false positive thrown by the Windows virus scanner. This has been [reported](https://golang.org/doc/faq#virus) with other GO binaries on windows as well ;(
|
||||
|
||||
That said, I've repeatdly scanned the K9s Windows-x64 and ended up with a clean bill of health on every single scans. So I've decided to drop the 386 windows support for the time being. If that causes you some grief, please land a hand as I am fresh out of ideas...
|
||||
|
||||
## And Now For Something A Bit More... Controversial?
|
||||
|
||||
There has been a lot of requests for K9s to support shelling directly into cluster nodes. I was resisting the temptation to support this useful feature as depending on your cluster hosting solution, this involved less than ideal solutions. My clusters are provisioned in a multitude of platforms ranging from bare metal to cloud vendor self/managed hosting. I wanted the same experience shelling into an GKE/AWS node as a local KiND cluster node. To this end, we've opted to experimentally support shelling into nodes using the following approach:
|
||||
|
||||
1. While in the Node view, we are introducing a new `s` mnemonic to shell into nodes on your cluster.
|
||||
2. K9s will spin up a `k9s-shell` pod in the `default` namespace with an official Busybox container running in `privileged` mode. This may require extra RBAC and PSPs (This will need Docs!)
|
||||
3. Once shelled-in, you can poke around any of your nodes.
|
||||
4. Upon exiting the node shell, K9s will automatically delete the `k9s-shell` pod for that node.
|
||||
|
||||
This feature is `OPT-IN` only ie you will need to manually enable the feature gate to make this functionality available to K9s on a specific cluster as follows:
|
||||
|
||||
```yaml
|
||||
# $HOME/.k9s/config.yml
|
||||
k9s:
|
||||
...
|
||||
clusters:
|
||||
fred:
|
||||
namespace:
|
||||
active: "default"
|
||||
favorites:
|
||||
- default
|
||||
view:
|
||||
active: po
|
||||
featureGates:
|
||||
nodeShell: true # Defaults to false!
|
||||
```
|
||||
|
||||
Please let us know if you dig this feature? This very much experimental and we're open to your suggestions. Thank you!
|
||||
|
||||
## New Sheriff In Town K9S_EDITOR
|
||||
|
||||
As you may know K9s currently uses your `EDITOR` env var to launch an editor while editing a k8s resource or viewing a screen dump or a performance benchmark. So folks voiced they are using some editors that require different CLI args when editing k8s resources vs files on disk. In this drop, we're introducing a new env var `K9S_EDITOR` to provide an affordance to deal with these discrepancies. If you are using emacs/vi/nano no action should be required. K9s will now check for `K9S_EDITOR` existence to view K9s artifacts such as screen_dumps. K9s still honors `KUBE_EDITOR` or `EDITOR` for K8s resource edits. K9s will fallback to the `EDITOR` env var if `K9S_EDITOR` is not set.
|
||||
|
||||
## Resolved Bugs/Features/PRs
|
||||
|
||||
* [Issue #669](https://github.com/derailed/k9s/issues/669)
|
||||
* [Issue #677](https://github.com/derailed/k9s/issues/677)
|
||||
* [Issue #673](https://github.com/derailed/k9s/issues/673)
|
||||
* [Issue #671](https://github.com/derailed/k9s/issues/671)
|
||||
* [Issue #670](https://github.com/derailed/k9s/issues/670)
|
||||
|
||||
---
|
||||
|
||||
<img src="https://raw.githubusercontent.com/derailed/k9s/master/assets/imhotep_logo.png" width="32" height="auto"/> © 2020 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
|
||||
16
go.mod
16
go.mod
|
|
@ -21,18 +21,18 @@ require (
|
|||
github.com/rs/zerolog v1.18.0
|
||||
github.com/ryanuber/go-glob v1.0.0 // indirect
|
||||
github.com/sahilm/fuzzy v0.1.0
|
||||
github.com/spf13/cobra v0.0.6
|
||||
github.com/spf13/cobra v1.0.0
|
||||
github.com/stretchr/testify v1.5.1
|
||||
golang.org/x/text v0.3.2
|
||||
gopkg.in/yaml.v2 v2.2.8
|
||||
helm.sh/helm/v3 v3.1.2
|
||||
k8s.io/api v0.18.0
|
||||
k8s.io/apimachinery v0.18.0
|
||||
k8s.io/cli-runtime v0.18.0
|
||||
k8s.io/client-go v0.18.0
|
||||
helm.sh/helm/v3 v3.2.0
|
||||
k8s.io/api v0.18.2
|
||||
k8s.io/apimachinery v0.18.2
|
||||
k8s.io/cli-runtime v0.18.2
|
||||
k8s.io/client-go v0.18.2
|
||||
k8s.io/klog v1.0.0
|
||||
k8s.io/kubectl v0.18.0
|
||||
k8s.io/metrics v0.18.0
|
||||
k8s.io/kubectl v0.18.2
|
||||
k8s.io/metrics v0.18.2
|
||||
sigs.k8s.io/yaml v1.2.0
|
||||
vbom.ml/util v0.0.0-20180919145318-efcd4e0f9787
|
||||
)
|
||||
|
|
|
|||
91
go.sum
91
go.sum
|
|
@ -32,14 +32,21 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
|
|||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/DATA-DOG/go-sqlmock v1.3.3 h1:CWUqKXe0s8A2z6qCgkP4Kru7wC11YoAnoupUKFDnH08=
|
||||
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||
github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||
github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd h1:sjQovDkwrZp8u+gxLtPgKGjk5hCxuy2hrRejBTA9xFU=
|
||||
github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E=
|
||||
github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg=
|
||||
github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||
github.com/Masterminds/semver/v3 v3.0.3 h1:znjIyLfpXEDQjOIEWh+ehwpTU14UzUPub3c3sm36u14=
|
||||
github.com/Masterminds/semver/v3 v3.0.3/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
||||
github.com/Masterminds/semver/v3 v3.1.0 h1:Y2lUDsFKVRSYGojLJ1yLxSXdMmMYTYls0rCvoqmMUQk=
|
||||
github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
||||
github.com/Masterminds/sprig/v3 v3.0.2 h1:wz22D0CiSctrliXiI9ZO3HoNApweeRGftyDN+BQa3B8=
|
||||
github.com/Masterminds/sprig/v3 v3.0.2/go.mod h1:oesJ8kPONMONaZgtiHNzUShJbksypC5kWczhZAf6+aU=
|
||||
github.com/Masterminds/sprig/v3 v3.1.0 h1:j7GpgZ7PdFqNsmncycTHsLmVPf5/3wJtlgW9TNDYD9Y=
|
||||
github.com/Masterminds/sprig/v3 v3.1.0/go.mod h1:ONGMf7UfYGAbMXCZmQLy8x3lCDIPrEZE/rU8pmrbihA=
|
||||
github.com/Masterminds/squirrel v1.2.0 h1:K1NhbTO21BWG47IVR0OnIZuE0LZcXAYqywrC3Ko53KI=
|
||||
github.com/Masterminds/squirrel v1.2.0/go.mod h1:yaPeOnPG5ZRwL9oKdTsO/prlkPbXWZlRVMQ/gGlzIuA=
|
||||
github.com/Masterminds/vcs v1.13.1/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA=
|
||||
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
|
||||
github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ=
|
||||
|
|
@ -60,6 +67,7 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
|
|||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||
github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496 h1:zV3ejI06GQ59hwDQAvmK1qxOQGB3WuVTRoY0okPTAv0=
|
||||
|
|
@ -125,6 +133,7 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
|||
github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE=
|
||||
github.com/deislabs/oras v0.8.1 h1:If674KraJVpujYR00rzdi0QAmW4BxzMJPVAZJKuhQ0c=
|
||||
github.com/deislabs/oras v0.8.1/go.mod h1:Mx0rMSbBNaNfY9hjpccEnxkOqJL6KGjtxNHPLC4G4As=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191001013358-cfbb681360f0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0=
|
||||
github.com/derailed/popeye v0.8.1 h1:N69XH0NZTBkrNj8qvUzy6Z6bP7+jx0AwollETqvc3dc=
|
||||
github.com/derailed/popeye v0.8.1/go.mod h1:OBHcJDa50VpE9QNyOU243bNOtHb29MyLlVHJolwlwas=
|
||||
|
|
@ -243,8 +252,15 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh
|
|||
github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
|
||||
github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA=
|
||||
github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
|
||||
github.com/gobuffalo/envy v1.7.1/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w=
|
||||
github.com/gobuffalo/logger v1.0.1/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs=
|
||||
github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q=
|
||||
github.com/gobuffalo/packr/v2 v2.7.1/go.mod h1:qYEvAazPaVxy7Y7KR0W8qYEE+RymX74kETFqjFoFlOc=
|
||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
|
||||
|
|
@ -254,6 +270,7 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV
|
|||
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
|
||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef h1:veQD95Isof8w9/WXiA+pa3tz3fJXkt5B7QaRBrM62gk=
|
||||
|
|
@ -309,7 +326,9 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf
|
|||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
|
|
@ -318,15 +337,22 @@ github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
|||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/huandu/xstrings v1.2.0 h1:yPeWdRnmynF7p+lLYz0H2tthW9lqhMJrQV/U7yy4wX0=
|
||||
github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4=
|
||||
github.com/huandu/xstrings v1.3.1 h1:4jgBlKK6tLKFvO8u5pmYjG91cqytmDCDvGh7ECVFfFs=
|
||||
github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI=
|
||||
github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ=
|
||||
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA=
|
||||
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
|
||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
|
|
@ -342,6 +368,8 @@ github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQL
|
|||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
|
|
@ -351,6 +379,14 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
|||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw=
|
||||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk=
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU=
|
||||
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
|
||||
github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=
|
||||
|
|
@ -370,6 +406,7 @@ github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHef
|
|||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM=
|
||||
|
|
@ -380,8 +417,12 @@ github.com/mattn/go-runewidth v0.0.5/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m
|
|||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-shellwords v1.0.9/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
|
||||
github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
|
||||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/go-sqlite3 v1.12.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
|
||||
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
|
|
@ -408,6 +449,8 @@ github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+
|
|||
github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||
github.com/olekukonko/tablewriter v0.0.2/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2fSBUmeGDbRWPxyQ=
|
||||
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
|
|
@ -449,6 +492,7 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
|||
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
|
||||
github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
|
|
@ -484,9 +528,15 @@ github.com/rivo/uniseg v0.0.0-20190513083848-b9f5b9457d44/go.mod h1:J6wj4VEh+S6Z
|
|||
github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY=
|
||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.4.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||
github.com/rs/zerolog v1.18.0 h1:CbAm3kP2Tptby1i9sYy2MGRg0uxIN9cyDb59Ys7W8z8=
|
||||
github.com/rs/zerolog v1.18.0/go.mod h1:9nvC1axdVrAHcu/s9taAVfBuIdTZLVQmKQyvrUjF5+I=
|
||||
github.com/rubenv/sql-migrate v0.0.0-20200212082348-64f95ea68aa3 h1:xkBtI5JktwbW/vf4vopBbhYsRFTGfQWHYXzC0/qYwxI=
|
||||
github.com/rubenv/sql-migrate v0.0.0-20200212082348-64f95ea68aa3/go.mod h1:rtQlpHw+eR6UrqaS3kX1VYeaCxzCVdimDS7g5Ln4pPc=
|
||||
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
|
|
@ -510,11 +560,15 @@ github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B
|
|||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
|
||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
github.com/spf13/cobra v0.0.6 h1:breEStsVwemnKh2/s6gMvSdMEkwW0sK8vGStnlVBMCs=
|
||||
github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
||||
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
|
||||
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
|
|
@ -557,6 +611,7 @@ github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX
|
|||
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
|
||||
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
|
||||
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
|
||||
|
|
@ -577,14 +632,18 @@ golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnf
|
|||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975 h1:/Tl7pH94bvbAAHBdZJT947M/+gp0+CqQXDtMRC0fseo=
|
||||
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904 h1:bXoxMPcSLOq08zI3/c5dEBT6lE4eh+jOh886GHrn6V8=
|
||||
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
|
|
@ -609,6 +668,7 @@ golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn
|
|||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
|
|
@ -629,6 +689,7 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
|
@ -644,6 +705,7 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
|
@ -679,6 +741,7 @@ golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgw
|
|||
golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190828213141-aed303cbaa74/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
|
@ -691,6 +754,7 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl
|
|||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
|
|
@ -705,6 +769,7 @@ google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiq
|
|||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
|
||||
|
|
@ -715,9 +780,12 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
|
|||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
|
||||
gopkg.in/gorp.v1 v1.7.2 h1:j3DWlAyGVv8whO7AcIWznQ2Yj7yJkn34B8s63GViAAw=
|
||||
gopkg.in/gorp.v1 v1.7.2/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw=
|
||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||
|
|
@ -736,29 +804,47 @@ gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
|||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
helm.sh/helm/v3 v3.1.2 h1:VpNzaNv2DX4aRnOCcV7v5Of+XT2SZrJ8iOQ25AGKOos=
|
||||
helm.sh/helm/v3 v3.1.2/go.mod h1:WYsFJuMASa/4XUqLyv54s0U/f3mlAaRErGmyy4z921g=
|
||||
helm.sh/helm/v3 v3.2.0-rc.1 h1:P5Aui2Q+P9eQYmRxdIgOKPatxEPd8yRUVFaOTdUvDYE=
|
||||
helm.sh/helm/v3 v3.2.0-rc.1/go.mod h1:ZaXz/vzktgwjyGGFbUWtIQkscfE7WYoRGP2szqAFHR0=
|
||||
helm.sh/helm/v3 v3.2.0 h1:V12EGAmr2DJ/fWrPo2fPdXWSIXvlXm51vGkQIXMeymE=
|
||||
helm.sh/helm/v3 v3.2.0/go.mod h1:ZaXz/vzktgwjyGGFbUWtIQkscfE7WYoRGP2szqAFHR0=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
k8s.io/api v0.17.2/go.mod h1:BS9fjjLc4CMuqfSO8vgbHPKMt5+SF0ET6u/RVDihTo4=
|
||||
k8s.io/api v0.18.0 h1:lwYk8Vt7rsVTwjRU6pzEsa9YNhThbmbocQlKvNBB4EQ=
|
||||
k8s.io/api v0.18.0/go.mod h1:q2HRQkfDzHMBZL9l/y9rH63PkQl4vae0xRT+8prbrK8=
|
||||
k8s.io/api v0.18.2 h1:wG5g5ZmSVgm5B+eHMIbI9EGATS2L8Z72rda19RIEgY8=
|
||||
k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78=
|
||||
k8s.io/apiextensions-apiserver v0.17.2 h1:cP579D2hSZNuO/rZj9XFRzwJNYb41DbNANJb6Kolpss=
|
||||
k8s.io/apiextensions-apiserver v0.17.2/go.mod h1:4KdMpjkEjjDI2pPfBA15OscyNldHWdBCfsWMDWAmSTs=
|
||||
k8s.io/apiextensions-apiserver v0.18.0 h1:HN4/P8vpGZFvB5SOMuPPH2Wt9Y/ryX+KRvIyAkchu1Q=
|
||||
k8s.io/apiextensions-apiserver v0.18.0/go.mod h1:18Cwn1Xws4xnWQNC00FLq1E350b9lUF+aOdIWDOZxgo=
|
||||
k8s.io/apimachinery v0.17.2/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg=
|
||||
k8s.io/apimachinery v0.18.0 h1:fuPfYpk3cs1Okp/515pAf0dNhL66+8zk8RLbSX+EgAE=
|
||||
k8s.io/apimachinery v0.18.0/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA=
|
||||
k8s.io/apimachinery v0.18.2 h1:44CmtbmkzVDAhCpRVSiP2R5PPrC2RtlIv/MoB8xpdRA=
|
||||
k8s.io/apimachinery v0.18.2/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA=
|
||||
k8s.io/apiserver v0.17.2/go.mod h1:lBmw/TtQdtxvrTk0e2cgtOxHizXI+d0mmGQURIHQZlo=
|
||||
k8s.io/apiserver v0.18.0/go.mod h1:3S2O6FeBBd6XTo0njUrLxiqk8GNy6wWOftjhJcXYnjw=
|
||||
k8s.io/cli-runtime v0.17.2/go.mod h1:aa8t9ziyQdbkuizkNLAw3qe3srSyWh9zlSB7zTqRNPI=
|
||||
k8s.io/cli-runtime v0.18.0 h1:jG8XpSqQ5TrV0N+EZ3PFz6+gqlCk71dkggWCCq9Mq34=
|
||||
k8s.io/cli-runtime v0.18.0/go.mod h1:1eXfmBsIJosjn9LjEBUd2WVPoPAY9XGTqTFcPMIBsUQ=
|
||||
k8s.io/cli-runtime v0.18.2 h1:JiTN5RgkFNTiMxHBRyrl6n26yKWAuNRlei1ZJALUmC8=
|
||||
k8s.io/cli-runtime v0.18.2/go.mod h1:yfFR2sQQzDsV0VEKGZtrJwEy4hLZ2oj4ZIfodgxAHWQ=
|
||||
k8s.io/client-go v0.17.2/go.mod h1:QAzRgsa0C2xl4/eVpeVAZMvikCn8Nm81yqVx3Kk9XYI=
|
||||
k8s.io/client-go v0.18.0 h1:yqKw4cTUQraZK3fcVCMeSa+lqKwcjZ5wtcOIPnxQno4=
|
||||
k8s.io/client-go v0.18.0/go.mod h1:uQSYDYs4WhVZ9i6AIoEZuwUggLVEF64HOD37boKAtF8=
|
||||
k8s.io/client-go v0.18.2 h1:aLB0iaD4nmwh7arT2wIn+lMnAq7OswjaejkQ8p9bBYE=
|
||||
k8s.io/client-go v0.18.2/go.mod h1:Xcm5wVGXX9HAA2JJ2sSBUn3tCJ+4SVlCbl2MNNv+CIU=
|
||||
k8s.io/code-generator v0.17.2/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s=
|
||||
k8s.io/code-generator v0.18.0/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc=
|
||||
k8s.io/code-generator v0.18.2/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc=
|
||||
k8s.io/component-base v0.17.2/go.mod h1:zMPW3g5aH7cHJpKYQ/ZsGMcgbsA/VyhEugF3QT1awLs=
|
||||
k8s.io/component-base v0.18.0 h1:I+lP0fNfsEdTDpHaL61bCAqTZLoiWjEEP304Mo5ZQgE=
|
||||
k8s.io/component-base v0.18.0/go.mod h1:u3BCg0z1uskkzrnAKFzulmYaEpZF7XC9Pf/uFyb1v2c=
|
||||
k8s.io/component-base v0.18.2 h1:SJweNZAGcUvsypLGNPNGeJ9UgPZQ6+bW+gEHe8uyh/Y=
|
||||
k8s.io/component-base v0.18.2/go.mod h1:kqLlMuhJNHQ9lz8Z7V5bxUUtjFZnrypArGl58gmDfUM=
|
||||
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||
k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||
k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||
|
|
@ -772,10 +858,14 @@ k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C
|
|||
k8s.io/kubectl v0.17.2/go.mod h1:y4rfLV0n6aPmvbRCqZQjvOp3ezxsFgpqL+zF5jH/lxk=
|
||||
k8s.io/kubectl v0.18.0 h1:hu52Ndq/d099YW+3sS3VARxFz61Wheiq8K9S7oa82Dk=
|
||||
k8s.io/kubectl v0.18.0/go.mod h1:LOkWx9Z5DXMEg5KtOjHhRiC1fqJPLyCr3KtQgEolCkU=
|
||||
k8s.io/kubectl v0.18.2 h1:9jnGSOC2DDVZmMUTMi0D1aed438mfQcgqa5TAzVjA1k=
|
||||
k8s.io/kubectl v0.18.2/go.mod h1:OdgFa3AlsPKRpFFYE7ICTwulXOcMGXHTc+UKhHKvrb4=
|
||||
k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
|
||||
k8s.io/metrics v0.17.2/go.mod h1:3TkNHET4ROd+NfzNxkjoVfQ0Ob4iZnaHmSEA4vYpwLw=
|
||||
k8s.io/metrics v0.18.0 h1:yTt/yuRVW1XfnBg8DcOGecW+rrR7VxrMUXYIiUqSELE=
|
||||
k8s.io/metrics v0.18.0/go.mod h1:8aYTW18koXqjLVKL7Ds05RPMX9ipJZI3mywYvBOxXd4=
|
||||
k8s.io/metrics v0.18.2 h1:v4J7WKu/Zo/htSH3w//UWJZT9/CpUThXWYyUbQ/F/jY=
|
||||
k8s.io/metrics v0.18.2/go.mod h1:qga8E7QfYNR9Q89cSCAjinC9pTZ7yv1XSVGUB0vJypg=
|
||||
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
||||
k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89 h1:d4vVOjXm687F1iLSP2q3lyPPuyvTUt3aVoBpi2DqRsU=
|
||||
k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
||||
|
|
@ -784,6 +874,7 @@ modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
|
|||
modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
|
||||
modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
|
||||
modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I=
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT7lCHcxMU+mDHEm+nx46H4zuuHZkDP6icnhu0=
|
||||
sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0=
|
||||
sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU=
|
||||
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
|
||||
|
|
|
|||
|
|
@ -37,16 +37,15 @@ var supportedMetricsAPIVersions = []string{"v1beta1"}
|
|||
|
||||
// APIClient represents a Kubernetes api client.
|
||||
type APIClient struct {
|
||||
checkClientSet *kubernetes.Clientset
|
||||
client kubernetes.Interface
|
||||
dClient dynamic.Interface
|
||||
nsClient dynamic.NamespaceableResourceInterface
|
||||
mxsClient *versioned.Clientset
|
||||
cachedClient *disk.CachedDiscoveryClient
|
||||
config *Config
|
||||
mx sync.Mutex
|
||||
cache *cache.LRUExpireCache
|
||||
metricsAPI bool
|
||||
client kubernetes.Interface
|
||||
dClient dynamic.Interface
|
||||
nsClient dynamic.NamespaceableResourceInterface
|
||||
mxsClient *versioned.Clientset
|
||||
cachedClient *disk.CachedDiscoveryClient
|
||||
config *Config
|
||||
mx sync.Mutex
|
||||
cache *cache.LRUExpireCache
|
||||
metricsAPI bool
|
||||
}
|
||||
|
||||
// NewTestClient for testing ONLY!!
|
||||
|
|
@ -181,28 +180,28 @@ func (a *APIClient) ValidNamespaces() ([]v1.Namespace, error) {
|
|||
// CheckConnectivity return true if api server is cool or false otherwise.
|
||||
func (a *APIClient) CheckConnectivity() (status bool) {
|
||||
defer func() {
|
||||
if !status {
|
||||
a.clearCache()
|
||||
}
|
||||
if err := recover(); err != nil {
|
||||
status = false
|
||||
}
|
||||
if !status {
|
||||
a.clearCache()
|
||||
}
|
||||
}()
|
||||
|
||||
if a.checkClientSet == nil {
|
||||
cfg, err := a.config.flags.ToRESTConfig()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
cfg.Timeout = checkConnTimeout
|
||||
cfg, err := a.config.flags.ToRESTConfig()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
cfg.Timeout = checkConnTimeout
|
||||
|
||||
if a.checkClientSet, err = kubernetes.NewForConfig(cfg); err != nil {
|
||||
log.Error().Err(err).Msgf("Unable to connect to api server")
|
||||
return
|
||||
}
|
||||
client, err := kubernetes.NewForConfig(cfg)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("Unable to connect to api server")
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := a.checkClientSet.ServerVersion(); err == nil {
|
||||
if _, err := client.ServerVersion(); err == nil {
|
||||
a.reset()
|
||||
status = true
|
||||
} else {
|
||||
log.Error().Err(err).Msgf("K9s can't connect to cluster")
|
||||
|
|
@ -253,8 +252,9 @@ func (a *APIClient) DialOrDie() kubernetes.Interface {
|
|||
|
||||
var err error
|
||||
if a.client, err = kubernetes.NewForConfig(a.RestConfigOrDie()); err != nil {
|
||||
log.Fatal().Err(err).Msgf("Unable to connect to api server")
|
||||
log.Panic().Err(err).Msgf("Unable to connect to api server")
|
||||
}
|
||||
|
||||
return a.client
|
||||
}
|
||||
|
||||
|
|
@ -262,7 +262,7 @@ func (a *APIClient) DialOrDie() kubernetes.Interface {
|
|||
func (a *APIClient) RestConfigOrDie() *restclient.Config {
|
||||
cfg, err := a.config.RESTConfig()
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msgf("Unable to connect to api server")
|
||||
log.Panic().Err(err).Msgf("Unable to connect to api server")
|
||||
}
|
||||
return cfg
|
||||
}
|
||||
|
|
@ -342,6 +342,7 @@ func (a *APIClient) reset() {
|
|||
a.mx.Lock()
|
||||
defer a.mx.Unlock()
|
||||
|
||||
a.config.reset()
|
||||
a.cache = cache.NewLRUExpireCache(cacheSize)
|
||||
a.client, a.dClient, a.nsClient, a.mxsClient = nil, nil, nil, nil
|
||||
a.cachedClient = nil
|
||||
|
|
|
|||
|
|
@ -319,8 +319,6 @@ func (c *Config) ensureConfig() {
|
|||
if c.clientConfig != nil {
|
||||
return
|
||||
}
|
||||
|
||||
log.Debug().Msg("Loading raw config from flags...")
|
||||
c.clientConfig = c.flags.ToRawKubeConfigLoader()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -80,9 +80,9 @@ func (m *MetricsServer) ClusterLoad(nos *v1.NodeList, nmx *mv1beta1.NodeMetricsL
|
|||
tmem += mx.AllocatableMEM
|
||||
teph += mx.AllocatableEphemeral
|
||||
}
|
||||
mx.PercCPU, mx.PercMEM, mx.PercEphemeral = ToPercentage(ccpu, tcpu),
|
||||
ToPercentage(cmem, tmem),
|
||||
ToPercentage(ceph, teph)
|
||||
mx.PercCPU = ToPercentage(ccpu, tcpu)
|
||||
mx.PercMEM = ToPercentage(cmem, tmem)
|
||||
mx.PercEphemeral = ToPercentage(ceph, teph)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ func (a *Aliases) loadDefaultAliases() {
|
|||
a.declare("quit", "q", "Q")
|
||||
a.declare("aliases", "alias", "a")
|
||||
a.declare("popeye", "pop")
|
||||
// a.declare("sanitize", "san", "sanitize")
|
||||
a.declare("helm", "charts", "chart", "hm")
|
||||
a.declare("contexts", "context", "ctx")
|
||||
a.declare("users", "user", "usr")
|
||||
a.declare("groups", "group", "grp")
|
||||
|
|
|
|||
|
|
@ -4,13 +4,18 @@ import "github.com/derailed/k9s/internal/client"
|
|||
|
||||
// Cluster tracks K9s cluster configuration.
|
||||
type Cluster struct {
|
||||
Namespace *Namespace `yaml:"namespace"`
|
||||
View *View `yaml:"view"`
|
||||
Namespace *Namespace `yaml:"namespace"`
|
||||
View *View `yaml:"view"`
|
||||
FeatureGates *FeatureGates `yaml:"featureGates"`
|
||||
}
|
||||
|
||||
// NewCluster creates a new cluster configuration.
|
||||
func NewCluster() *Cluster {
|
||||
return &Cluster{Namespace: NewNamespace(), View: NewView()}
|
||||
return &Cluster{
|
||||
Namespace: NewNamespace(),
|
||||
View: NewView(),
|
||||
FeatureGates: NewFeatureGates(),
|
||||
}
|
||||
}
|
||||
|
||||
// Validate a cluster config.
|
||||
|
|
@ -20,6 +25,10 @@ func (c *Cluster) Validate(conn client.Connection, ks KubeSettings) {
|
|||
}
|
||||
c.Namespace.Validate(conn, ks)
|
||||
|
||||
if c.FeatureGates == nil {
|
||||
c.FeatureGates = NewFeatureGates()
|
||||
}
|
||||
|
||||
if c.View == nil {
|
||||
c.View = NewView()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -281,28 +281,30 @@ var expectedConfig = `k9s:
|
|||
- default
|
||||
view:
|
||||
active: po
|
||||
featureGates:
|
||||
nodeShell: false
|
||||
fred:
|
||||
namespace:
|
||||
active: default
|
||||
favorites:
|
||||
- default
|
||||
- kube-public
|
||||
- istio-system
|
||||
- all
|
||||
- kube-system
|
||||
view:
|
||||
active: po
|
||||
featureGates:
|
||||
nodeShell: false
|
||||
minikube:
|
||||
namespace:
|
||||
active: kube-system
|
||||
favorites:
|
||||
- default
|
||||
- kube-public
|
||||
- istio-system
|
||||
- all
|
||||
- kube-system
|
||||
view:
|
||||
active: ctx
|
||||
featureGates:
|
||||
nodeShell: false
|
||||
thresholds:
|
||||
cpu:
|
||||
critical: 90
|
||||
|
|
@ -334,6 +336,8 @@ var resetConfig = `k9s:
|
|||
- default
|
||||
view:
|
||||
active: po
|
||||
featureGates:
|
||||
nodeShell: false
|
||||
thresholds:
|
||||
cpu:
|
||||
critical: 90
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
package config
|
||||
|
||||
// FeatureGates represents K9s opt-in features.
|
||||
type FeatureGates struct {
|
||||
NodeShell bool `yaml:"nodeShell"`
|
||||
}
|
||||
|
||||
// NewFeatureGate returns a new feature gate.
|
||||
func NewFeatureGates() *FeatureGates {
|
||||
return &FeatureGates{}
|
||||
}
|
||||
|
|
@ -100,12 +100,13 @@ func (k *K9s) validateDefaults() {
|
|||
}
|
||||
}
|
||||
|
||||
func (k *K9s) checkClusters(ks KubeSettings) {
|
||||
func (k *K9s) checkClusters(c client.Connection, ks KubeSettings) {
|
||||
cc, err := ks.ClusterNames()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for key := range k.Clusters {
|
||||
k.Clusters[key].Validate(c, ks)
|
||||
if InList(cc, key) {
|
||||
continue
|
||||
}
|
||||
|
|
@ -122,7 +123,7 @@ func (k *K9s) Validate(c client.Connection, ks KubeSettings) {
|
|||
if k.Clusters == nil {
|
||||
k.Clusters = map[string]*Cluster{}
|
||||
}
|
||||
k.checkClusters(ks)
|
||||
k.checkClusters(c, ks)
|
||||
|
||||
if k.Logger == nil {
|
||||
k.Logger = NewLogger()
|
||||
|
|
|
|||
|
|
@ -1,124 +0,0 @@
|
|||
package dao
|
||||
|
||||
// BOZO!! v1.18.0
|
||||
// import (
|
||||
// "context"
|
||||
// "fmt"
|
||||
// "os"
|
||||
|
||||
// "github.com/derailed/k9s/internal/client"
|
||||
// "github.com/derailed/k9s/internal/render"
|
||||
// "github.com/rs/zerolog/log"
|
||||
// "helm.sh/helm/v3/pkg/action"
|
||||
// "k8s.io/apimachinery/pkg/runtime"
|
||||
// )
|
||||
|
||||
// var (
|
||||
// _ Accessor = (*Chart)(nil)
|
||||
// _ Nuker = (*Chart)(nil)
|
||||
// _ Describer = (*Chart)(nil)
|
||||
// )
|
||||
|
||||
// // Chart represents a helm chart.
|
||||
// type Chart struct {
|
||||
// NonResource
|
||||
// }
|
||||
|
||||
// // List returns a collection of resources.
|
||||
// func (c *Chart) List(ctx context.Context, ns string) ([]runtime.Object, error) {
|
||||
// cfg, err := c.EnsureHelmConfig(ns)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
|
||||
// rr, err := action.NewList(cfg).Run()
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
|
||||
// oo := make([]runtime.Object, 0, len(rr))
|
||||
// for _, r := range rr {
|
||||
// oo = append(oo, render.ChartRes{Release: r})
|
||||
// }
|
||||
|
||||
// return oo, nil
|
||||
// }
|
||||
|
||||
// // Get returns a resource.
|
||||
// func (c *Chart) Get(_ context.Context, path string) (runtime.Object, error) {
|
||||
// ns, n := client.Namespaced(path)
|
||||
// cfg, err := c.EnsureHelmConfig(ns)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// resp, err := action.NewGet(cfg).Run(n)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
|
||||
// return render.ChartRes{Release: resp}, nil
|
||||
// }
|
||||
|
||||
// // Describe returns the chart notes.
|
||||
// func (c *Chart) Describe(path string) (string, error) {
|
||||
// ns, n := client.Namespaced(path)
|
||||
// cfg, err := c.EnsureHelmConfig(ns)
|
||||
// if err != nil {
|
||||
// return "", err
|
||||
// }
|
||||
// resp, err := action.NewGet(cfg).Run(n)
|
||||
// if err != nil {
|
||||
// return "", err
|
||||
// }
|
||||
|
||||
// return resp.Info.Notes, nil
|
||||
// }
|
||||
|
||||
// // ToYAML returns the chart manifest.
|
||||
// func (c *Chart) ToYAML(path string) (string, error) {
|
||||
// ns, n := client.Namespaced(path)
|
||||
// cfg, err := c.EnsureHelmConfig(ns)
|
||||
// if err != nil {
|
||||
// return "", err
|
||||
// }
|
||||
// resp, err := action.NewGet(cfg).Run(n)
|
||||
// if err != nil {
|
||||
// return "", err
|
||||
// }
|
||||
|
||||
// return resp.Manifest, nil
|
||||
// }
|
||||
|
||||
// // Delete uninstall a Chart.
|
||||
// func (c *Chart) Delete(path string, cascade, force bool) error {
|
||||
// ns, n := client.Namespaced(path)
|
||||
// cfg, err := c.EnsureHelmConfig(ns)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
// res, err := action.NewUninstall(cfg).Run(n)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
// if res != nil && res.Info != "" {
|
||||
// return fmt.Errorf("%s", res.Info)
|
||||
// }
|
||||
|
||||
// return nil
|
||||
// }
|
||||
|
||||
// // EnsureHelmConfig return a new configuration.
|
||||
// func (c *Chart) EnsureHelmConfig(ns string) (*action.Configuration, error) {
|
||||
// cfg := new(action.Configuration)
|
||||
// flags := c.Client().Config().Flags()
|
||||
// if err := cfg.Init(flags, ns, os.Getenv("HELM_DRIVER"), helmLogger); err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// return cfg, nil
|
||||
// }
|
||||
|
||||
// func helmLogger(s string, args ...interface{}) {
|
||||
// log.Debug().Msgf("%s %v", s, args)
|
||||
// }
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/rs/zerolog/log"
|
||||
"helm.sh/helm/v3/pkg/action"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
var (
|
||||
_ Accessor = (*Helm)(nil)
|
||||
_ Nuker = (*Helm)(nil)
|
||||
_ Describer = (*Helm)(nil)
|
||||
)
|
||||
|
||||
// Helm represents a helm chart.
|
||||
type Helm struct {
|
||||
NonResource
|
||||
}
|
||||
|
||||
// List returns a collection of resources.
|
||||
func (c *Helm) List(ctx context.Context, ns string) ([]runtime.Object, error) {
|
||||
cfg, err := c.EnsureHelmConfig(ns)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rr, err := action.NewList(cfg).Run()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
oo := make([]runtime.Object, 0, len(rr))
|
||||
for _, r := range rr {
|
||||
oo = append(oo, render.HelmRes{Release: r})
|
||||
}
|
||||
|
||||
return oo, nil
|
||||
}
|
||||
|
||||
// Get returns a resource.
|
||||
func (c *Helm) Get(_ context.Context, path string) (runtime.Object, error) {
|
||||
ns, n := client.Namespaced(path)
|
||||
cfg, err := c.EnsureHelmConfig(ns)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := action.NewGet(cfg).Run(n)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return render.HelmRes{Release: resp}, nil
|
||||
}
|
||||
|
||||
// Describe returns the chart notes.
|
||||
func (c *Helm) Describe(path string) (string, error) {
|
||||
ns, n := client.Namespaced(path)
|
||||
cfg, err := c.EnsureHelmConfig(ns)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
resp, err := action.NewGet(cfg).Run(n)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return resp.Info.Notes, nil
|
||||
}
|
||||
|
||||
// ToYAML returns the chart manifest.
|
||||
func (c *Helm) ToYAML(path string) (string, error) {
|
||||
ns, n := client.Namespaced(path)
|
||||
cfg, err := c.EnsureHelmConfig(ns)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
resp, err := action.NewGet(cfg).Run(n)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return resp.Manifest, nil
|
||||
}
|
||||
|
||||
// Delete uninstall a Helm.
|
||||
func (c *Helm) Delete(path string, cascade, force bool) error {
|
||||
ns, n := client.Namespaced(path)
|
||||
cfg, err := c.EnsureHelmConfig(ns)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res, err := action.NewUninstall(cfg).Run(n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if res != nil && res.Info != "" {
|
||||
return fmt.Errorf("%s", res.Info)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// EnsureHelmConfig return a new configuration.
|
||||
func (c *Helm) EnsureHelmConfig(ns string) (*action.Configuration, error) {
|
||||
cfg := new(action.Configuration)
|
||||
flags := c.Client().Config().Flags()
|
||||
if err := cfg.Init(flags, ns, os.Getenv("HELM_DRIVER"), helmLogger); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func helmLogger(s string, args ...interface{}) {
|
||||
log.Debug().Msgf("%s %v", s, args)
|
||||
}
|
||||
|
|
@ -50,9 +50,7 @@ func AccessorFor(f Factory, gvr client.GVR) (Accessor, error) {
|
|||
client.NewGVR("openfaas"): &OpenFaas{},
|
||||
client.NewGVR("popeye"): &Popeye{},
|
||||
client.NewGVR("sanitizer"): &Popeye{},
|
||||
|
||||
// BOZO!! v1.18.0
|
||||
// client.NewGVR("charts"): &Chart{},
|
||||
client.NewGVR("helm"): &Helm{},
|
||||
}
|
||||
|
||||
r, ok := m[gvr]
|
||||
|
|
@ -224,9 +222,9 @@ func loadK9s(m ResourceMetas) {
|
|||
}
|
||||
|
||||
func loadHelm(m ResourceMetas) {
|
||||
m[client.NewGVR("charts")] = metav1.APIResource{
|
||||
Name: "charts",
|
||||
Kind: "Charts",
|
||||
m[client.NewGVR("helm")] = metav1.APIResource{
|
||||
Name: "helm",
|
||||
Kind: "Helm",
|
||||
Namespaced: true,
|
||||
Verbs: []string{"delete"},
|
||||
Categories: []string{"helm"},
|
||||
|
|
|
|||
|
|
@ -22,10 +22,12 @@ type Resource struct {
|
|||
|
||||
// List returns a collection of resources.
|
||||
func (r *Resource) List(ctx context.Context, ns string) ([]runtime.Object, error) {
|
||||
strLabel, ok := ctx.Value(internal.KeyLabels).(string)
|
||||
strLabel, _ := ctx.Value(internal.KeyLabels).(string)
|
||||
lsel := labels.Everything()
|
||||
if sel, err := labels.ConvertSelectorToLabelsMap(strLabel); ok && err == nil {
|
||||
lsel = sel.AsSelector()
|
||||
if strLabel != "" {
|
||||
if sel, err := labels.Parse(strLabel); err == nil {
|
||||
lsel = sel
|
||||
}
|
||||
}
|
||||
|
||||
return r.Factory.List(r.gvr.String(), ns, false, lsel)
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ func (c *CmdBuff) Reset() {
|
|||
c.SetActive(false)
|
||||
}
|
||||
|
||||
// Empty returns true is no cmd, false otherwise.
|
||||
// Empty returns true if no cmd, false otherwise.
|
||||
func (c *CmdBuff) Empty() bool {
|
||||
return len(c.buff) == 0
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,11 +50,14 @@ func (f *FishBuff) NextSuggestion() (string, bool) {
|
|||
if f.suggestionIndex < 0 {
|
||||
return "", false
|
||||
}
|
||||
f.suggestionIndex++
|
||||
|
||||
if f.suggestionIndex >= len(f.suggestions) {
|
||||
f.suggestionIndex = 0
|
||||
}
|
||||
return f.suggestions[f.suggestionIndex], true
|
||||
s := f.suggestions[f.suggestionIndex]
|
||||
f.suggestionIndex++
|
||||
|
||||
return s, true
|
||||
}
|
||||
|
||||
// ClearSuggestions clear out all suggestions.
|
||||
|
|
@ -67,6 +70,11 @@ func (f *FishBuff) CurrentSuggestion() (string, bool) {
|
|||
if f.suggestionIndex < 0 {
|
||||
return "", false
|
||||
}
|
||||
|
||||
if f.suggestionIndex >= len(f.suggestions) {
|
||||
return "", false
|
||||
}
|
||||
|
||||
return f.suggestions[f.suggestionIndex], true
|
||||
}
|
||||
|
||||
|
|
@ -119,7 +127,7 @@ func (f *FishBuff) Delete() {
|
|||
|
||||
func (f *FishBuff) fireSuggestionChanged(ss []string) {
|
||||
f.suggestions, f.suggestionIndex = ss, 0
|
||||
if ss == nil {
|
||||
if len(ss) == 0 {
|
||||
f.suggestionIndex, f.suggestion = -1, ""
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// MaxHistory tracks max command history
|
||||
const MaxHistory = 20
|
||||
|
||||
|
|
@ -11,7 +15,9 @@ type History struct {
|
|||
|
||||
// NewHistory returns a new instance.
|
||||
func NewHistory(limit int) *History {
|
||||
return &History{limit: limit}
|
||||
return &History{
|
||||
limit: limit,
|
||||
}
|
||||
}
|
||||
|
||||
// List returns the current command history.
|
||||
|
|
@ -21,14 +27,19 @@ func (h *History) List() []string {
|
|||
|
||||
// Push adds a new item.
|
||||
func (h *History) Push(c string) {
|
||||
if i := h.indexOf(c); i != -1 {
|
||||
h.commands = append(h.commands[:i], h.commands[i+1:]...)
|
||||
}
|
||||
if len(h.commands) < h.limit {
|
||||
h.commands = append(h.commands, c)
|
||||
if c == "" {
|
||||
return
|
||||
}
|
||||
h.commands = append(h.commands[1:], c)
|
||||
|
||||
c = strings.ToLower(c)
|
||||
if i := h.indexOf(c); i != -1 {
|
||||
return
|
||||
}
|
||||
if len(h.commands) < h.limit {
|
||||
h.commands = append([]string{c}, h.commands...)
|
||||
return
|
||||
}
|
||||
h.commands = append([]string{c}, h.commands[:len(h.commands)-1]...)
|
||||
}
|
||||
|
||||
// Clear clear out the stack using pops.
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ func TestHistory(t *testing.T) {
|
|||
h.Push(fmt.Sprintf("cmd%d", i))
|
||||
}
|
||||
|
||||
assert.Equal(t, []string{"cmd2", "cmd3", "cmd4"}, h.List())
|
||||
assert.Equal(t, []string{"cmd4", "cmd3", "cmd2"}, h.List())
|
||||
h.Clear()
|
||||
assert.True(t, h.Empty())
|
||||
}
|
||||
|
|
@ -25,6 +25,7 @@ func TestHistoryDups(t *testing.T) {
|
|||
h.Push(fmt.Sprintf("cmd%d", i))
|
||||
}
|
||||
h.Push("cmd1")
|
||||
h.Push("")
|
||||
|
||||
assert.Equal(t, []string{"cmd2", "cmd3", "cmd1"}, h.List())
|
||||
assert.Equal(t, []string{"cmd3", "cmd2", "cmd1"}, h.List())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,11 +10,10 @@ import (
|
|||
// BOZO!! Break up deps and merge into single registrar
|
||||
var Registry = map[string]ResourceMeta{
|
||||
// Custom...
|
||||
// BOZO!! v1.18.0
|
||||
// "charts": {
|
||||
// DAO: &dao.Chart{},
|
||||
// Renderer: &render.Chart{},
|
||||
// },
|
||||
"helm": {
|
||||
DAO: &dao.Helm{},
|
||||
Renderer: &render.Helm{},
|
||||
},
|
||||
"pulses": {
|
||||
DAO: &dao.Pulse{},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -24,6 +24,23 @@ func NewDeltaRow(o, n Row, excludeLast bool) DeltaRow {
|
|||
return deltas
|
||||
}
|
||||
|
||||
// Labelize returns a new deltaRow based on labels.
|
||||
func (d DeltaRow) Labelize(cols []int, labelCol int) DeltaRow {
|
||||
if len(d) == 0 {
|
||||
return d
|
||||
}
|
||||
_, vals := sortLabels(labelize(d[labelCol]))
|
||||
out := make(DeltaRow, 0, len(cols)+len(vals))
|
||||
for _, i := range cols {
|
||||
out = append(out, d[i])
|
||||
}
|
||||
for _, v := range vals {
|
||||
out = append(out, v)
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// Diff returns true if deltas differ or false otherwise.
|
||||
func (d DeltaRow) Diff(r DeltaRow, ageCol int) bool {
|
||||
if len(d) != len(r) {
|
||||
|
|
@ -77,9 +94,7 @@ func (d DeltaRow) IsBlank() bool {
|
|||
// Clone returns a delta copy.
|
||||
func (d DeltaRow) Clone() DeltaRow {
|
||||
res := make(DeltaRow, len(d))
|
||||
for i, f := range d {
|
||||
res[i] = f
|
||||
}
|
||||
copy(res, d)
|
||||
|
||||
return res
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,33 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestDeltaLabelize(t *testing.T) {
|
||||
uu := map[string]struct {
|
||||
o render.Row
|
||||
n render.Row
|
||||
e render.DeltaRow
|
||||
}{
|
||||
"same": {
|
||||
o: render.Row{
|
||||
Fields: render.Fields{"a", "b", "blee=fred,doh=zorg"},
|
||||
},
|
||||
n: render.Row{
|
||||
Fields: render.Fields{"a", "b", "blee=fred1,doh=zorg"},
|
||||
},
|
||||
e: render.DeltaRow{"", "", "fred", "zorg"},
|
||||
},
|
||||
}
|
||||
|
||||
for k := range uu {
|
||||
u := uu[k]
|
||||
t.Run(k, func(t *testing.T) {
|
||||
d := render.NewDeltaRow(u.o, u.n, false)
|
||||
d = d.Labelize([]int{0, 1}, 2)
|
||||
assert.Equal(t, u.e, d)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeltaCustomize(t *testing.T) {
|
||||
uu := map[string]struct {
|
||||
r1, r2 render.Row
|
||||
|
|
|
|||
|
|
@ -39,6 +39,20 @@ func (h Header) Clone() Header {
|
|||
return header
|
||||
}
|
||||
|
||||
// Labelize returns a new Header based on labels.
|
||||
func (h Header) Labelize(cols []int, labelCol int, rr RowEvents) Header {
|
||||
header := make(Header, 0, len(cols)+1)
|
||||
for _, c := range cols {
|
||||
header = append(header, h[c])
|
||||
}
|
||||
cc := rr.ExtractHeaderLabels(labelCol)
|
||||
for _, c := range cc {
|
||||
header = append(header, HeaderColumn{Name: c})
|
||||
}
|
||||
|
||||
return header
|
||||
}
|
||||
|
||||
// MapIndices returns a collection of mapped column indices based of the requested columns.
|
||||
func (h Header) MapIndices(cols []string, wide bool) []int {
|
||||
ii := make([]int, 0, len(cols))
|
||||
|
|
|
|||
|
|
@ -12,11 +12,11 @@ import (
|
|||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// Chart renders a helm chart to screen.
|
||||
type Chart struct{}
|
||||
// Helm renders a helm chart to screen.
|
||||
type Helm struct{}
|
||||
|
||||
// ColorerFunc colors a resource row.
|
||||
func (Chart) ColorerFunc() ColorerFunc {
|
||||
func (Helm) ColorerFunc() ColorerFunc {
|
||||
return func(ns string, h Header, re RowEvent) tcell.Color {
|
||||
if !Happy(ns, h, re.Row) {
|
||||
return ErrColor
|
||||
|
|
@ -27,7 +27,7 @@ func (Chart) ColorerFunc() ColorerFunc {
|
|||
}
|
||||
|
||||
// Header returns a header row.
|
||||
func (Chart) Header(_ string) Header {
|
||||
func (Helm) Header(_ string) Header {
|
||||
return Header{
|
||||
HeaderColumn{Name: "NAMESPACE"},
|
||||
HeaderColumn{Name: "NAME"},
|
||||
|
|
@ -41,10 +41,10 @@ func (Chart) Header(_ string) Header {
|
|||
}
|
||||
|
||||
// Render renders a chart to screen.
|
||||
func (c Chart) Render(o interface{}, ns string, r *Row) error {
|
||||
h, ok := o.(ChartRes)
|
||||
func (c Helm) Render(o interface{}, ns string, r *Row) error {
|
||||
h, ok := o.(HelmRes)
|
||||
if !ok {
|
||||
return fmt.Errorf("expected ChartRes, but got %T", o)
|
||||
return fmt.Errorf("expected HelmRes, but got %T", o)
|
||||
}
|
||||
|
||||
r.ID = client.FQN(h.Release.Namespace, h.Release.Name)
|
||||
|
|
@ -62,7 +62,7 @@ func (c Chart) Render(o interface{}, ns string, r *Row) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c Chart) diagnose(s string) error {
|
||||
func (c Helm) diagnose(s string) error {
|
||||
if s != "deployed" {
|
||||
return fmt.Errorf("chart is in an invalid state")
|
||||
}
|
||||
|
|
@ -73,17 +73,17 @@ func (c Chart) diagnose(s string) error {
|
|||
// ----------------------------------------------------------------------------
|
||||
// Helpers...
|
||||
|
||||
// ChartRes represents an helm chart resource.
|
||||
type ChartRes struct {
|
||||
// HelmRes represents an helm chart resource.
|
||||
type HelmRes struct {
|
||||
Release *release.Release
|
||||
}
|
||||
|
||||
// GetObjectKind returns a schema object.
|
||||
func (ChartRes) GetObjectKind() schema.ObjectKind {
|
||||
func (HelmRes) GetObjectKind() schema.ObjectKind {
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyObject returns a container copy.
|
||||
func (h ChartRes) DeepCopyObject() runtime.Object {
|
||||
func (h HelmRes) DeepCopyObject() runtime.Object {
|
||||
return h
|
||||
}
|
||||
|
|
@ -297,3 +297,30 @@ func Pad(s string, width int) string {
|
|||
|
||||
return s + strings.Repeat(" ", width-len(s))
|
||||
}
|
||||
|
||||
// Converts labels string to map
|
||||
func labelize(labels string) map[string]string {
|
||||
ll := strings.Split(labels, ",")
|
||||
data := make(map[string]string, len(ll))
|
||||
|
||||
for _, l := range ll {
|
||||
tokens := strings.Split(l, "=")
|
||||
if len(tokens) == 2 {
|
||||
data[tokens[0]] = tokens[1]
|
||||
}
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
func sortLabels(m map[string]string) (keys, vals []string) {
|
||||
for k := range m {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
vals = append(vals, m[k])
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,49 @@ import (
|
|||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func TestSortLabels(t *testing.T) {
|
||||
uu := map[string]struct {
|
||||
labels string
|
||||
e [][]string
|
||||
}{
|
||||
"simple": {
|
||||
labels: "a=b,c=d",
|
||||
e: [][]string{
|
||||
{"a", "c"},
|
||||
{"b", "d"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for k := range uu {
|
||||
u := uu[k]
|
||||
t.Run(k, func(t *testing.T) {
|
||||
hh, vv := sortLabels(labelize(u.labels))
|
||||
assert.Equal(t, u.e[0], hh)
|
||||
assert.Equal(t, u.e[1], vv)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLabelize(t *testing.T) {
|
||||
uu := map[string]struct {
|
||||
labels string
|
||||
e map[string]string
|
||||
}{
|
||||
"simple": {
|
||||
labels: "a=b,c=d",
|
||||
e: map[string]string{"a": "b", "c": "d"},
|
||||
},
|
||||
}
|
||||
|
||||
for k := range uu {
|
||||
u := uu[k]
|
||||
t.Run(k, func(t *testing.T) {
|
||||
assert.Equal(t, u.e, labelize(u.labels))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDurationToNumber(t *testing.T) {
|
||||
uu := map[string]struct {
|
||||
s, e string
|
||||
|
|
|
|||
|
|
@ -83,8 +83,7 @@ func (p Pod) Render(o interface{}, ns string, r *Row) error {
|
|||
}
|
||||
|
||||
var po v1.Pod
|
||||
err := runtime.DefaultUnstructuredConverter.FromUnstructured(pwm.Raw.Object, &po)
|
||||
if err != nil {
|
||||
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(pwm.Raw.Object, &po); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -57,6 +57,20 @@ func NewRow(size int) Row {
|
|||
return Row{Fields: make([]string, size)}
|
||||
}
|
||||
|
||||
// Labelize returns a new row based on labels.
|
||||
func (r Row) Labelize(cols []int, labelCol int, labels []string) Row {
|
||||
out := NewRow(len(cols) + len(labels))
|
||||
for _, col := range cols {
|
||||
out.Fields = append(out.Fields, r.Fields[col])
|
||||
}
|
||||
m := labelize(r.Fields[labelCol])
|
||||
for _, label := range labels {
|
||||
out.Fields = append(out.Fields, m[label])
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// Customize returns a row subset based on given col indices.
|
||||
func (r Row) Customize(cols []int) Row {
|
||||
out := NewRow(len(cols))
|
||||
|
|
|
|||
|
|
@ -42,8 +42,8 @@ func NewRowEvent(kind ResEvent, row Row) RowEvent {
|
|||
}
|
||||
}
|
||||
|
||||
// NewDeltaRowEvent returns a new row event with deltas.
|
||||
func NewDeltaRowEvent(row Row, delta DeltaRow) RowEvent {
|
||||
// NewRowEventWithDeltas returns a new row event with deltas.
|
||||
func NewRowEventWithDeltas(row Row, delta DeltaRow) RowEvent {
|
||||
return RowEvent{
|
||||
Kind: EventUpdate,
|
||||
Row: row,
|
||||
|
|
@ -75,6 +75,20 @@ func (r RowEvent) Customize(cols []int) RowEvent {
|
|||
}
|
||||
}
|
||||
|
||||
func (r RowEvent) ExtractHeaderLabels(labelCol int) []string {
|
||||
hh, _ := sortLabels(labelize(r.Row.Fields[labelCol]))
|
||||
return hh
|
||||
}
|
||||
|
||||
// Labelize returns a new row event based on labels.
|
||||
func (r RowEvent) Labelize(cols []int, labelCol int, labels []string) RowEvent {
|
||||
return RowEvent{
|
||||
Kind: r.Kind,
|
||||
Deltas: r.Deltas.Labelize(cols, labelCol),
|
||||
Row: r.Row.Labelize(cols, labelCol, labels),
|
||||
}
|
||||
}
|
||||
|
||||
// Diff returns true if the row changed.
|
||||
func (r RowEvent) Diff(re RowEvent, ageCol int) bool {
|
||||
if r.Kind != re.Kind {
|
||||
|
|
@ -91,6 +105,24 @@ func (r RowEvent) Diff(re RowEvent, ageCol int) bool {
|
|||
// RowEvents a collection of row events.
|
||||
type RowEvents []RowEvent
|
||||
|
||||
func (r RowEvents) ExtractHeaderLabels(labelCol int) []string {
|
||||
ll := make([]string, 0, 10)
|
||||
for _, re := range r {
|
||||
ll = append(ll, re.ExtractHeaderLabels(labelCol)...)
|
||||
}
|
||||
|
||||
return ll
|
||||
}
|
||||
|
||||
func (r RowEvents) Labelize(cols []int, labelCol int, labels []string) RowEvents {
|
||||
out := make(RowEvents, 0, len(r))
|
||||
for _, re := range r {
|
||||
out = append(out, re.Labelize(cols, labelCol, labels))
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// Customize returns custom row events based on columns layout.
|
||||
func (r RowEvents) Customize(cols []int) RowEvents {
|
||||
ee := make(RowEvents, 0, len(cols))
|
||||
|
|
|
|||
|
|
@ -65,6 +65,38 @@ func TestFieldClone(t *testing.T) {
|
|||
assert.NotEqual(t, fmt.Sprintf("%p", f), fmt.Sprintf("%p", f1))
|
||||
}
|
||||
|
||||
func TestRowlabelize(t *testing.T) {
|
||||
uu := map[string]struct {
|
||||
row render.Row
|
||||
cols []int
|
||||
e render.Row
|
||||
}{
|
||||
"empty": {
|
||||
row: render.Row{},
|
||||
cols: []int{0, 1, 2},
|
||||
e: render.Row{ID: "", Fields: render.Fields{"", "", ""}},
|
||||
},
|
||||
"no-cols-no-data": {
|
||||
row: render.Row{},
|
||||
cols: []int{},
|
||||
e: render.Row{ID: "", Fields: render.Fields{}},
|
||||
},
|
||||
"no-cols-data": {
|
||||
row: render.Row{ID: "fred", Fields: render.Fields{"f1", "f2", "f3"}},
|
||||
cols: []int{},
|
||||
e: render.Row{ID: "fred", Fields: render.Fields{}},
|
||||
},
|
||||
}
|
||||
|
||||
for k := range uu {
|
||||
u := uu[k]
|
||||
t.Run(k, func(t *testing.T) {
|
||||
row := u.row.Customize(u.cols)
|
||||
assert.Equal(t, u.e, row)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRowCustomize(t *testing.T) {
|
||||
uu := map[string]struct {
|
||||
row render.Row
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package render
|
||||
|
||||
import "github.com/derailed/k9s/internal/client"
|
||||
|
||||
// TableData tracks a K8s resource for tabular display.
|
||||
type TableData struct {
|
||||
Header Header
|
||||
|
|
@ -12,6 +14,22 @@ func NewTableData() *TableData {
|
|||
return &TableData{}
|
||||
}
|
||||
|
||||
// Labelize prints out specific label columns
|
||||
func (t *TableData) Labelize(labels []string) TableData {
|
||||
labelCol := t.Header.IndexOf("LABELS", true)
|
||||
cols := []int{0, 1}
|
||||
if client.IsNamespaced(t.Namespace) {
|
||||
cols = cols[1:]
|
||||
}
|
||||
data := TableData{
|
||||
Namespace: t.Namespace,
|
||||
Header: t.Header.Labelize(cols, labelCol, t.RowEvents),
|
||||
}
|
||||
data.RowEvents = t.RowEvents.Labelize(cols, labelCol, labels)
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
// Customize returns a new model with customized column layout.
|
||||
func (t *TableData) Customize(cols []string, wide bool) TableData {
|
||||
res := TableData{
|
||||
|
|
@ -61,7 +79,7 @@ func (t *TableData) Update(rows Rows) {
|
|||
t.RowEvents[index].Kind, t.RowEvents[index].Deltas = EventUnchanged, blankDelta
|
||||
t.RowEvents[index].Row = row
|
||||
} else {
|
||||
t.RowEvents[index] = NewDeltaRowEvent(row, delta)
|
||||
t.RowEvents[index] = NewRowEventWithDeltas(row, delta)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
|
|
|||
|
|
@ -133,9 +133,5 @@ func (s *StatusIndicator) setText(msg string) {
|
|||
// AsPercDelta represents a percentage with a delta indicator.
|
||||
func AsPercDelta(ov, nv int) string {
|
||||
prev, cur := render.IntToStr(ov), render.IntToStr(nv)
|
||||
if cur == "0" {
|
||||
return render.NAValue
|
||||
}
|
||||
|
||||
return cur + "%" + Deltas(prev, cur)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ func (p *Prompt) SetModel(m PromptModel) {
|
|||
func (p *Prompt) keyboard(evt *tcell.EventKey) *tcell.EventKey {
|
||||
m, ok := p.model.(Suggester)
|
||||
if !ok {
|
||||
return nil
|
||||
return evt
|
||||
}
|
||||
|
||||
switch evt.Key() {
|
||||
|
|
@ -138,9 +138,7 @@ func (p *Prompt) keyboard(evt *tcell.EventKey) *tcell.EventKey {
|
|||
p.model.ClearText()
|
||||
p.model.SetActive(false)
|
||||
case tcell.KeyEnter, tcell.KeyCtrlE:
|
||||
if curr, ok := m.CurrentSuggestion(); ok {
|
||||
p.model.SetText(p.model.GetText() + curr)
|
||||
}
|
||||
p.model.SetText(p.model.GetText())
|
||||
p.model.SetActive(false)
|
||||
case tcell.KeyCtrlW, tcell.KeyCtrlU:
|
||||
p.model.ClearText()
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ type Table struct {
|
|||
gvr client.GVR
|
||||
Path string
|
||||
Extras string
|
||||
cmdBuff *model.CmdBuff
|
||||
cmdBuff *model.FishBuff
|
||||
styles *config.Styles
|
||||
viewSetting *config.ViewSetting
|
||||
sortCol SortColumn
|
||||
|
|
@ -57,7 +57,7 @@ func NewTable(gvr client.GVR) *Table {
|
|||
},
|
||||
gvr: gvr,
|
||||
actions: make(KeyActions),
|
||||
cmdBuff: model.NewCmdBuff('/', model.FilterBuffer),
|
||||
cmdBuff: model.NewFishBuff('/', model.FilterBuffer),
|
||||
sortCol: SortColumn{asc: true},
|
||||
}
|
||||
}
|
||||
|
|
@ -149,7 +149,7 @@ func (t *Table) FilterInput(r rune) bool {
|
|||
}
|
||||
|
||||
// Filter filters out table data.
|
||||
func (t *Table) Filter(s string) {
|
||||
func (t *Table) Filter(q string) {
|
||||
t.ClearSelection()
|
||||
t.doUpdate(t.filtered(t.GetModel().Peek()))
|
||||
t.UpdateTitle()
|
||||
|
|
@ -390,7 +390,7 @@ func (t *Table) filtered(data render.TableData) render.TableData {
|
|||
}
|
||||
|
||||
// CmdBuff returns the associated command buffer.
|
||||
func (t *Table) CmdBuff() *model.CmdBuff {
|
||||
func (t *Table) CmdBuff() *model.FishBuff {
|
||||
return t.cmdBuff
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ func (a *Alias) aliasContext(ctx context.Context) context.Context {
|
|||
|
||||
func (a *Alias) bindKeys(aa ui.KeyActions) {
|
||||
aa.Delete(ui.KeyShiftA, ui.KeyShiftN, tcell.KeyCtrlS, tcell.KeyCtrlSpace, ui.KeySpace)
|
||||
aa.Delete(tcell.KeyCtrlW, tcell.KeyCtrlL)
|
||||
aa.Add(ui.KeyActions{
|
||||
tcell.KeyEnter: ui.NewKeyAction("Goto", a.gotoCmd, true),
|
||||
ui.KeyShiftR: ui.NewKeyAction("Sort Resource", a.GetTable().SortColCmd("RESOURCE", true), false),
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ func TestAliasNew(t *testing.T) {
|
|||
|
||||
assert.Nil(t, v.Init(makeContext()))
|
||||
assert.Equal(t, "Aliases", v.Name())
|
||||
assert.Equal(t, 6, len(v.Hints()))
|
||||
assert.Equal(t, 5, len(v.Hints()))
|
||||
}
|
||||
|
||||
func TestAliasSearch(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -4,9 +4,12 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
|
|
@ -26,7 +29,7 @@ var ExitStatus = ""
|
|||
const (
|
||||
splashDelay = 1 * time.Second
|
||||
clusterRefresh = 5 * time.Second
|
||||
maxConRetry = 10
|
||||
maxConRetry = 15
|
||||
clusterInfoWidth = 50
|
||||
clusterInfoPad = 15
|
||||
)
|
||||
|
|
@ -35,23 +38,25 @@ const (
|
|||
type App struct {
|
||||
*ui.App
|
||||
|
||||
Content *PageStack
|
||||
command *Command
|
||||
factory *watch.Factory
|
||||
version string
|
||||
showHeader bool
|
||||
cancelFn context.CancelFunc
|
||||
conRetry int32
|
||||
clusterModel *model.ClusterInfo
|
||||
history *model.History
|
||||
Content *PageStack
|
||||
command *Command
|
||||
factory *watch.Factory
|
||||
version string
|
||||
showHeader bool
|
||||
cancelFn context.CancelFunc
|
||||
conRetry int32
|
||||
clusterModel *model.ClusterInfo
|
||||
cmdHistory *model.History
|
||||
filterHistory *model.History
|
||||
}
|
||||
|
||||
// NewApp returns a K9s app instance.
|
||||
func NewApp(cfg *config.Config) *App {
|
||||
a := App{
|
||||
App: ui.NewApp(cfg, cfg.K9s.CurrentContext),
|
||||
history: model.NewHistory(model.MaxHistory),
|
||||
Content: NewPageStack(),
|
||||
App: ui.NewApp(cfg, cfg.K9s.CurrentContext),
|
||||
cmdHistory: model.NewHistory(model.MaxHistory),
|
||||
filterHistory: model.NewHistory(model.MaxHistory),
|
||||
Content: NewPageStack(),
|
||||
}
|
||||
|
||||
a.Views()["statusIndicator"] = ui.NewStatusIndicator(a.App, a.Styles)
|
||||
|
|
@ -116,26 +121,37 @@ func (a *App) Init(version string, rate int) error {
|
|||
a.Main.AddPage("splash", ui.NewSplash(a.Styles, version), true, true)
|
||||
a.toggleHeader(!a.Config.K9s.GetHeadless())
|
||||
|
||||
a.initSignals()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) initSignals() {
|
||||
sig := make(chan os.Signal, 1)
|
||||
signal.Notify(sig, syscall.SIGABRT, syscall.SIGINT, syscall.SIGHUP, syscall.SIGQUIT)
|
||||
|
||||
go func(sig chan os.Signal) {
|
||||
<-sig
|
||||
a.BailOut()
|
||||
}(sig)
|
||||
}
|
||||
|
||||
func (a *App) suggestCommand() model.SuggestionFunc {
|
||||
return func(s string) (entries sort.StringSlice) {
|
||||
if s == "" {
|
||||
if a.history.Empty() {
|
||||
if a.cmdHistory.Empty() {
|
||||
return
|
||||
}
|
||||
return a.history.List()
|
||||
return a.cmdHistory.List()
|
||||
}
|
||||
|
||||
lowS := strings.ToLower(s)
|
||||
s = strings.ToLower(s)
|
||||
for _, k := range a.command.alias.Aliases.Keys() {
|
||||
lowK := strings.ToLower(k)
|
||||
if lowK == lowS {
|
||||
if k == s {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(lowK, lowS) {
|
||||
entries = append(entries, strings.Replace(k, lowS, "", 1))
|
||||
if strings.HasPrefix(k, s) {
|
||||
entries = append(entries, strings.Replace(k, s, "", 1))
|
||||
}
|
||||
}
|
||||
if len(entries) == 0 {
|
||||
|
|
@ -333,6 +349,13 @@ func (a *App) initFactory(ns string) {
|
|||
|
||||
// BailOut exists the application.
|
||||
func (a *App) BailOut() {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
log.Error().Msgf("Bailing out %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
nukeK9sShell(a.Conn())
|
||||
a.factory.Terminate()
|
||||
a.App.BailOut()
|
||||
}
|
||||
|
|
@ -448,10 +471,11 @@ func (a *App) gotoCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
}
|
||||
|
||||
func (a *App) helpCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
if _, ok := a.Content.GetPrimitive("main").(*Help); ok {
|
||||
if a.CmdBuff().InCmdMode() {
|
||||
return evt
|
||||
}
|
||||
if a.Content.Top() != nil && a.Content.Top().Name() == helpTitle {
|
||||
|
||||
if a.Content.Top() != nil && a.Content.Top().Name() == "help" {
|
||||
a.Content.Pop()
|
||||
return nil
|
||||
}
|
||||
|
|
@ -467,9 +491,6 @@ func (a *App) aliasCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
if a.CmdBuff().InCmdMode() {
|
||||
return evt
|
||||
}
|
||||
if _, ok := a.Content.GetPrimitive("main").(*Alias); ok {
|
||||
return evt
|
||||
}
|
||||
|
||||
if a.Content.Top() != nil && a.Content.Top().Name() == aliasTitle {
|
||||
a.Content.Pop()
|
||||
|
|
|
|||
|
|
@ -4,13 +4,16 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/config"
|
||||
"github.com/derailed/k9s/internal/dao"
|
||||
"github.com/derailed/k9s/internal/model"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/derailed/k9s/internal/ui"
|
||||
"github.com/derailed/k9s/internal/ui/dialog"
|
||||
|
|
@ -73,9 +76,36 @@ func (b *Browser) Init(ctx context.Context) error {
|
|||
b.GetModel().AddListener(b)
|
||||
b.GetModel().SetRefreshRate(time.Duration(b.App().Config.K9s.GetRefreshRate()) * time.Second)
|
||||
|
||||
b.CmdBuff().SetSuggestionFn(b.suggestFilter())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Browser) suggestFilter() model.SuggestionFunc {
|
||||
return func(s string) (entries sort.StringSlice) {
|
||||
if s == "" {
|
||||
if b.App().filterHistory.Empty() {
|
||||
return
|
||||
}
|
||||
return b.App().filterHistory.List()
|
||||
}
|
||||
|
||||
s = strings.ToLower(s)
|
||||
for _, h := range b.App().filterHistory.List() {
|
||||
if h == s {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(h, s) {
|
||||
entries = append(entries, strings.Replace(h, s, "", 1))
|
||||
}
|
||||
}
|
||||
if len(entries) == 0 {
|
||||
return nil
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Browser) bindKeys() {
|
||||
b.Actions().Add(ui.KeyActions{
|
||||
tcell.KeyEscape: ui.NewSharedKeyAction("Filter Reset", b.resetCmd, false),
|
||||
|
|
@ -92,9 +122,35 @@ func (b *Browser) SetInstance(path string) {
|
|||
func (b *Browser) Start() {
|
||||
b.Stop()
|
||||
b.Table.Start()
|
||||
b.CmdBuff().AddListener(b)
|
||||
b.GetModel().Watch(b.prepareContext())
|
||||
}
|
||||
|
||||
// Stop terminates browser updates.
|
||||
func (b *Browser) Stop() {
|
||||
b.CmdBuff().RemoveListener(b)
|
||||
b.Table.Stop()
|
||||
if b.cancelFn != nil {
|
||||
b.cancelFn()
|
||||
b.cancelFn = nil
|
||||
}
|
||||
}
|
||||
|
||||
// BufferChanged indicates the buffer was changed.
|
||||
func (b *Browser) BufferChanged(s string) {}
|
||||
|
||||
// BufferActive indicates the buff activity changed.
|
||||
func (b *Browser) BufferActive(state bool, k model.BufferKind) {
|
||||
if b.cancelFn != nil {
|
||||
b.cancelFn()
|
||||
}
|
||||
b.GetModel().Watch(b.prepareContext())
|
||||
|
||||
if !state && b.GetRowCount() > 1 {
|
||||
b.App().filterHistory.Push(b.CmdBuff().GetText())
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Browser) prepareContext() context.Context {
|
||||
ctx := b.defaultContext()
|
||||
ctx, b.cancelFn = context.WithCancel(ctx)
|
||||
|
|
@ -108,16 +164,6 @@ func (b *Browser) prepareContext() context.Context {
|
|||
return ctx
|
||||
}
|
||||
|
||||
// Stop terminates browser updates.
|
||||
func (b *Browser) Stop() {
|
||||
if b.cancelFn == nil {
|
||||
return
|
||||
}
|
||||
b.Table.Stop()
|
||||
b.cancelFn()
|
||||
b.cancelFn = nil
|
||||
}
|
||||
|
||||
func (b *Browser) refresh() {
|
||||
b.Start()
|
||||
}
|
||||
|
|
@ -188,11 +234,11 @@ func (b *Browser) resetCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
return b.App().PrevCmd(evt)
|
||||
}
|
||||
|
||||
b.CmdBuff().Reset()
|
||||
if ui.IsLabelSelector(b.CmdBuff().GetText()) {
|
||||
b.CmdBuff().Reset()
|
||||
b.Start()
|
||||
return nil
|
||||
}
|
||||
b.CmdBuff().Reset()
|
||||
b.Refresh()
|
||||
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package view
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/derailed/k9s/internal/config"
|
||||
"github.com/derailed/k9s/internal/model"
|
||||
|
|
@ -90,7 +91,7 @@ func (c *ClusterInfo) ClusterInfoChanged(prev, curr model.ClusterMeta) {
|
|||
row := c.setCell(0, curr.Context)
|
||||
row = c.setCell(row, curr.Cluster)
|
||||
row = c.setCell(row, curr.User)
|
||||
row = c.setCell(row, curr.K9sVer)
|
||||
row = c.setCell(row, fmt.Sprintf("%s [%d]", curr.K9sVer, os.Getpid()))
|
||||
row = c.setCell(row, curr.K8sVer)
|
||||
if c.app.Conn().HasMetrics() {
|
||||
row = c.setCell(row, ui.AsPercDelta(prev.Cpu, curr.Cpu))
|
||||
|
|
|
|||
|
|
@ -135,8 +135,6 @@ func (c *Command) run(cmd, path string, clearStack bool) error {
|
|||
}
|
||||
|
||||
switch cmds[0] {
|
||||
case "chart", "charts":
|
||||
return fmt.Errorf("Command no longer supported. Awaiting helm release for k8s v1.18!")
|
||||
case "ctx", "context", "contexts":
|
||||
if len(cmds) == 2 {
|
||||
return useContext(c.app, cmds[1])
|
||||
|
|
@ -246,7 +244,7 @@ func (c *Command) exec(cmd, gvr string, comp model.Component, clearStack bool) e
|
|||
if err := c.app.inject(comp); err != nil {
|
||||
return err
|
||||
}
|
||||
c.app.cmdHistory.Push(cmd)
|
||||
|
||||
c.app.history.Push(cmd)
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,8 +9,17 @@ import (
|
|||
"os/signal"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/rs/zerolog/log"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -28,7 +37,7 @@ type shellOpts struct {
|
|||
func runK(a *App, opts shellOpts) bool {
|
||||
bin, err := exec.LookPath("kubectl")
|
||||
if err != nil {
|
||||
log.Error().Msgf("Unable to find kubectl command in path %v", err)
|
||||
log.Error().Err(err).Msgf("kubectl command is not in your path")
|
||||
return false
|
||||
}
|
||||
var args []string
|
||||
|
|
@ -43,9 +52,8 @@ func runK(a *App, opts shellOpts) bool {
|
|||
args = append(args, "--kubeconfig", *cfg)
|
||||
}
|
||||
if len(args) > 0 {
|
||||
opts.args = append(opts.args, args...)
|
||||
opts.args = append(args, opts.args...)
|
||||
}
|
||||
|
||||
opts.binary, opts.background = bin, false
|
||||
|
||||
return run(a, opts)
|
||||
|
|
@ -63,10 +71,13 @@ func run(a *App, opts shellOpts) bool {
|
|||
}
|
||||
|
||||
func edit(a *App, opts shellOpts) bool {
|
||||
bin, err := exec.LookPath(os.Getenv("EDITOR"))
|
||||
bin, err := exec.LookPath(os.Getenv("K9S_EDITOR"))
|
||||
if err != nil {
|
||||
log.Error().Msgf("Unable to find editor command in path %v", err)
|
||||
return false
|
||||
bin, err = exec.LookPath(os.Getenv("EDITOR"))
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("K9S_EDITOR|EDITOR not set")
|
||||
return false
|
||||
}
|
||||
}
|
||||
opts.binary, opts.background = bin, false
|
||||
|
||||
|
|
@ -92,7 +103,6 @@ func execute(opts shellOpts) error {
|
|||
}()
|
||||
|
||||
log.Debug().Msgf("Running command> %s %s", opts.binary, strings.Join(opts.args, " "))
|
||||
|
||||
cmd := exec.Command(opts.binary, opts.args...)
|
||||
|
||||
var err error
|
||||
|
|
@ -115,3 +125,114 @@ func execute(opts shellOpts) error {
|
|||
func clearScreen() {
|
||||
fmt.Print("\033[H\033[2J")
|
||||
}
|
||||
|
||||
const (
|
||||
k9sShell = "k9s-shell"
|
||||
k9sShellNS = "default"
|
||||
k9sShellRetryCount = 10
|
||||
k9sShellRetryDelay = 500 * time.Millisecond
|
||||
)
|
||||
|
||||
func ssh(a *App, node string) error {
|
||||
nukeK9sShell(a.Conn())
|
||||
defer nukeK9sShell(a.Conn())
|
||||
if err := launchShellPod(a, node); err != nil {
|
||||
return err
|
||||
}
|
||||
shellIn(a, client.FQN(k9sShellNS, k9sShell), k9sShell)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func nukeK9sShell(c client.Connection) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
|
||||
defer cancel()
|
||||
|
||||
err := c.DialOrDie().CoreV1().Pods(k9sShellNS).Delete(ctx, k9sShell, metav1.DeleteOptions{})
|
||||
if kerrors.IsNotFound(err) {
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("Fail to delete pod %s", k9sShell)
|
||||
}
|
||||
}
|
||||
|
||||
func launchShellPod(a *App, node string) error {
|
||||
spec := k9sShellPod(node)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
|
||||
defer cancel()
|
||||
dial := a.Conn().DialOrDie().CoreV1().Pods(k9sShellNS)
|
||||
if _, err := dial.Create(ctx, &spec, metav1.CreateOptions{}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < k9sShellRetryCount; i++ {
|
||||
o, err := a.factory.Get("v1/pods", client.FQN(k9sShellNS, k9sShell), true, labels.Everything())
|
||||
if err != nil {
|
||||
time.Sleep(k9sShellRetryDelay)
|
||||
continue
|
||||
}
|
||||
var pod v1.Pod
|
||||
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &pod); err != nil {
|
||||
return err
|
||||
}
|
||||
if pod.Status.Phase == v1.PodRunning {
|
||||
return nil
|
||||
}
|
||||
time.Sleep(k9sShellRetryDelay)
|
||||
}
|
||||
|
||||
return fmt.Errorf("Unable to launch shell pod on node %s", node)
|
||||
}
|
||||
|
||||
func k9sShellPod(node string) v1.Pod {
|
||||
var grace int64
|
||||
var priv bool = true
|
||||
|
||||
return v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: k9sShell,
|
||||
Namespace: k9sShellNS,
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
NodeName: node,
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
HostPID: true,
|
||||
HostNetwork: true,
|
||||
TerminationGracePeriodSeconds: &grace,
|
||||
Volumes: []v1.Volume{
|
||||
{
|
||||
Name: "root-vol",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
HostPath: &v1.HostPathVolumeSource{
|
||||
Path: "/",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: k9sShell,
|
||||
Image: "busybox:1.31",
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
Name: "root-vol",
|
||||
MountPath: "/host",
|
||||
ReadOnly: true,
|
||||
},
|
||||
},
|
||||
Resources: v1.ResourceRequirements{
|
||||
Limits: v1.ResourceList{
|
||||
v1.ResourceCPU: resource.MustParse("200m"),
|
||||
v1.ResourceMemory: resource.MustParse("100Mi"),
|
||||
},
|
||||
},
|
||||
Stdin: true,
|
||||
SecurityContext: &v1.SecurityContext{
|
||||
Privileged: &priv,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,17 +9,17 @@ import (
|
|||
"github.com/gdamore/tcell"
|
||||
)
|
||||
|
||||
// Chart represents a helm chart view.
|
||||
type Chart struct {
|
||||
// Helm represents a helm chart view.
|
||||
type Helm struct {
|
||||
ResourceViewer
|
||||
}
|
||||
|
||||
// NewChart returns a new alias view.
|
||||
func NewChart(gvr client.GVR) ResourceViewer {
|
||||
c := Chart{
|
||||
// NewHelm returns a new alias view.
|
||||
func NewHelm(gvr client.GVR) ResourceViewer {
|
||||
c := Helm{
|
||||
ResourceViewer: NewBrowser(gvr),
|
||||
}
|
||||
c.GetTable().SetColorerFn(render.Chart{}.ColorerFunc())
|
||||
c.GetTable().SetColorerFn(render.Helm{}.ColorerFunc())
|
||||
c.GetTable().SetBorderFocusColor(tcell.ColorMediumSpringGreen)
|
||||
c.GetTable().SetSelectedStyle(tcell.ColorWhite, tcell.ColorMediumSpringGreen, tcell.AttrNone)
|
||||
c.SetBindKeysFn(c.bindKeys)
|
||||
|
|
@ -28,11 +28,11 @@ func NewChart(gvr client.GVR) ResourceViewer {
|
|||
return &c
|
||||
}
|
||||
|
||||
func (c *Chart) chartContext(ctx context.Context) context.Context {
|
||||
func (c *Helm) chartContext(ctx context.Context) context.Context {
|
||||
return ctx
|
||||
}
|
||||
|
||||
func (c *Chart) bindKeys(aa ui.KeyActions) {
|
||||
func (c *Helm) bindKeys(aa ui.KeyActions) {
|
||||
aa.Delete(ui.KeyShiftA, ui.KeyShiftN, tcell.KeyCtrlS, tcell.KeyCtrlSpace, ui.KeySpace)
|
||||
aa.Add(ui.KeyActions{
|
||||
ui.KeyShiftN: ui.NewKeyAction("Sort Name", c.GetTable().SortColCmd(nameCol, true), false),
|
||||
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/derailed/k9s/internal/ui"
|
||||
"github.com/derailed/k9s/internal/ui/dialog"
|
||||
"github.com/gdamore/tcell"
|
||||
"github.com/rs/zerolog/log"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
|
|
@ -43,6 +44,13 @@ func (n *Node) bindKeys(aa ui.KeyActions) {
|
|||
ui.KeyShiftX: ui.NewKeyAction("Sort CPU%", n.GetTable().SortColCmd("%CPU", false), false),
|
||||
ui.KeyShiftZ: ui.NewKeyAction("Sort MEM%", n.GetTable().SortColCmd("%MEM", false), false),
|
||||
})
|
||||
|
||||
cl := n.App().Config.K9s.CurrentCluster
|
||||
if n.App().Config.K9s.Clusters[cl].FeatureGates.NodeShell {
|
||||
aa.Add(ui.KeyActions{
|
||||
ui.KeyS: ui.NewKeyAction("Shell", n.sshCmd, true),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Node) showPods(app *App, _ ui.Tabular, _, path string) {
|
||||
|
|
@ -127,6 +135,20 @@ func (n *Node) toggleCordonCmd(cordon bool) func(evt *tcell.EventKey) *tcell.Eve
|
|||
}
|
||||
}
|
||||
|
||||
func (n *Node) sshCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
path := n.GetTable().GetSelectedItem()
|
||||
if path == "" {
|
||||
return evt
|
||||
}
|
||||
|
||||
_, node := client.Namespaced(path)
|
||||
if err := ssh(n.App(), node); err != nil {
|
||||
log.Error().Err(err).Msgf("SSH Failed")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *Node) yamlCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
path := n.GetTable().GetSelectedItem()
|
||||
if path == "" {
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ func resumeShellIn(a *App, c model.Component, path, co string) {
|
|||
}
|
||||
|
||||
func shellIn(a *App, path, co string) {
|
||||
args := computeShellArgs(path, co, a.Config.K9s.CurrentContext, a.Conn().Config().Flags().KubeConfig)
|
||||
args := computeShellArgs(path, co, a.Conn().Config().Flags().KubeConfig)
|
||||
|
||||
c := color.New(color.BgGreen).Add(color.FgBlack).Add(color.Bold)
|
||||
if !runK(a, shellOpts{clear: true, banner: c.Sprintf(bannerFmt, path, co), args: args}) {
|
||||
|
|
@ -226,24 +226,25 @@ func resumeAttachIn(a *App, c model.Component, path, co string) {
|
|||
}
|
||||
|
||||
func attachIn(a *App, path, co string) {
|
||||
args := buildShellArgs("attach", path, co, a.Config.K9s.CurrentContext, a.Conn().Config().Flags().KubeConfig)
|
||||
args := buildShellArgs("attach", path, co, a.Conn().Config().Flags().KubeConfig)
|
||||
c := color.New(color.BgGreen).Add(color.FgBlack).Add(color.Bold)
|
||||
if !runK(a, shellOpts{clear: true, banner: c.Sprintf(bannerFmt, path, co), args: args}) {
|
||||
a.Flash().Err(errors.New("Attach exec failed"))
|
||||
}
|
||||
}
|
||||
|
||||
func computeShellArgs(path, co, context string, kcfg *string) []string {
|
||||
args := buildShellArgs("exec", path, co, context, kcfg)
|
||||
func computeShellArgs(path, co string, kcfg *string) []string {
|
||||
args := buildShellArgs("exec", path, co, kcfg)
|
||||
return append(args, "--", "sh", "-c", shellCheck)
|
||||
}
|
||||
|
||||
func buildShellArgs(cmd, path, co, context string, kcfg *string) []string {
|
||||
func buildShellArgs(cmd, path, co string, kcfg *string) []string {
|
||||
args := make([]string, 0, 15)
|
||||
args = append(args, cmd, "-it")
|
||||
args = append(args, "--context", context)
|
||||
ns, po := client.Namespaced(path)
|
||||
args = append(args, "-n", ns)
|
||||
if ns != client.AllNamespaces {
|
||||
args = append(args, "-n", ns)
|
||||
}
|
||||
args = append(args, po)
|
||||
if kcfg != nil && *kcfg != "" {
|
||||
args = append(args, "--kubeconfig", *kcfg)
|
||||
|
|
|
|||
|
|
@ -10,44 +10,40 @@ import (
|
|||
func TestComputeShellArgs(t *testing.T) {
|
||||
config, empty := "coolConfig", ""
|
||||
uu := map[string]struct {
|
||||
path, co, context string
|
||||
cfg *string
|
||||
e string
|
||||
path, co string
|
||||
cfg *string
|
||||
e string
|
||||
}{
|
||||
"config": {
|
||||
"fred/blee",
|
||||
"c1",
|
||||
"ctx1",
|
||||
&config,
|
||||
"exec -it --context ctx1 -n fred blee --kubeconfig coolConfig -c c1 -- sh -c " + shellCheck,
|
||||
"exec -it -n fred blee --kubeconfig coolConfig -c c1 -- sh -c " + shellCheck,
|
||||
},
|
||||
"noconfig": {
|
||||
"fred/blee",
|
||||
"c1",
|
||||
"ctx1",
|
||||
nil,
|
||||
"exec -it --context ctx1 -n fred blee -c c1 -- sh -c " + shellCheck,
|
||||
"exec -it -n fred blee -c c1 -- sh -c " + shellCheck,
|
||||
},
|
||||
"emptyConfig": {
|
||||
"fred/blee",
|
||||
"c1",
|
||||
"ctx1",
|
||||
&empty,
|
||||
"exec -it --context ctx1 -n fred blee -c c1 -- sh -c " + shellCheck,
|
||||
"exec -it -n fred blee -c c1 -- sh -c " + shellCheck,
|
||||
},
|
||||
"singleContainer": {
|
||||
"fred/blee",
|
||||
"",
|
||||
"ctx1",
|
||||
&empty,
|
||||
"exec -it --context ctx1 -n fred blee -- sh -c " + shellCheck,
|
||||
"exec -it -n fred blee -- sh -c " + shellCheck,
|
||||
},
|
||||
}
|
||||
|
||||
for k := range uu {
|
||||
u := uu[k]
|
||||
t.Run(k, func(t *testing.T) {
|
||||
args := computeShellArgs(u.path, u.co, u.context, u.cfg)
|
||||
args := computeShellArgs(u.path, u.co, u.cfg)
|
||||
|
||||
assert.Equal(t, u.e, strings.Join(args, " "))
|
||||
})
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ func loadCustomViewers() MetaViewers {
|
|||
}
|
||||
|
||||
func helmViewers(vv MetaViewers) {
|
||||
vv[client.NewGVR("charts")] = MetaViewer{
|
||||
viewerFn: NewChart,
|
||||
vv[client.NewGVR("helm")] = MetaViewer{
|
||||
viewerFn: NewHelm,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ func (t *Table) bindKeys() {
|
|||
tcell.KeyCtrlS: ui.NewSharedKeyAction("Save", t.saveCmd, false),
|
||||
ui.KeySlash: ui.NewSharedKeyAction("Filter Mode", t.activateCmd, false),
|
||||
tcell.KeyCtrlZ: ui.NewKeyAction("Toggle Faults", t.toggleFaultCmd, false),
|
||||
tcell.KeyCtrlW: ui.NewKeyAction("Show Wide", t.toggleWideCmd, false),
|
||||
tcell.KeyCtrlW: ui.NewKeyAction("Toggle Wide", t.toggleWideCmd, false),
|
||||
ui.KeyShiftN: ui.NewKeyAction("Sort Name", t.SortColCmd(nameCol, true), false),
|
||||
ui.KeyShiftA: ui.NewKeyAction("Sort Age", t.SortColCmd(ageCol, true), false),
|
||||
})
|
||||
|
|
@ -163,13 +163,11 @@ func (t *Table) bindKeys() {
|
|||
|
||||
func (t *Table) toggleFaultCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
t.ToggleToast()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Table) toggleWideCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||
t.ToggleWide()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
# K9s Kiss Skin Contributed by [@beejeebus](justin.p.randell@gmail.com)
|
||||
k9s:
|
||||
body:
|
||||
fgColor: default
|
||||
bgColor: default
|
||||
logoColor: default
|
||||
info:
|
||||
fgColor: default
|
||||
sectionColor: default
|
||||
frame:
|
||||
border:
|
||||
fgColor: default
|
||||
focusColor: default
|
||||
menu:
|
||||
fgColor: default
|
||||
keyColor: default
|
||||
numKeyColor: default
|
||||
crumbs:
|
||||
fgColor: default
|
||||
bgColor: default
|
||||
activeColor: default
|
||||
status:
|
||||
newColor: default
|
||||
modifyColor: default
|
||||
addColor: default
|
||||
errorColor: default
|
||||
highlightcolor: default
|
||||
killColor: default
|
||||
completedColor: default
|
||||
title:
|
||||
fgColor: default
|
||||
bgColor: default
|
||||
highlightColor: default
|
||||
counterColor: default
|
||||
filterColor: default
|
||||
views:
|
||||
table:
|
||||
fgColor: default
|
||||
bgColor: default
|
||||
cursorColor: default
|
||||
header:
|
||||
fgColor: default
|
||||
bgColor: default
|
||||
sorterColor: default
|
||||
yaml:
|
||||
keyColor: default
|
||||
colonColor: default
|
||||
valueColor: default
|
||||
logs:
|
||||
fgColor: default
|
||||
bgColor: default
|
||||
Loading…
Reference in New Issue