checkpoint
parent
48869f9f51
commit
4f05dc9cbf
3
Makefile
3
Makefile
|
|
@ -10,7 +10,8 @@ IMAGE := ${IMG_NAME}:${VERSION}
|
|||
default: help
|
||||
|
||||
test: ## Run all tests
|
||||
@go test ./...
|
||||
@go clean --testcache && go test ./...
|
||||
|
||||
|
||||
cover: ## Run test coverage suite
|
||||
@go test ./... --coverprofile=cov.out
|
||||
|
|
|
|||
|
|
@ -572,9 +572,6 @@ to make this project a reality!
|
|||
* [Fernand Galiana](https://github.com/derailed)
|
||||
* <img src="assets/mail.png" width="16" height="auto"/> fernand@imhotep.io
|
||||
* <img src="assets/twitter.png" width="16" height="auto"/> [@kitesurfer](https://twitter.com/kitesurfer?lang=en)
|
||||
* [Gustavo Silva Paiva](https://github.com/paivagustavo)
|
||||
* <img src="assets/mail.png" width="16" height="auto"/> guustavo.paiva@gmail.com
|
||||
* <img src="assets/twitter.png" width="16" height="auto"/> [@paivagustavodev](https://twitter.com/paivagustavodev)
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import (
|
|||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/color"
|
||||
"github.com/derailed/k9s/internal/config"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/derailed/k9s/internal/view"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
|
@ -113,7 +112,7 @@ func loadConfiguration() *config.Config {
|
|||
k9sCfg.K9s.OverrideCommand(*k9sFlags.Command)
|
||||
}
|
||||
|
||||
if isBoolSet(k9sFlags.AllNamespaces) && k9sCfg.SetActiveNamespace(render.AllNamespaces) != nil {
|
||||
if isBoolSet(k9sFlags.AllNamespaces) && k9sCfg.SetActiveNamespace(client.AllNamespaces) != nil {
|
||||
log.Error().Msg("Setting active namespace")
|
||||
}
|
||||
|
||||
|
|
|
|||
14
go.mod
14
go.mod
|
|
@ -3,6 +3,7 @@ module github.com/derailed/k9s
|
|||
go 1.13
|
||||
|
||||
replace (
|
||||
github.com/docker/docker => github.com/docker/docker v1.4.2-0.20181221150755-2cb26cfe9cbf
|
||||
k8s.io/api => k8s.io/api v0.0.0-20190918155943-95b840bb6a1f
|
||||
k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.0.0-20190918161926-8f644eb6e783
|
||||
k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20190913080033-27d36303b655
|
||||
|
|
@ -27,19 +28,15 @@ replace (
|
|||
)
|
||||
|
||||
require (
|
||||
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
|
||||
github.com/atotto/clipboard v0.1.2
|
||||
github.com/derailed/tview v0.3.3
|
||||
github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c // indirect
|
||||
github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f // indirect
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20190421051319-9d40249d3c2f // indirect
|
||||
github.com/fsnotify/fsnotify v1.4.7
|
||||
github.com/gdamore/tcell v1.3.0
|
||||
github.com/ghodss/yaml v1.0.0
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef // indirect
|
||||
github.com/google/btree v1.0.0 // indirect
|
||||
github.com/googleapis/gnostic v0.2.0 // indirect
|
||||
github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc // indirect
|
||||
github.com/imdario/mergo v0.3.7 // indirect
|
||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.5
|
||||
github.com/petergtz/pegomock v2.6.0+incompatible
|
||||
|
|
@ -47,16 +44,15 @@ require (
|
|||
github.com/rs/zerolog v1.17.2
|
||||
github.com/sahilm/fuzzy v0.1.0
|
||||
github.com/spf13/cobra v0.0.5
|
||||
github.com/stretchr/testify v1.3.0
|
||||
github.com/stretchr/testify v1.4.0
|
||||
golang.org/x/text v0.3.2
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.2.4
|
||||
helm.sh/helm/v3 v3.0.2
|
||||
k8s.io/api v0.0.0
|
||||
k8s.io/apimachinery v0.0.0
|
||||
k8s.io/cli-runtime v0.0.0
|
||||
k8s.io/client-go v0.0.0
|
||||
k8s.io/klog v0.4.0
|
||||
k8s.io/klog v1.0.0
|
||||
k8s.io/kubectl v0.0.0
|
||||
k8s.io/kubernetes v1.16.3
|
||||
k8s.io/metrics v0.0.0
|
||||
|
|
|
|||
199
go.sum
199
go.sum
|
|
@ -21,6 +21,7 @@ github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6L
|
|||
github.com/Azure/go-autorest/tracing v0.5.0 h1:TRn4WjSnkcSy5AEG3pnbtFSwNtwzjr4VYyQflFE619k=
|
||||
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
|
||||
github.com/BurntSushi/toml v0.3.0/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
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=
|
||||
|
|
@ -28,10 +29,23 @@ github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q
|
|||
github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14=
|
||||
github.com/JeffAshton/win_pdh v0.0.0-20161109143554-76bb4ee9f0ab/go.mod h1:3VYc5hodBMJ5+l/7J4xAyMeuM2PNuepvHlGs8yilUCA=
|
||||
github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E=
|
||||
github.com/MakeNowJust/heredoc v0.0.0-20171113091838-e9091a26100e h1:eb0Pzkt15Bm7f2FFYv7sjY7NPFi3cPkS3tv1CcrFBWA=
|
||||
github.com/MakeNowJust/heredoc v0.0.0-20171113091838-e9091a26100e/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/sprig/v3 v3.0.2 h1:wz22D0CiSctrliXiI9ZO3HoNApweeRGftyDN+BQa3B8=
|
||||
github.com/Masterminds/sprig/v3 v3.0.2/go.mod h1:oesJ8kPONMONaZgtiHNzUShJbksypC5kWczhZAf6+aU=
|
||||
github.com/Masterminds/vcs v1.13.0/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA=
|
||||
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
|
||||
github.com/Microsoft/go-winio v0.4.12/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
|
||||
github.com/Microsoft/hcsshim v0.0.0-20190417211021-672e52e9209d/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
|
||||
github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
|
||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46 h1:lsxEuwrXEAokXB9qhlbKWPpo3KMLZQ5WB5WLQRW1uq0=
|
||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw=
|
||||
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
|
||||
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
||||
|
|
@ -40,6 +54,11 @@ github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdko
|
|||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/Rican7/retry v0.1.0/go.mod h1:FgOROf8P5bebcC1DS0PdOQiqGUridaZvikzUmkFW6gg=
|
||||
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||
|
|
@ -53,13 +72,23 @@ github.com/bazelbuild/bazel-gazelle v0.0.0-20181012220611-c728ce9f663e/go.mod h1
|
|||
github.com/bazelbuild/buildtools v0.0.0-20180226164855-80c7f0d45d7e/go.mod h1:5JP0TXzWDHXv8qvxRC4InIazwdyDseBDbzESUMKk1yU=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bifurcation/mint v0.0.0-20180715133206-93c51c6ce115/go.mod h1:zVt7zX3K/aDCk9Tj+VM7YymsX66ERvzCJzw8rFCX2JU=
|
||||
github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
|
||||
github.com/blang/semver v3.5.0+incompatible h1:CGxCgetQ64DKk7rdZ++Vfnb1+ogGNnB17OJKJXD2Cfs=
|
||||
github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
||||
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
|
||||
github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
|
||||
github.com/bugsnag/bugsnag-go v1.5.0/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
|
||||
github.com/bugsnag/panicwrap v1.2.0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
|
||||
github.com/caddyserver/caddy v1.0.3/go.mod h1:G+ouvOY32gENkJC+jhgl62TyhvqEsFaDiZ4uw0RzP1E=
|
||||
github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||
github.com/cespare/prettybench v0.0.0-20150116022406-03b8cfe5406c/go.mod h1:Xe6ZsFhtM8HrDku0pxJ3/Lr51rwykrzgFwpmTzleatY=
|
||||
github.com/cespare/xxhash/v2 v2.1.0 h1:yTUvW7Vhb89inJ+8irsUqiWjh8iT6sQPZiQzI6ReGkA=
|
||||
github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM=
|
||||
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw=
|
||||
github.com/checkpoint-restore/go-criu v0.0.0-20190109184317-bdb7599cd87b/go.mod h1:TrMrLQfeENAPYPRsJuq3jsqdlRh3lvi6trTZJG8+tho=
|
||||
github.com/cheekybits/genny v0.0.0-20170328200008-9127e812e1e9/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
|
||||
|
|
@ -70,6 +99,10 @@ github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2
|
|||
github.com/container-storage-interface/spec v1.1.0/go.mod h1:6URME8mwIBbpVyZV93Ce5St17xBiQJQY67NDsuohiy4=
|
||||
github.com/containerd/console v0.0.0-20170925154832-84eeaae905fa/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
|
||||
github.com/containerd/containerd v1.0.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
|
||||
github.com/containerd/containerd v1.3.0-beta.2.0.20190823190603-4a2f61c4f2b4/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
|
||||
github.com/containerd/containerd v1.3.0 h1:xjvXQWABwS2uiv3TWgQt5Uth60Gu86LTGZXMJkjc7rY=
|
||||
github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
|
||||
github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||
github.com/containerd/typeurl v0.0.0-20190228175220-2a93cfde8c20/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
|
||||
github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
|
||||
github.com/coredns/corefile-migration v1.0.2/go.mod h1:OFwBp/Wc9dJt5cAZzHWMNhK1r5L0p0jDwIBc6j8NC8E=
|
||||
|
|
@ -89,25 +122,46 @@ github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea h1:n2Ltr3SrfQlf/9nOna1D
|
|||
github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/coreos/rkt v1.30.0/go.mod h1:O634mlH6U7qk87poQifK6M2rsFNt+FyUTWNMnP1hF1U=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg=
|
||||
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
|
||||
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE=
|
||||
github.com/deislabs/oras v0.7.0 h1:RnDoFd3tQYODMiUqxgQ8JxlrlWL0/VMKIKRD01MmNYk=
|
||||
github.com/deislabs/oras v0.7.0/go.mod h1:sqMKPG3tMyIX9xwXUBRLhZ24o+uT4y6jgBD2RzUTKDM=
|
||||
github.com/deislabs/oras v0.8.0 h1:WZqPI25DlEmth2VE/pIcnEh6msL2yHrzS5lV5gwaCsQ=
|
||||
github.com/derailed/tview v0.3.3 h1:tipPwxcDhx0zRBZuc8VKIrNgWL40FL5JeF/30XVieUE=
|
||||
github.com/derailed/tview v0.3.3/go.mod h1:yApPszFU62FoaGkf7swy2nIdV/h7Nid3dhMSVy6+OFI=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
|
||||
github.com/docker/cli v0.0.0-20190506213505-d88565df0c2d h1:qdD+BtyCE1XXpDyhvn0yZVcZOLILdj9Cw4pKu0kQbPQ=
|
||||
github.com/docker/cli v0.0.0-20190506213505-d88565df0c2d/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
|
||||
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v1.4.2-0.20181221150755-2cb26cfe9cbf h1:+Hdbkr8QbGSQ4dY50mmgZEGtzjhv0we2Ws2XCz3c0Q8=
|
||||
github.com/docker/docker v1.4.2-0.20181221150755-2cb26cfe9cbf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.6.1 h1:Dq4iIfcM7cNtddhLVWe9h4QDjsi4OER3Z8voPu/I52g=
|
||||
github.com/docker/docker-credential-helpers v0.6.1/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
|
||||
github.com/docker/go-connections v0.3.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-metrics v0.0.0-20181218153428-b84716841b82 h1:X0fj836zx99zFu83v/M79DuBn84IL/Syx1SY6Y5ZEMA=
|
||||
github.com/docker/go-metrics v0.0.0-20181218153428-b84716841b82/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI=
|
||||
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
|
||||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/docker/libnetwork v0.0.0-20180830151422-a9cd636e3789/go.mod h1:93m0aTqz6z+g32wla4l4WxTrdtvBRmVzYRkYvasA5Z8=
|
||||
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
|
||||
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96 h1:cenwrSVm+Z7QLSV/BsnenAOcDXdX4cMv4wP0B/5QbPg=
|
||||
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
|
||||
github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c h1:ZfSZ3P3BedhKGUhzj7BQlPSU4OvT6tfOKe3DVHzOA7s=
|
||||
github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
|
||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||
github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f h1:8GDPb0tCY8LQ+OJ3dbHb5sA6YZWXFORQYZx5sdsTlMs=
|
||||
|
|
@ -117,9 +171,14 @@ github.com/elazarl/goproxy/ext v0.0.0-20190421051319-9d40249d3c2f/go.mod h1:gNh8
|
|||
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||
github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk=
|
||||
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||
github.com/emicklei/go-restful v2.11.1+incompatible h1:CjKsv3uWcCMvySPQYKxO8XX3f9zD4FeZRsW4G0B4ffE=
|
||||
github.com/emicklei/go-restful v2.11.1+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||
github.com/euank/go-kmsg-parser v2.0.0+incompatible/go.mod h1:MhmAMZ8V4CYH4ybgdRwPr2TU5ThnS43puaKEMpja1uw=
|
||||
github.com/evanphx/json-patch v4.2.0+incompatible h1:fUDGZCv/7iAN7u0puUVhvKCcsR6vRfwrJatElLBEf0I=
|
||||
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M=
|
||||
github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM=
|
||||
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4=
|
||||
github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8=
|
||||
github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc=
|
||||
|
|
@ -127,6 +186,7 @@ github.com/fatih/color v1.6.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv
|
|||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
|
||||
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
|
||||
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
|
||||
github.com/gdamore/tcell v1.1.2/go.mod h1:h3kq4HO9l2On+V9ed8w8ewqQEmGCSSHOgQ+2h8uzurE=
|
||||
|
|
@ -141,6 +201,10 @@ github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 h1:DujepqpGd1hyOd7a
|
|||
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
||||
github.com/go-acme/lego v2.5.0+incompatible/go.mod h1:yzMNe9CasVUhkquNvti5nAtPmG94USbYxYrZfTkIn0M=
|
||||
github.com/go-bindata/go-bindata v3.1.1+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||
github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
|
||||
github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
|
||||
|
|
@ -156,11 +220,15 @@ github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwds
|
|||
github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
|
||||
github.com/go-openapi/jsonpointer v0.19.2 h1:A9+F4Dc/MCNB5jibxf6rRvOvR/iFgQdyNx9eIhnGqq0=
|
||||
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
|
||||
github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
|
||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
|
||||
github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
|
||||
github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
|
||||
github.com/go-openapi/jsonreference v0.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w=
|
||||
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
|
||||
github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o=
|
||||
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
|
||||
github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
|
||||
github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
|
||||
github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
|
||||
|
|
@ -174,6 +242,8 @@ github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsd
|
|||
github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
|
||||
github.com/go-openapi/spec v0.19.2 h1:SStNd1jRcYtfKCN7R0laGNs80WYYvn5CbBjM2sOmCrE=
|
||||
github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY=
|
||||
github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo=
|
||||
github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
|
||||
github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
|
||||
github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
|
||||
github.com/go-openapi/strfmt v0.19.0 h1:0Dn9qy1G9+UJfRU7TR8bmdGxb4uifB7HNrJjOnV0yPk=
|
||||
|
|
@ -183,17 +253,30 @@ github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/
|
|||
github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
|
||||
github.com/go-openapi/swag v0.19.2 h1:jvO6bCMBEilGwMfHhrd61zIID4oIFdwb76V17SM88dE=
|
||||
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
|
||||
github.com/go-openapi/validate v0.19.2 h1:ky5l57HjyVRrsJfd2+Ro5Z9PjGuKbsmftwyMtk8H7js=
|
||||
github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA=
|
||||
github.com/go-ozzo/ozzo-validation v3.5.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
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 v4.1.0+incompatible/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
|
||||
github.com/gofrs/flock v0.7.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I=
|
||||
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/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=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
|
|
@ -201,6 +284,8 @@ github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+
|
|||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAONeMXrxql8uvOKuAZSu8aM5RUGv+1C6IJaEho=
|
||||
github.com/golangplus/fmt v0.0.0-20150411045040-2a5d6d7d2995/go.mod h1:lJgMEyOkYFkPcDKwRXegd+iM6E7matEszMG5HhwytU8=
|
||||
github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk=
|
||||
|
|
@ -212,6 +297,8 @@ github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB
|
|||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
||||
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
|
|
@ -225,13 +312,20 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+
|
|||
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||
github.com/googleapis/gnostic v0.2.0 h1:l6N3VoaVzTncYYW+9yOz2LJJammFZGBO13sqgEhpy9g=
|
||||
github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||
github.com/googleapis/gnostic v0.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk=
|
||||
github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU=
|
||||
github.com/gophercloud/gophercloud v0.1.0 h1:P/nh25+rzXouhytV2pUHBb65fnds26Ghl8/391+sT5o=
|
||||
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/handlers v1.4.0/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
|
||||
github.com/gorilla/mux v1.7.0 h1:tOSd0UKHQd6urX6ApfOn4XdBMY6Sh1MfxV3kmaazO+U=
|
||||
github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gosuri/uitable v0.0.1 h1:M9sMNgSZPyAu1FJZJLpJ16ofL8q5ko2EDUkICsynvlY=
|
||||
github.com/gosuri/uitable v0.0.1/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo=
|
||||
github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc h1:f8eY6cV/x1x+HLjOp4r72s/31/V2aTUtg5oKRRPf8/Q=
|
||||
github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v0.0.0-20190222133341-cfaf5686ec79/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
|
|
@ -243,6 +337,8 @@ github.com/hashicorp/golang-lru v0.0.0-20180201235237-0fb14efe8c47/go.mod h1:/m3
|
|||
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=
|
||||
github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk=
|
||||
github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/heketi/heketi v9.0.0+incompatible/go.mod h1:bB9ly3RchcQqsQ9CpyaQwvva7RS5ytVoSoholZQON6o=
|
||||
github.com/heketi/rest v0.0.0-20180404230133-aa6a65207413/go.mod h1:BeS3M108VzVlmAue3lv2WcGuPAX94/KN63MUURzbYSI=
|
||||
|
|
@ -250,9 +346,13 @@ github.com/heketi/tests v0.0.0-20151005000721-f3775cbcefd6/go.mod h1:xGMAM8JLi7U
|
|||
github.com/heketi/utils v0.0.0-20170317161834-435bc5bdfa64/go.mod h1:RYlF4ghFZPPmk2TC5REt5OFwvfb6lzxFWrTWB+qs28s=
|
||||
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/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/jimstudt/http-authentication v0.0.0-20140401203705-3eca13d6893a/go.mod h1:wK6yTYYcgjHE1Z1QtXACPDjcFJyBskHEdagmnq3vsP8=
|
||||
|
|
@ -264,11 +364,15 @@ github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62F
|
|||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
|
||||
github.com/karrick/godirwalk v1.7.5/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/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=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
|
|
@ -295,6 +399,9 @@ github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN
|
|||
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63 h1:nTT4s92Dgz2HlrB2NaMgvlfqHH39OgMhA7z3PK7PGD4=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM=
|
||||
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
|
||||
github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
|
|
@ -306,14 +413,20 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0j
|
|||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mesos/mesos-go v0.0.9/go.mod h1:kPYCMQ9gsOXVAle1OsoY4I1+9kPu8GHkf88aV59fDr4=
|
||||
github.com/mholt/certmagic v0.6.2-0.20190624175158-6a42ef9fe8c2/go.mod h1:g4cOPxcjV0oFq3qwpjSA30LReKD8AoIfwAY9VvG35NY=
|
||||
github.com/miekg/dns v0.0.0-20181005163659-0d29b283ac0f/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.3/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.4/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/mindprince/gonvml v0.0.0-20171110221305-fee913ce8fb2/go.mod h1:2eu9pRWp8mo84xCg6KswZ+USQHjwgRhNp06sozOdsTY=
|
||||
github.com/mistifyio/go-zfs v2.1.1+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
|
||||
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/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4=
|
||||
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
|
||||
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
|
|
@ -327,6 +440,7 @@ github.com/mrunalp/fileutils v0.0.0-20160930181131-4ee1cc9a8058/go.mod h1:x8F1gn
|
|||
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d h1:7PxY7LVfSZm7PEeBTyK1rj1gABdCO2mbri6GKO1cMDs=
|
||||
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/mvdan/xurls v1.1.0/go.mod h1:tQlNn3BED8bE/15hnSL2HLkDeLWpNPAwtw7wkEq44oU=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
||||
github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=
|
||||
github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=
|
||||
|
|
@ -334,12 +448,19 @@ github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB
|
|||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w=
|
||||
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo=
|
||||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
|
||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ=
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
|
||||
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||
github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||
github.com/opencontainers/runc v1.0.0-rc2.0.20190611121236-6cc515888830 h1:yvQ/2Pupw60ON8TYEIGGTAI77yZsWYkiOeHFZWkwlCk=
|
||||
github.com/opencontainers/runc v1.0.0-rc2.0.20190611121236-6cc515888830/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||
github.com/opencontainers/runtime-spec v1.0.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/selinux v1.2.2/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs=
|
||||
|
|
@ -351,6 +472,7 @@ github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+v
|
|||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||
github.com/petergtz/pegomock v2.6.0+incompatible h1:gD9YvI42LylIA/il2Cy8lMfg+CncNFMqexYepyEWGaQ=
|
||||
github.com/petergtz/pegomock v2.6.0+incompatible/go.mod h1:nuBLWZpVyv/fLo56qTwt/AUau7jgouO1h7bEvZCq82o=
|
||||
github.com/phayes/freeport v0.0.0-20171002181615-b8543db493a5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
|
|
@ -359,14 +481,30 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
|||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
|
||||
github.com/pquerna/ffjson v0.0.0-20180717144149-af8b230fcd20/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.2 h1:awm861/B8OKDd2I/6o1dy3ra4BamzKhYOiGItCeZ740=
|
||||
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.2.1 h1:JnMpQc6ppsNgw9QPAGF6Dod479itz7lvlsMzzNayLOI=
|
||||
github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275 h1:PnBWHBf+6L0jOqq0gIVUe6Yk0/QMZ640k6NvkxcBf+8=
|
||||
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.7.0 h1:L+1lyG48J1zAQXA3RBX/nG/B3gjlHq0zTt2tlbJLyCY=
|
||||
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a h1:9a8MnZMP0X2nLJdBg+pBmGgkJlSaKC2KaQmTCk1XDtE=
|
||||
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190129233650-316cf8ccfec5/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8=
|
||||
github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
||||
github.com/quobyte/api v0.1.2/go.mod h1:jL7lIHrmqQ7yh05OJ+eEEdHr0u/kmT1Ff9iHd+4H6VI=
|
||||
github.com/rakyll/hey v0.1.2 h1:XlGaKcBdmXJaPImiTnE+TGLDUWQ2toYuHCwdrylLjmg=
|
||||
github.com/rakyll/hey v0.1.2/go.mod h1:S5M+++KwbmxA7w68S92B5NdWiCB+cIhITaMUkq9W608=
|
||||
|
|
@ -383,19 +521,24 @@ github.com/rs/zerolog v1.17.2 h1:RMRHFw2+wF7LO0QqtELQwo8hqSmqISyCJeFeAAuWcRo=
|
|||
github.com/rs/zerolog v1.17.2/go.mod h1:9nvC1axdVrAHcu/s9taAVfBuIdTZLVQmKQyvrUjF5+I=
|
||||
github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto=
|
||||
github.com/russross/blackfriday v0.0.0-20170610170232-067529f716f4/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
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/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI=
|
||||
github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
|
||||
github.com/sirupsen/logrus v1.0.5/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.3/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
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/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
|
|
@ -404,6 +547,8 @@ github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzu
|
|||
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||
github.com/storageos/go-api v0.0.0-20180912212459-343b3eff91fc/go.mod h1:ZrLn+e0ZuF3Y65PNF6dIwbJPZqfmtCXxFm9ckv0agOY=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
|
|
@ -414,6 +559,8 @@ github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRci
|
|||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/syndtr/gocapability v0.0.0-20160928074757-e7cb7fa329f4/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
github.com/thecodeteam/goscaleio v0.1.0/go.mod h1:68sdkZAsK8bvEwBlbQnlLS+xU+hvLYM/iQ8KXej1AwM=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
|
|
@ -422,10 +569,21 @@ github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKn
|
|||
github.com/vishvananda/netlink v0.0.0-20171020171820-b2de5d10e38e/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
|
||||
github.com/vishvananda/netns v0.0.0-20171111001504-be1fbeda1936/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
|
||||
github.com/vmware/govmomi v0.20.1/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
github.com/xeipuuv/gojsonschema v1.1.0 h1:ngVtJC9TY/lg0AA/1k48FYhBrhRoFlEmWzsehpNAaZg=
|
||||
github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
|
||||
github.com/xenolf/lego v0.0.0-20160613233155-a9d8cec0e656/go.mod h1:fwiGnfsIjG7OHPfOvgK7Y/Qo6+2Ox0iozjNTkZICKbY=
|
||||
github.com/xenolf/lego v0.3.2-0.20160613233155-a9d8cec0e656/go.mod h1:fwiGnfsIjG7OHPfOvgK7Y/Qo6+2Ox0iozjNTkZICKbY=
|
||||
github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1 h1:j2hhcujLRHAg872RWAV5yaUrEjHEObwDv3aImCaNLek=
|
||||
github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
github.com/yvasiyarov/go-metrics v0.0.0-20150112132944-c25f46c4b940/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
|
||||
github.com/yvasiyarov/gorelic v0.0.6/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=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.uber.org/atomic v0.0.0-20181018215023-8dc6146f7569 h1:nSQar3Y0E3VQF/VdZ8PTAilaXpER+d7ypdABCrpwMdg=
|
||||
|
|
@ -435,6 +593,7 @@ go.uber.org/multierr v0.0.0-20180122172545-ddea229ff1df/go.mod h1:wR5kodmAFQ0UK8
|
|||
go.uber.org/zap v0.0.0-20180814183419-67bc79d13d15 h1:Z2sc4+v0JHV6Mn4kX1f2a5nruNjmV+Th32sugE8zwz8=
|
||||
go.uber.org/zap v0.0.0-20180814183419-67bc79d13d15/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
golang.org/x/crypto v0.0.0-20180426230345-b49d69b5da94/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
|
|
@ -444,10 +603,14 @@ golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACk
|
|||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8 h1:1wopBVtVdWnn03fZelqdXTqk7U7zPQCb+T4rbU9ZEoU=
|
||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191028145041-f83a4685e152 h1:ZC1Xn5A1nlpSmQCIva4bZ3ob3lmhYIefc+GU+DLg1Ow=
|
||||
golang.org/x/crypto v0.0.0-20191028145041-f83a4685e152/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=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
|
|
@ -462,6 +625,8 @@ golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73r
|
|||
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181017193950-04a2e542c03f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181102091132-c10e9556a7bc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
|
@ -471,10 +636,14 @@ golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn
|
|||
golang.org/x/net v0.0.0-20190328230028-74de082e2cca/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
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-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc h1:gkKoSkUmnU6bpS/VhkuO27bzQeSA51uaEfbOW5dNb68=
|
||||
golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271 h1:N66aaryRB3Ax92gH0v3hp1QYZ3zWWCCUR/j8Ifh45Ss=
|
||||
golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
|
||||
|
|
@ -483,11 +652,14 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/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-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=
|
||||
golang.org/x/sys v0.0.0-20181004145325-8469e314837c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
|
@ -501,6 +673,9 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756 h1:9nuHUbU8dRnRRfj9KjWUVrJeoexdbeMjttk6Oh1rD10=
|
||||
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191028164358-195ce5e7f934 h1:u/E0NqCIWRDAo9WCFo6Ko49njPFDLSd3z+X1HgWDMpE=
|
||||
golang.org/x/sys v0.0.0-20191028164358-195ce5e7f934/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
|
@ -509,7 +684,11 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
|||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20170824195420-5d2fd3ccab98/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
|
@ -535,16 +714,24 @@ 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/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190128161407-8ac453e89fca/go.mod h1:L3J43x8/uS+qIUoksaLKe6OS3nUKxOKuIFz1sl2/jx4=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873 h1:nfPFGzJkUDX6uBmpN/pSw7MbOAWegH5QDQuoXFHedLg=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6 h1:UXl+Zk3jqqcbEVV7ace5lrt4YdA4tXiz3f/KbmD29Vo=
|
||||
google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.24.0 h1:vb/1TCsVn3DcJlQ0Gs1yB1pKI6Do2/QNwxdKqmc/b0s=
|
||||
google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
|
||||
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
|
@ -559,6 +746,7 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
|||
gopkg.in/mcuadros/go-syslog.v2 v2.2.1/go.mod h1:l5LPIyOOyIdQquNg+oU6Z3524YwrcqEm0aKH+5zpt2U=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||
gopkg.in/square/go-jose.v1 v1.1.2/go.mod h1:QpYS+a4WhS+DTlyQIi6Ka7MS3SuR9a055rgXNEe6EiA=
|
||||
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
|
|
@ -572,6 +760,10 @@ gotest.tools v2.1.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81
|
|||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
gotest.tools/gotestsum v0.3.5/go.mod h1:Mnf3e5FUzXbkCfynWBGOwLssY7gTQgCHObK9tMpAriY=
|
||||
helm.sh/helm v2.16.1+incompatible h1:np11uYeEtlYcFIFRya8Xs5ZweV1z6MvaWQqJAW+1SZQ=
|
||||
helm.sh/helm/v3 v3.0.2 h1:BggvLisIMrAc+Is5oAHVrlVxgwOOrMN8nddfQbm5gKo=
|
||||
helm.sh/helm/v3 v3.0.2/go.mod h1:KBxE6XWO57XSNA1PA9CvVLYRY0zWqYQTad84bNXp1lw=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
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-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
|
@ -603,10 +795,14 @@ k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUc
|
|||
k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||
k8s.io/klog v0.4.0 h1:lCJCxf/LIowc2IGS9TPjWDyXY4nOmdGdfcwwDQCOURQ=
|
||||
k8s.io/klog v0.4.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
|
||||
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
|
||||
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
|
||||
k8s.io/kube-aggregator v0.0.0-20190918161219-8c8f079fddc3/go.mod h1:NJisPUqwlg1A99RhO1BTnNtwC4pKUyXJ2f3Xc4PxKQg=
|
||||
k8s.io/kube-controller-manager v0.0.0-20190918162944-7a93a0ddadd8/go.mod h1:+HrHoqJm0UqnlrBEKXGzs2701YN4+ozi76oG7iYvJ8s=
|
||||
k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf h1:EYm5AW/UUDbnmnI+gK0TJDVK9qPLhM+sRHYanNKw0EQ=
|
||||
k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
|
||||
k8s.io/kube-openapi v0.0.0-20190918143330-0270cf2f1c1d h1:Xpe6sK+RY4ZgCTyZ3y273UmFmURhjtoJiwOMbQsXitY=
|
||||
k8s.io/kube-openapi v0.0.0-20190918143330-0270cf2f1c1d/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
|
||||
k8s.io/kube-proxy v0.0.0-20190918162534-de037b596c1e/go.mod h1:/48p8Y6dkWJrll4tsceAoGKudGpRmtQu/u1zlG14NnI=
|
||||
k8s.io/kube-scheduler v0.0.0-20190918162820-3b5c1246eb18/go.mod h1:k2dnGirIGylr51dpqxn2Zv6Yt47A+6NiynBIYfAU67I=
|
||||
k8s.io/kubectl v0.0.0-20190918164019-21692a0861df h1:EwjdCG4HveZxJkI650+g4UoIuSvH7vODn55VmBjxIAo=
|
||||
|
|
@ -621,11 +817,14 @@ k8s.io/repo-infra v0.0.0-20181204233714-00fe14e3d1a3/go.mod h1:+G1xBfZDfVFsm1Tj/
|
|||
k8s.io/sample-apiserver v0.0.0-20190918161442-d4c9c65c82af/go.mod h1:HP/BmiRyZTMIZ5RI2p4tCz/b2kre7URuKLQ7/KHqWAs=
|
||||
k8s.io/utils v0.0.0-20190801114015-581e00157fb1 h1:+ySTxfHnfzZb9ys375PXNlLhkJPLKgHajBU0N62BDvE=
|
||||
k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
||||
k8s.io/utils v0.0.0-20191010214722-8d271d903fe4 h1:Gi+/O1saihwDqnlmC8Vhv1M5Sp4+rbOmK9TbsLn8ZEA=
|
||||
k8s.io/utils v0.0.0-20191010214722-8d271d903fe4/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
||||
modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw=
|
||||
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=
|
||||
rsc.io/letsencrypt v0.0.1/go.mod h1:buyQKZ6IXrRnB7TdkHP0RyEybLx18HHyOSoTyoOLqNY=
|
||||
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=
|
||||
|
|
|
|||
|
|
@ -19,9 +19,6 @@ import (
|
|||
versioned "k8s.io/metrics/pkg/client/clientset/versioned"
|
||||
)
|
||||
|
||||
// NA Not available
|
||||
const NA = "n/a"
|
||||
|
||||
var supportedMetricsAPIVersions = []string{"v1beta1"}
|
||||
|
||||
// Authorizer checks what a user can or cannot do to a resource.
|
||||
|
|
@ -30,27 +27,6 @@ type Authorizer interface {
|
|||
CanI(ns, gvr string, verbs []string) (bool, error)
|
||||
}
|
||||
|
||||
// Connection represents a Kubenetes apiserver connection.
|
||||
// BOZO!! Refactor!
|
||||
type Connection interface {
|
||||
Authorizer
|
||||
|
||||
Config() *Config
|
||||
DialOrDie() kubernetes.Interface
|
||||
SwitchContextOrDie(ctx string)
|
||||
CachedDiscovery() (*disk.CachedDiscoveryClient, error)
|
||||
RestConfigOrDie() *restclient.Config
|
||||
MXDial() (*versioned.Clientset, error)
|
||||
DynDialOrDie() dynamic.Interface
|
||||
HasMetrics() bool
|
||||
IsNamespaced(n string) bool
|
||||
SupportsResource(group string) bool
|
||||
ValidNamespaces() ([]v1.Namespace, error)
|
||||
SupportsRes(grp string, versions []string) (string, bool, error)
|
||||
ServerVersion() (*version.Info, error)
|
||||
CurrentNamespaceName() (string, error)
|
||||
}
|
||||
|
||||
// APIClient represents a Kubernetes api client.
|
||||
type APIClient struct {
|
||||
client kubernetes.Interface
|
||||
|
|
|
|||
|
|
@ -11,6 +11,41 @@ import (
|
|||
|
||||
var toFileName = regexp.MustCompile(`[^(\w/\.)]`)
|
||||
|
||||
// ClusterWide returns true if ns designates cluster scope, false otherwise.
|
||||
func IsClusterWide(ns string) bool {
|
||||
return ns == NamespaceAll || ns == AllNamespaces || ns == ClusterScope
|
||||
}
|
||||
|
||||
// IsAllNamespace returns true if ns == all.
|
||||
func IsAllNamespace(ns string) bool {
|
||||
return ns == NamespaceAll
|
||||
}
|
||||
|
||||
// IsAllNamespaces returns true if all namespaces, false otherwise.
|
||||
func IsAllNamespaces(ns string) bool {
|
||||
return ns == NamespaceAll || ns == AllNamespaces
|
||||
}
|
||||
|
||||
// IsNamespaced returns true if a specific ns is given.
|
||||
func IsNamespaced(ns string) bool {
|
||||
return !IsClusterScoped(ns)
|
||||
}
|
||||
|
||||
// IsClusterScoped returns true if resource is not namespaced.
|
||||
func IsClusterScoped(ns string) bool {
|
||||
return ns == ClusterScope
|
||||
}
|
||||
|
||||
// NormalizeNS normalizes a namespace name to a k8s ns known designation.
|
||||
func NormalizeNS(ns string) string {
|
||||
switch ns {
|
||||
case NamespaceAll, ClusterScope:
|
||||
return ""
|
||||
default:
|
||||
return ns
|
||||
}
|
||||
}
|
||||
|
||||
// Namespaced converts a resource path to namespace and resource name.
|
||||
func Namespaced(p string) (string, string) {
|
||||
ns, n := path.Split(p)
|
||||
|
|
|
|||
|
|
@ -8,46 +8,10 @@ import (
|
|||
mv1beta1 "k8s.io/metrics/pkg/apis/metrics/v1beta1"
|
||||
)
|
||||
|
||||
const (
|
||||
NamespaceAll = "all"
|
||||
AllNamespaces = ""
|
||||
)
|
||||
|
||||
type (
|
||||
// MetricsServer serves cluster metrics for nodes and pods.
|
||||
MetricsServer struct {
|
||||
Connection
|
||||
}
|
||||
|
||||
currentMetrics struct {
|
||||
CurrentCPU int64
|
||||
CurrentMEM float64
|
||||
}
|
||||
|
||||
// PodMetrics represent an aggregation of all pod containers metrics.
|
||||
PodMetrics currentMetrics
|
||||
|
||||
// NodeMetrics describes raw node metrics.
|
||||
NodeMetrics struct {
|
||||
currentMetrics
|
||||
AvailCPU int64
|
||||
AvailMEM float64
|
||||
TotalCPU int64
|
||||
TotalMEM float64
|
||||
}
|
||||
|
||||
// ClusterMetrics summarizes total node metrics as percentages.
|
||||
ClusterMetrics struct {
|
||||
PercCPU float64
|
||||
PercMEM float64
|
||||
}
|
||||
|
||||
// NodesMetrics tracks usage metrics per nodes.
|
||||
NodesMetrics map[string]NodeMetrics
|
||||
|
||||
// PodsMetrics tracks usage metrics per pods.
|
||||
PodsMetrics map[string]PodMetrics
|
||||
)
|
||||
// MetricsServer serves cluster metrics for nodes and pods.
|
||||
type MetricsServer struct {
|
||||
Connection
|
||||
}
|
||||
|
||||
// NewMetricsServer return a metric server instance.
|
||||
func NewMetricsServer(c Connection) *MetricsServer {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/version"
|
||||
"k8s.io/client-go/discovery/cached/disk"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
versioned "k8s.io/metrics/pkg/client/clientset/versioned"
|
||||
)
|
||||
|
||||
const (
|
||||
// NA Not available
|
||||
NA = "n/a"
|
||||
|
||||
// NamespaceAll designates the fictional all namespace.
|
||||
NamespaceAll = "all"
|
||||
|
||||
// AllNamespaces designates all namespaces.
|
||||
AllNamespaces = ""
|
||||
|
||||
// ClusterScope designates a resource is not namespaced.
|
||||
ClusterScope = "-"
|
||||
)
|
||||
|
||||
// Connection represents a Kubenetes apiserver connection.
|
||||
// BOZO!! Refactor!
|
||||
type Connection interface {
|
||||
Authorizer
|
||||
|
||||
Config() *Config
|
||||
DialOrDie() kubernetes.Interface
|
||||
SwitchContextOrDie(ctx string)
|
||||
CachedDiscovery() (*disk.CachedDiscoveryClient, error)
|
||||
RestConfigOrDie() *restclient.Config
|
||||
MXDial() (*versioned.Clientset, error)
|
||||
DynDialOrDie() dynamic.Interface
|
||||
HasMetrics() bool
|
||||
IsNamespaced(n string) bool
|
||||
SupportsResource(group string) bool
|
||||
ValidNamespaces() ([]v1.Namespace, error)
|
||||
SupportsRes(grp string, versions []string) (string, bool, error)
|
||||
ServerVersion() (*version.Info, error)
|
||||
CurrentNamespaceName() (string, error)
|
||||
}
|
||||
|
||||
type currentMetrics struct {
|
||||
CurrentCPU int64
|
||||
CurrentMEM float64
|
||||
}
|
||||
|
||||
// PodMetrics represent an aggregation of all pod containers metrics.
|
||||
type PodMetrics currentMetrics
|
||||
|
||||
// NodeMetrics describes raw node metrics.
|
||||
type NodeMetrics struct {
|
||||
currentMetrics
|
||||
AvailCPU int64
|
||||
AvailMEM float64
|
||||
TotalCPU int64
|
||||
TotalMEM float64
|
||||
}
|
||||
|
||||
// ClusterMetrics summarizes total node metrics as percentages.
|
||||
type ClusterMetrics struct {
|
||||
PercCPU float64
|
||||
PercMEM float64
|
||||
}
|
||||
|
||||
// NodesMetrics tracks usage metrics per nodes.
|
||||
type NodesMetrics map[string]NodeMetrics
|
||||
|
||||
// PodsMetrics tracks usage metrics per pods.
|
||||
type PodsMetrics map[string]PodMetrics
|
||||
|
|
@ -33,13 +33,13 @@ func (n *Namespace) Validate(c client.Connection, ks KubeSettings) {
|
|||
return
|
||||
}
|
||||
nn := ks.NamespaceNames(nns)
|
||||
if !n.isAllNamespace() && !InList(nn, n.Active) {
|
||||
if !n.isAllNamespaces() && !InList(nn, n.Active) {
|
||||
log.Error().Msgf("[Config] Validation error active namespace %q does not exists", n.Active)
|
||||
}
|
||||
|
||||
for _, ns := range n.Favorites {
|
||||
if ns != allNS && !InList(nn, ns) {
|
||||
log.Debug().Msgf("[Config] Invalid favorite found '%s' - %t", ns, n.isAllNamespace())
|
||||
log.Debug().Msgf("[Config] Invalid favorite found '%s' - %t", ns, n.isAllNamespaces())
|
||||
n.rmFavNS(ns)
|
||||
}
|
||||
}
|
||||
|
|
@ -55,7 +55,7 @@ func (n *Namespace) SetActive(ns string, ks KubeSettings) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (n *Namespace) isAllNamespace() bool {
|
||||
func (n *Namespace) isAllNamespaces() bool {
|
||||
return n.Active == allNS || n.Active == ""
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,23 +1,32 @@
|
|||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/config"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
var _ Accessor = (*Alias)(nil)
|
||||
|
||||
// Alias tracks standard and custom command aliases.
|
||||
type Alias struct {
|
||||
NonResource
|
||||
config.Aliases
|
||||
factory Factory
|
||||
}
|
||||
|
||||
// NewAlias returns a new set of aliases.
|
||||
func NewAlias(f Factory) *Alias {
|
||||
return &Alias{
|
||||
Aliases: config.NewAliases(),
|
||||
factory: f,
|
||||
}
|
||||
a := Alias{Aliases: config.NewAliases()}
|
||||
a.Init(f, client.NewGVR("aliases"))
|
||||
|
||||
return &a
|
||||
}
|
||||
|
||||
// Clear remove all aliases.
|
||||
|
|
@ -27,9 +36,48 @@ func (a *Alias) Clear() {
|
|||
}
|
||||
}
|
||||
|
||||
// List returns a collection of screen dumps.
|
||||
// BOZO!! Already have aliases here. Refact!!
|
||||
func (a *Alias) List(ctx context.Context, _ string) ([]runtime.Object, error) {
|
||||
a, ok := ctx.Value(internal.KeyAliases).(*Alias)
|
||||
if !ok {
|
||||
return nil, errors.New("no aliases found in context")
|
||||
}
|
||||
|
||||
m := make(config.ShortNames, len(a.Alias))
|
||||
for alias, gvr := range a.Alias {
|
||||
if _, ok := m[gvr]; ok {
|
||||
m[gvr] = append(m[gvr], alias)
|
||||
} else {
|
||||
m[gvr] = []string{alias}
|
||||
}
|
||||
}
|
||||
|
||||
oo := make([]runtime.Object, 0, len(m))
|
||||
for gvr, aliases := range m {
|
||||
sort.StringSlice(aliases).Sort()
|
||||
oo = append(oo, render.AliasRes{GVR: gvr, Aliases: aliases})
|
||||
}
|
||||
|
||||
return oo, nil
|
||||
}
|
||||
|
||||
// GVR returns a matching gvr if it exists.
|
||||
func (a *Alias) AsGVR(cmd string) (client.GVR, bool) {
|
||||
gvr, ok := a.Aliases.Get(cmd)
|
||||
if ok {
|
||||
return client.NewGVR(gvr), true
|
||||
}
|
||||
return client.GVR{}, false
|
||||
}
|
||||
|
||||
func (a *Alias) Get(_ context.Context, _ string) (runtime.Object, error) {
|
||||
panic("NYI!")
|
||||
}
|
||||
|
||||
// Ensure makes sure alias are loaded.
|
||||
func (a *Alias) Ensure() (config.Alias, error) {
|
||||
if err := LoadResources(a.factory); err != nil {
|
||||
if err := LoadResources(a.Factory); err != nil {
|
||||
return config.Alias{}, err
|
||||
}
|
||||
return a.Alias, a.load()
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package model_test
|
||||
package dao_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
@ -8,7 +8,6 @@ import (
|
|||
"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/watch"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
|
@ -18,30 +17,17 @@ import (
|
|||
)
|
||||
|
||||
func TestAliasList(t *testing.T) {
|
||||
a := model.Alias{}
|
||||
a.Init(render.ClusterScope, "aliases", makeFactory())
|
||||
a := dao.Alias{}
|
||||
a.Init(makeFactory(), client.NewGVR("aliases"))
|
||||
|
||||
ctx := context.WithValue(context.Background(), internal.KeyAliases, makeAliases())
|
||||
oo, err := a.List(ctx)
|
||||
oo, err := a.List(ctx, "-")
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, len(oo))
|
||||
assert.Equal(t, 2, len(oo[0].(render.AliasRes).Aliases))
|
||||
}
|
||||
|
||||
func TestAliasHydrate(t *testing.T) {
|
||||
a := model.Alias{}
|
||||
a.Init(render.ClusterScope, "aliases", makeFactory())
|
||||
|
||||
ctx := context.WithValue(context.Background(), internal.KeyAliases, makeAliases())
|
||||
oo, err := a.List(ctx)
|
||||
assert.Nil(t, err)
|
||||
|
||||
rr := make(render.Rows, len(oo))
|
||||
assert.Nil(t, a.Hydrate(oo, rr, render.Alias{}))
|
||||
assert.Equal(t, 2, len(rr))
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Helpers...
|
||||
|
||||
|
|
@ -1,18 +1,53 @@
|
|||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
var (
|
||||
_ Accessor = (*Benchmark)(nil)
|
||||
_ Nuker = (*Benchmark)(nil)
|
||||
)
|
||||
|
||||
// Benchmark represents a benchmark resource.
|
||||
type Benchmark struct {
|
||||
Generic
|
||||
NonResource
|
||||
}
|
||||
|
||||
var _ Accessor = (*Benchmark)(nil)
|
||||
var _ Nuker = (*Benchmark)(nil)
|
||||
|
||||
// Delete a Benchmark.
|
||||
func (d *Benchmark) Delete(path string, cascade, force bool) error {
|
||||
// Delete nukes a resource.
|
||||
func (b *Benchmark) Delete(path string, cascade, force bool) error {
|
||||
return os.Remove(path)
|
||||
}
|
||||
|
||||
// Get returns a resource.
|
||||
func (b *Benchmark) Get(context.Context, string) (runtime.Object, error) {
|
||||
panic("NYI")
|
||||
}
|
||||
|
||||
// List returns a collection of resources.
|
||||
func (b *Benchmark) List(ctx context.Context, _ string) ([]runtime.Object, error) {
|
||||
dir, ok := ctx.Value(internal.KeyDir).(string)
|
||||
if !ok {
|
||||
return nil, errors.New("no benchmark dir found in context")
|
||||
}
|
||||
|
||||
ff, err := ioutil.ReadDir(dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
oo := make([]runtime.Object, len(ff))
|
||||
for i, f := range ff {
|
||||
oo[i] = render.BenchInfo{File: f, Path: filepath.Join(dir, f.Name())}
|
||||
}
|
||||
|
||||
return oo, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
package dao_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/dao"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestBenchmarkList(t *testing.T) {
|
||||
a := dao.Benchmark{}
|
||||
a.Init(makeFactory(), client.NewGVR("benchmarks"))
|
||||
|
||||
ctx := context.WithValue(context.Background(), internal.KeyDir, "test_assets/bench")
|
||||
oo, err := a.List(ctx, "-")
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 1, len(oo))
|
||||
assert.Equal(t, "test_assets/bench/default_fred_1577308050814961000.txt", oo[0].(render.BenchInfo).Path)
|
||||
}
|
||||
|
|
@ -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 = (*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 {
|
||||
log.Debug().Msgf("CHART DELETE %q", path)
|
||||
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
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
|
@ -3,23 +3,67 @@ package dao
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/rs/zerolog/log"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
mv1beta1 "k8s.io/metrics/pkg/apis/metrics/v1beta1"
|
||||
)
|
||||
|
||||
var (
|
||||
_ Accessor = (*Container)(nil)
|
||||
_ Loggable = (*Container)(nil)
|
||||
)
|
||||
|
||||
// Container represents a pod's container dao.
|
||||
type Container struct {
|
||||
Generic
|
||||
NonResource
|
||||
}
|
||||
|
||||
var _ Accessor = (*Container)(nil)
|
||||
var _ Loggable = (*Container)(nil)
|
||||
// List returns a collection of containers.
|
||||
func (c *Container) List(ctx context.Context, _ string) ([]runtime.Object, error) {
|
||||
path, ok := ctx.Value(internal.KeyPath).(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no context path for %q", c.gvr)
|
||||
}
|
||||
ns, _ := render.Namespaced(path)
|
||||
o, err := c.Factory.Get("v1/pods", path, true, labels.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var po v1.Pod
|
||||
err = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &po)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res := make([]runtime.Object, 0, len(po.Spec.InitContainers)+len(po.Spec.Containers))
|
||||
mx := client.NewMetricsServer(c.Client())
|
||||
var pmx *mv1beta1.PodMetrics
|
||||
if c.Client() != nil {
|
||||
var err error
|
||||
pmx, err = mx.FetchPodMetrics(ns, po.Name)
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msgf("No metrics found for pod %q:%q", ns, po.Name)
|
||||
}
|
||||
}
|
||||
|
||||
for _, co := range po.Spec.InitContainers {
|
||||
res = append(res, makeContainerRes(co, po, pmx, true))
|
||||
}
|
||||
for _, co := range po.Spec.Containers {
|
||||
res = append(res, makeContainerRes(co, po, pmx, false))
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// TailLogs tails a given container logs
|
||||
func (c *Container) TailLogs(ctx context.Context, logChan chan<- string, opts LogOptions) error {
|
||||
|
|
@ -51,3 +95,53 @@ func (c *Container) Logs(path string, opts *v1.PodLogOptions) (*restclient.Reque
|
|||
ns, n := client.Namespaced(path)
|
||||
return c.Client().DialOrDie().CoreV1().Pods(ns).GetLogs(n, opts), nil
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Helpers...
|
||||
|
||||
func makeContainerRes(co v1.Container, po v1.Pod, pmx *mv1beta1.PodMetrics, isInit bool) render.ContainerRes {
|
||||
cmx, err := containerMetrics(co.Name, pmx)
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msgf("Container metrics for %s", co.Name)
|
||||
}
|
||||
|
||||
return render.ContainerRes{
|
||||
Container: co,
|
||||
Status: getContainerStatus(co.Name, po.Status),
|
||||
Metrics: cmx,
|
||||
IsInit: isInit,
|
||||
Age: po.ObjectMeta.CreationTimestamp,
|
||||
}
|
||||
}
|
||||
|
||||
func containerMetrics(n string, mx runtime.Object) (*mv1beta1.ContainerMetrics, error) {
|
||||
pmx, ok := mx.(*mv1beta1.PodMetrics)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expecting podmetrics but got `%T", mx)
|
||||
}
|
||||
if pmx == nil {
|
||||
return nil, fmt.Errorf("no metrics for container %s", n)
|
||||
}
|
||||
for _, m := range pmx.Containers {
|
||||
if m.Name == n {
|
||||
return &m, nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func getContainerStatus(co string, status v1.PodStatus) *v1.ContainerStatus {
|
||||
for _, c := range status.ContainerStatuses {
|
||||
if c.Name == co {
|
||||
return &c
|
||||
}
|
||||
}
|
||||
|
||||
for _, c := range status.InitContainerStatuses {
|
||||
if c.Name == co {
|
||||
return &c
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package model_test
|
||||
package dao_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
@ -7,8 +7,6 @@ import (
|
|||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/dao"
|
||||
"github.com/derailed/k9s/internal/model"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/derailed/k9s/internal/watch"
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
|
@ -19,30 +17,15 @@ import (
|
|||
)
|
||||
|
||||
func TestContainerList(t *testing.T) {
|
||||
c := model.Container{}
|
||||
c.Init(render.ClusterScope, "containers", makePodFactory())
|
||||
c := dao.Container{}
|
||||
c.Init(makePodFactory(), client.NewGVR("containers"))
|
||||
|
||||
ctx := context.WithValue(context.Background(), internal.KeyPath, "fred/p1")
|
||||
oo, err := c.List(ctx)
|
||||
oo, err := c.List(ctx, "")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 1, len(oo))
|
||||
}
|
||||
|
||||
func TestContainerHydrate(t *testing.T) {
|
||||
c := model.Container{}
|
||||
c.Init(render.ClusterScope, "containers", makePodFactory())
|
||||
|
||||
ctx := context.WithValue(context.Background(), internal.KeyPath, "fred/p1")
|
||||
oo, err := c.List(ctx)
|
||||
assert.Nil(t, err)
|
||||
|
||||
rr := make(render.Rows, len(oo))
|
||||
assert.Nil(t, c.Hydrate(oo, rr, render.Container{}))
|
||||
assert.Equal(t, 1, len(rr))
|
||||
assert.Equal(t, "fred", rr[0].ID)
|
||||
assert.Equal(t, render.Fields{"fred", "blee", "false", "Running", "false", "0", "off:off", "n/a", "n/a", "n/a", "n/a", ""}, rr[0].Fields[0:len(rr[0].Fields)-1])
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Helpers...
|
||||
|
||||
|
|
@ -1,39 +1,40 @@
|
|||
package dao
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"context"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/rs/zerolog/log"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
)
|
||||
|
||||
var (
|
||||
_ Accessor = (*Context)(nil)
|
||||
_ Switchable = (*Context)(nil)
|
||||
)
|
||||
|
||||
// Context represents a kubenetes context.
|
||||
type Context struct {
|
||||
Generic
|
||||
NonResource
|
||||
}
|
||||
|
||||
var _ Accessor = (*Context)(nil)
|
||||
var _ Switchable = (*Context)(nil)
|
||||
|
||||
func (c *Context) config() *client.Config {
|
||||
return c.Factory.Client().Config()
|
||||
}
|
||||
|
||||
// Get a Context.
|
||||
func (c *Context) Get(_, n string) (runtime.Object, error) {
|
||||
ctx, err := c.config().GetContext(n)
|
||||
func (c *Context) Get(ctx context.Context, path string) (runtime.Object, error) {
|
||||
co, err := c.config().GetContext(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &render.NamedContext{Name: n, Context: ctx}, nil
|
||||
return &render.NamedContext{Name: path, Context: co}, nil
|
||||
}
|
||||
|
||||
// List all Contexts on the current cluster.
|
||||
func (c *Context) List(string, metav1.ListOptions) ([]runtime.Object, error) {
|
||||
func (c *Context) List(_ context.Context, _ string) ([]runtime.Object, error) {
|
||||
ctxs, err := c.config().Contexts()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -46,19 +47,6 @@ func (c *Context) List(string, metav1.ListOptions) ([]runtime.Object, error) {
|
|||
return cc, nil
|
||||
}
|
||||
|
||||
// Delete a Context.
|
||||
func (c *Context) Delete(path string, cascade, force bool) error {
|
||||
ctx, err := c.config().CurrentContextName()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ctx == path {
|
||||
return fmt.Errorf("trying to delete your current context %s", path)
|
||||
}
|
||||
|
||||
return c.config().DelContext(path)
|
||||
}
|
||||
|
||||
// MustCurrentContextName return the active context name.
|
||||
func (c *Context) MustCurrentContextName() string {
|
||||
cl, err := c.config().CurrentContextName()
|
||||
|
|
@ -87,36 +75,3 @@ func (c *Context) KubeUpdate(n string) error {
|
|||
clientcmd.NewDefaultPathOptions(), config, true,
|
||||
)
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// // NamedContext represents a named cluster context.
|
||||
// type NamedContext struct {
|
||||
// Name string
|
||||
// Context *api.Context
|
||||
// config *client.Config
|
||||
// }
|
||||
|
||||
// // NewNamedContext returns a new named context.
|
||||
// func NewNamedContext(c *client.Config, n string, ctx *api.Context) *NamedContext {
|
||||
// return &NamedContext{Name: n, Context: ctx, config: c}
|
||||
// }
|
||||
|
||||
// // MustCurrentContextName return the active context name.
|
||||
// func (c *NamedContext) MustCurrentContextName() string {
|
||||
// cl, err := c.config.CurrentContextName()
|
||||
// if err != nil {
|
||||
// log.Fatal().Err(err).Msg("Fetching current context")
|
||||
// }
|
||||
// return cl
|
||||
// }
|
||||
|
||||
// // GetObjectKind returns a schema object.
|
||||
// func (c *NamedContext) GetObjectKind() schema.ObjectKind {
|
||||
// return nil
|
||||
// }
|
||||
|
||||
// // DeepCopyObject returns a container copy.
|
||||
// func (c *NamedContext) DeepCopyObject() runtime.Object {
|
||||
// return c
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package model
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
@ -8,13 +8,18 @@ import (
|
|||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
var (
|
||||
_ Accessor = (*CustomResourceDefinition)(nil)
|
||||
_ Nuker = (*CustomResourceDefinition)(nil)
|
||||
)
|
||||
|
||||
// CustomResourceDefinition represents a CRD resource model.
|
||||
type CustomResourceDefinition struct {
|
||||
Resource
|
||||
}
|
||||
|
||||
// List returns a collection of nodes.
|
||||
func (c *CustomResourceDefinition) List(ctx context.Context) ([]runtime.Object, error) {
|
||||
func (c *CustomResourceDefinition) List(ctx context.Context, _ string) ([]runtime.Object, error) {
|
||||
strLabel, ok := ctx.Value(internal.KeyLabels).(string)
|
||||
lsel := labels.Everything()
|
||||
if sel, e := labels.ConvertSelectorToLabelsMap(strLabel); ok && e == nil {
|
||||
|
|
@ -22,7 +27,7 @@ func (c *CustomResourceDefinition) List(ctx context.Context) ([]runtime.Object,
|
|||
}
|
||||
|
||||
const gvr = "apiextensions.k8s.io/v1beta1/customresourcedefinitions"
|
||||
oo, err := c.factory.List(gvr, "-", true, lsel)
|
||||
oo, err := c.Factory.List(gvr, "-", true, lsel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -9,14 +9,16 @@ import (
|
|||
|
||||
const maxJobNameSize = 42
|
||||
|
||||
var (
|
||||
_ Accessor = (*CronJob)(nil)
|
||||
_ Runnable = (*CronJob)(nil)
|
||||
)
|
||||
|
||||
// CronJob represents a cronjob K8s resource.
|
||||
type CronJob struct {
|
||||
Generic
|
||||
}
|
||||
|
||||
var _ Accessor = (*CronJob)(nil)
|
||||
var _ Runnable = (*CronJob)(nil)
|
||||
|
||||
// Run a CronJob.
|
||||
func (c *CronJob) Run(path string) error {
|
||||
ns, n := client.Namespaced(path)
|
||||
|
|
@ -25,6 +27,7 @@ func (c *CronJob) Run(path string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// BOZO!! Factory resource??
|
||||
cj, err := c.Client().DialOrDie().BatchV1beta1().CronJobs(ns).Get(n, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
package dao
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
func mustMap(o runtime.Object, field string) map[string]interface{} {
|
||||
u, ok := o.(*unstructured.Unstructured)
|
||||
if !ok {
|
||||
panic("no unstructured")
|
||||
}
|
||||
m, ok := u.Object[field].(map[string]interface{})
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("map extract failed for %q", field))
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
func mustSlice(o runtime.Object, field string) []interface{} {
|
||||
u, ok := o.(*unstructured.Unstructured)
|
||||
if !ok {
|
||||
return []interface{}{}
|
||||
}
|
||||
s, ok := u.Object[field].([]interface{})
|
||||
if !ok {
|
||||
return []interface{}{}
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func mustField(o map[string]interface{}, field string) interface{} {
|
||||
f, ok := o[field]
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("no field for %q", field))
|
||||
}
|
||||
|
||||
return f
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package dao
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
func TestCruiserMeta(t *testing.T) {
|
||||
o := loadJSON(t, "crb")
|
||||
|
||||
m := mustMap(o, "metadata")
|
||||
assert.Equal(t, "blee", mustField(m, "name"))
|
||||
}
|
||||
|
||||
func TestCruiserSlice(t *testing.T) {
|
||||
o := loadJSON(t, "crb")
|
||||
|
||||
s := mustSlice(o, "subjects")
|
||||
assert.Equal(t, 1, len(s))
|
||||
assert.Equal(t, "fernand", mustField(s[0].(map[string]interface{}), "name"))
|
||||
assert.Equal(t, "User", mustField(s[0].(map[string]interface{}), "kind"))
|
||||
}
|
||||
|
||||
// Helpers...
|
||||
|
||||
func loadJSON(t assert.TestingT, n string) *unstructured.Unstructured {
|
||||
raw, err := ioutil.ReadFile(fmt.Sprintf("test_assets/%s.json", n))
|
||||
assert.Nil(t, err)
|
||||
|
||||
var o unstructured.Unstructured
|
||||
err = json.Unmarshal(raw, &o)
|
||||
assert.Nil(t, err)
|
||||
|
||||
return &o
|
||||
}
|
||||
|
|
@ -8,7 +8,8 @@ import (
|
|||
)
|
||||
|
||||
// Describe describes a resource.
|
||||
func Describe(c client.Connection, gvr client.GVR, ns, n string) (string, error) {
|
||||
func Describe(c client.Connection, gvr client.GVR, path string) (string, error) {
|
||||
log.Debug().Msgf("DESCRIBE %q::%q", gvr, path)
|
||||
mapper := RestMapper{Connection: c}
|
||||
m, err := mapper.ToRESTMapper()
|
||||
if err != nil {
|
||||
|
|
@ -22,6 +23,10 @@ func Describe(c client.Connection, gvr client.GVR, ns, n string) (string, error)
|
|||
return "", err
|
||||
}
|
||||
|
||||
ns, n := client.Namespaced(path)
|
||||
if client.IsClusterScoped(ns) {
|
||||
ns = client.AllNamespaces
|
||||
}
|
||||
mapping, err := mapper.ResourceFor(gvr.AsResourceName(), gvk.Kind)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("Unable to find mapper for %s %s", gvr, n)
|
||||
|
|
|
|||
|
|
@ -15,16 +15,19 @@ import (
|
|||
"k8s.io/kubectl/pkg/polymorphichelpers"
|
||||
)
|
||||
|
||||
var (
|
||||
_ Accessor = (*Deployment)(nil)
|
||||
_ Nuker = (*Deployment)(nil)
|
||||
_ Loggable = (*Deployment)(nil)
|
||||
_ Restartable = (*Deployment)(nil)
|
||||
_ Scalable = (*Deployment)(nil)
|
||||
)
|
||||
|
||||
// Deployment represents a deployment K8s resource.
|
||||
type Deployment struct {
|
||||
Generic
|
||||
Resource
|
||||
}
|
||||
|
||||
var _ Accessor = (*Deployment)(nil)
|
||||
var _ Loggable = (*Deployment)(nil)
|
||||
var _ Restartable = (*Deployment)(nil)
|
||||
var _ Scalable = (*Deployment)(nil)
|
||||
|
||||
// Scale a Deployment.
|
||||
func (d *Deployment) Scale(path string, replicas int32) error {
|
||||
ns, n := client.Namespaced(path)
|
||||
|
|
@ -45,7 +48,7 @@ func (d *Deployment) Scale(path string, replicas int32) error {
|
|||
|
||||
// Restart a Deployment rollout.
|
||||
func (d *Deployment) Restart(path string) error {
|
||||
o, err := d.Get(d.gvr.String(), path, true, labels.Everything())
|
||||
o, err := d.Factory.Get(d.gvr.String(), path, true, labels.Everything())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -71,7 +74,7 @@ func (d *Deployment) Restart(path string) error {
|
|||
|
||||
// TailLogs tail logs for all pods represented by this Deployment.
|
||||
func (d *Deployment) TailLogs(ctx context.Context, c chan<- string, opts LogOptions) error {
|
||||
o, err := d.Get(d.gvr.String(), opts.Path, true, labels.Everything())
|
||||
o, err := d.Factory.Get(d.gvr.String(), opts.Path, true, labels.Everything())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,18 +20,21 @@ import (
|
|||
"k8s.io/kubectl/pkg/polymorphichelpers"
|
||||
)
|
||||
|
||||
var (
|
||||
_ Accessor = (*DaemonSet)(nil)
|
||||
_ Nuker = (*DaemonSet)(nil)
|
||||
_ Loggable = (*DaemonSet)(nil)
|
||||
_ Restartable = (*DaemonSet)(nil)
|
||||
)
|
||||
|
||||
// DaemonSet represents a K8s daemonset.
|
||||
type DaemonSet struct {
|
||||
Generic
|
||||
Resource
|
||||
}
|
||||
|
||||
var _ Accessor = (*DaemonSet)(nil)
|
||||
var _ Loggable = (*DaemonSet)(nil)
|
||||
var _ Restartable = (*DaemonSet)(nil)
|
||||
|
||||
// Restart a DaemonSet rollout.
|
||||
func (d *DaemonSet) Restart(path string) error {
|
||||
o, err := d.Get(d.gvr.String(), path, true, labels.Everything())
|
||||
o, err := d.Factory.Get(d.gvr.String(), path, true, labels.Everything())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -56,7 +59,7 @@ func (d *DaemonSet) Restart(path string) error {
|
|||
|
||||
// TailLogs tail logs for all pods represented by this DaemonSet.
|
||||
func (d *DaemonSet) TailLogs(ctx context.Context, c chan<- string, opts LogOptions) error {
|
||||
o, err := d.Get(d.gvr.String(), opts.Path, true, labels.Everything())
|
||||
o, err := d.Factory.Get(d.gvr.String(), opts.Path, true, labels.Everything())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,24 +1,91 @@
|
|||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/rs/zerolog/log"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/dynamic"
|
||||
)
|
||||
|
||||
var _ Describer = (*Generic)(nil)
|
||||
|
||||
// Generic represents a generic resource.
|
||||
type Generic struct {
|
||||
Factory
|
||||
|
||||
gvr client.GVR
|
||||
NonResource
|
||||
}
|
||||
|
||||
// Init initializes the resource.
|
||||
func (g *Generic) Init(f Factory, gvr client.GVR) {
|
||||
g.Factory, g.gvr = f, gvr
|
||||
// Describe describes a k8s resource.
|
||||
func (g *Generic) Describe(path string) (string, error) {
|
||||
return Describe(g.Client(), g.gvr, path)
|
||||
}
|
||||
|
||||
// Delete a Generic.
|
||||
// ToYAML returns a resource yaml.
|
||||
func (g *Generic) ToYAML(path string) (string, error) {
|
||||
o, err := g.Get(context.Background(), path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
raw, err := ToYAML(o)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to marshal resource %s", err)
|
||||
}
|
||||
return raw, nil
|
||||
}
|
||||
|
||||
// List returns a collection of nodes.
|
||||
func (g *Generic) List(ctx context.Context, ns string) ([]runtime.Object, error) {
|
||||
labelSel, ok := ctx.Value(internal.KeyLabels).(string)
|
||||
if !ok {
|
||||
log.Warn().Msgf("No label selector found in context. Listing all resources")
|
||||
}
|
||||
|
||||
if client.IsAllNamespace(ns) {
|
||||
ns = client.AllNamespaces
|
||||
}
|
||||
|
||||
var (
|
||||
ll *unstructured.UnstructuredList
|
||||
err error
|
||||
)
|
||||
if client.IsNamespaced(ns) {
|
||||
ll, err = g.dynClient().Namespace(ns).List(metav1.ListOptions{LabelSelector: labelSel})
|
||||
} else {
|
||||
ll, err = g.dynClient().List(metav1.ListOptions{LabelSelector: labelSel})
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
oo := make([]runtime.Object, len(ll.Items))
|
||||
for i := range ll.Items {
|
||||
oo[i] = &ll.Items[i]
|
||||
}
|
||||
|
||||
return oo, nil
|
||||
}
|
||||
|
||||
// List returns a collection of node resources.
|
||||
func (g *Generic) Get(ctx context.Context, path string) (runtime.Object, error) {
|
||||
var opts metav1.GetOptions
|
||||
|
||||
ns, n := client.Namespaced(path)
|
||||
req := g.dynClient()
|
||||
if client.IsClusterScoped(ns) {
|
||||
return req.Get(n, opts)
|
||||
}
|
||||
|
||||
return req.Namespace(ns).Get(n, opts)
|
||||
}
|
||||
|
||||
// Delete deletes a resource.
|
||||
func (g *Generic) Delete(path string, cascade, force bool) error {
|
||||
ns, n := client.Namespaced(path)
|
||||
auth, err := g.Client().CanI(ns, g.gvr.String(), []string{"delete"})
|
||||
|
|
@ -31,10 +98,11 @@ func (g *Generic) Delete(path string, cascade, force bool) error {
|
|||
p = metav1.DeletePropagationBackground
|
||||
}
|
||||
opts := metav1.DeleteOptions{PropagationPolicy: &p}
|
||||
if ns != "-" {
|
||||
return g.dynClient().Namespace(ns).Delete(n, &opts)
|
||||
if client.IsClusterScoped(ns) {
|
||||
return g.dynClient().Delete(n, &opts)
|
||||
}
|
||||
return g.dynClient().Delete(n, &opts)
|
||||
|
||||
return g.dynClient().Namespace(ns).Delete(n, &opts)
|
||||
}
|
||||
|
||||
func (g *Generic) dynClient() dynamic.NamespaceableResourceInterface {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,15 @@
|
|||
package dao
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"math"
|
||||
|
||||
"github.com/derailed/tview"
|
||||
runewidth "github.com/mattn/go-runewidth"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"github.com/rs/zerolog/log"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/cli-runtime/pkg/printers"
|
||||
)
|
||||
|
||||
func toPerc(v1, v2 float64) float64 {
|
||||
|
|
@ -21,12 +24,20 @@ func Truncate(str string, width int) string {
|
|||
return runewidth.Truncate(str, width, string(tview.SemigraphicsHorizontalEllipsis))
|
||||
}
|
||||
|
||||
// FetchNodes returns a collection of nodes.
|
||||
func FetchNodes(f Factory) (*v1.NodeList, error) {
|
||||
auth, err := f.Client().CanI("", "v1/nodes", []string{"list"})
|
||||
if !auth || err != nil {
|
||||
return nil, err
|
||||
// ToYAML converts a resource to its YAML representation.
|
||||
func ToYAML(o runtime.Object) (string, error) {
|
||||
if o == nil {
|
||||
return "", errors.New("no object to yamlize")
|
||||
}
|
||||
var (
|
||||
buff bytes.Buffer
|
||||
p printers.YAMLPrinter
|
||||
)
|
||||
err := p.PrintObj(o, &buff)
|
||||
if err != nil {
|
||||
log.Error().Msgf("Marshal Error %v", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
return f.Client().DialOrDie().CoreV1().Nodes().List(metav1.ListOptions{})
|
||||
return buff.String(), nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package model
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
@ -10,13 +10,18 @@ import (
|
|||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
var (
|
||||
_ Accessor = (*HorizontalPodAutoscaler)(nil)
|
||||
_ Nuker = (*HorizontalPodAutoscaler)(nil)
|
||||
)
|
||||
|
||||
// HorizontalPodAutoscaler represents a HPA resource model.
|
||||
type HorizontalPodAutoscaler struct {
|
||||
Resource
|
||||
}
|
||||
|
||||
// List returns a collection of nodes.
|
||||
func (h *HorizontalPodAutoscaler) List(ctx context.Context) ([]runtime.Object, error) {
|
||||
func (h *HorizontalPodAutoscaler) List(ctx context.Context, ns string) ([]runtime.Object, error) {
|
||||
strLabel, ok := ctx.Value(internal.KeyLabels).(string)
|
||||
lsel := labels.Everything()
|
||||
if sel, err := labels.ConvertSelectorToLabelsMap(strLabel); ok && err == nil {
|
||||
|
|
@ -30,7 +35,7 @@ func (h *HorizontalPodAutoscaler) List(ctx context.Context) ([]runtime.Object, e
|
|||
}
|
||||
|
||||
for _, gvr := range gvrs {
|
||||
oo, err := h.list(gvr, lsel)
|
||||
oo, err := h.list(gvr, ns, lsel)
|
||||
if err == nil && len(oo) > 0 {
|
||||
return oo, nil
|
||||
}
|
||||
|
|
@ -40,8 +45,8 @@ func (h *HorizontalPodAutoscaler) List(ctx context.Context) ([]runtime.Object, e
|
|||
return []runtime.Object{}, nil
|
||||
}
|
||||
|
||||
func (h *HorizontalPodAutoscaler) list(gvr string, sel labels.Selector) ([]runtime.Object, error) {
|
||||
oo, err := h.factory.List(gvr, h.namespace, true, sel)
|
||||
func (h *HorizontalPodAutoscaler) list(gvr, ns string, sel labels.Selector) ([]runtime.Object, error) {
|
||||
oo, err := h.Factory.List(gvr, ns, true, sel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -11,17 +11,20 @@ import (
|
|||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
var (
|
||||
_ Accessor = (*Job)(nil)
|
||||
_ Nuker = (*Job)(nil)
|
||||
_ Loggable = (*Job)(nil)
|
||||
)
|
||||
|
||||
// Job represents a K8s job resource.
|
||||
type Job struct {
|
||||
Generic
|
||||
Resource
|
||||
}
|
||||
|
||||
var _ Accessor = (*Job)(nil)
|
||||
var _ Loggable = (*Job)(nil)
|
||||
|
||||
// TailLogs tail logs for all pods represented by this Job.
|
||||
func (j *Job) TailLogs(ctx context.Context, c chan<- string, opts LogOptions) error {
|
||||
o, err := j.Get(j.gvr.String(), opts.Path, true, labels.Everything())
|
||||
o, err := j.Factory.Get(j.gvr.String(), opts.Path, true, labels.Everything())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,22 @@
|
|||
package model
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/dao"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/rs/zerolog/log"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
mv1beta1 "k8s.io/metrics/pkg/apis/metrics/v1beta1"
|
||||
)
|
||||
|
||||
var (
|
||||
_ Accessor = (*Node)(nil)
|
||||
)
|
||||
|
||||
type NodeMetricsFunc func() (*mv1beta1.NodeMetricsList, error)
|
||||
|
||||
// Node represents a node model.
|
||||
|
|
@ -21,13 +25,13 @@ type Node struct {
|
|||
}
|
||||
|
||||
// List returns a collection of node resources.
|
||||
func (n *Node) List(ctx context.Context) ([]runtime.Object, error) {
|
||||
func (n *Node) List(ctx context.Context, ns string) ([]runtime.Object, error) {
|
||||
nmx, ok := ctx.Value(internal.KeyMetrics).(*mv1beta1.NodeMetricsList)
|
||||
if !ok {
|
||||
log.Warn().Msgf("No node metrics available in context")
|
||||
}
|
||||
|
||||
nn, err := dao.FetchNodes(n.factory)
|
||||
nn, err := FetchNodes(n.Factory)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -47,27 +51,18 @@ func (n *Node) List(ctx context.Context) ([]runtime.Object, error) {
|
|||
return oo, nil
|
||||
}
|
||||
|
||||
// Hydrate returns nodes as rows.
|
||||
func (n *Node) Hydrate(oo []runtime.Object, rr render.Rows, re Renderer) error {
|
||||
for i, o := range oo {
|
||||
nmx, ok := o.(*render.NodeWithMetrics)
|
||||
if !ok {
|
||||
return fmt.Errorf("expecting *NodeWithMetrics but got %T", o)
|
||||
}
|
||||
|
||||
var row render.Row
|
||||
if err := re.Render(nmx, render.ClusterScope, &row); err != nil {
|
||||
return err
|
||||
}
|
||||
rr[i] = row
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Helpers...
|
||||
|
||||
func FetchNodes(f Factory) (*v1.NodeList, error) {
|
||||
auth, err := f.Client().CanI("", "v1/nodes", []string{"list"})
|
||||
if !auth || err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return f.Client().DialOrDie().CoreV1().Nodes().List(metav1.ListOptions{})
|
||||
}
|
||||
|
||||
func nodeMetricsFor(fqn string, mmx *mv1beta1.NodeMetricsList) *mv1beta1.NodeMetrics {
|
||||
for _, mx := range mmx.Items {
|
||||
if MetaFQN(mx.ObjectMeta) == fqn {
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// NonResource represents a non k8s resource.
|
||||
type NonResource struct {
|
||||
Factory
|
||||
|
||||
gvr client.GVR
|
||||
}
|
||||
|
||||
// Init initializes the resource.
|
||||
func (g *NonResource) Init(f Factory, gvr client.GVR) {
|
||||
g.Factory, g.gvr = f, gvr
|
||||
}
|
||||
|
||||
func (g *NonResource) GVR() string {
|
||||
return g.gvr.String()
|
||||
}
|
||||
|
||||
// Get returns the given resource.
|
||||
func (c *NonResource) Get(context.Context, string) (runtime.Object, error) {
|
||||
return nil, fmt.Errorf("NYI!")
|
||||
}
|
||||
|
|
@ -12,24 +12,75 @@ import (
|
|||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/color"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/derailed/k9s/internal/watch"
|
||||
"github.com/rs/zerolog/log"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
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"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
mv1beta1 "k8s.io/metrics/pkg/apis/metrics/v1beta1"
|
||||
)
|
||||
|
||||
const defaultTimeout = 1 * time.Second
|
||||
|
||||
var (
|
||||
_ Accessor = (*Pod)(nil)
|
||||
_ Nuker = (*Pod)(nil)
|
||||
_ Loggable = (*Pod)(nil)
|
||||
)
|
||||
|
||||
// Pod represents a pod resource.
|
||||
type Pod struct {
|
||||
Generic
|
||||
Resource
|
||||
}
|
||||
|
||||
var _ Accessor = (*Pod)(nil)
|
||||
var _ Loggable = (*Pod)(nil)
|
||||
// List returns a collection of nodes.
|
||||
func (p *Pod) List(ctx context.Context, ns string) ([]runtime.Object, error) {
|
||||
oo, err := p.Resource.List(ctx, ns)
|
||||
if err != nil {
|
||||
return oo, err
|
||||
}
|
||||
|
||||
pmx, ok := ctx.Value(internal.KeyMetrics).(*mv1beta1.PodMetricsList)
|
||||
if !ok {
|
||||
log.Warn().Msgf("expecting context PodMetricsList")
|
||||
}
|
||||
|
||||
sel, ok := ctx.Value(internal.KeyFields).(string)
|
||||
if !ok {
|
||||
return oo, nil
|
||||
}
|
||||
fsel, err := labels.ConvertSelectorToLabelsMap(sel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nodeName := fsel["spec.nodeName"]
|
||||
|
||||
var res []runtime.Object
|
||||
for _, o := range oo {
|
||||
u, ok := o.(*unstructured.Unstructured)
|
||||
if !ok {
|
||||
return res, fmt.Errorf("expecting *unstructured.Unstructured but got `%T", o)
|
||||
}
|
||||
if nodeName == "" {
|
||||
res = append(res, &render.PodWithMetrics{Raw: u, MX: podMetricsFor(o, pmx)})
|
||||
continue
|
||||
}
|
||||
|
||||
spec, ok := u.Object["spec"].(map[string]interface{})
|
||||
if !ok {
|
||||
return res, fmt.Errorf("expecting interface map but got `%T", o)
|
||||
}
|
||||
if spec["nodeName"] == nodeName {
|
||||
res = append(res, &render.PodWithMetrics{Raw: u, MX: podMetricsFor(o, pmx)})
|
||||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Logs fetch container logs for a given pod and container.
|
||||
func (p *Pod) Logs(path string, opts *v1.PodLogOptions) (*restclient.Request, error) {
|
||||
|
|
@ -45,7 +96,7 @@ func (p *Pod) Logs(path string, opts *v1.PodLogOptions) (*restclient.Request, er
|
|||
|
||||
// Containers returns all container names on pod
|
||||
func (p *Pod) Containers(path string, includeInit bool) ([]string, error) {
|
||||
o, err := p.Get(p.gvr.String(), path, true, labels.Everything())
|
||||
o, err := p.Factory.Get(p.gvr.String(), path, true, labels.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -177,6 +228,59 @@ func readLogs(ctx context.Context, stream io.ReadCloser, c chan<- string, opts L
|
|||
// ----------------------------------------------------------------------------
|
||||
// Helpers...
|
||||
|
||||
func podMetricsFor(o runtime.Object, mmx *mv1beta1.PodMetricsList) *mv1beta1.PodMetrics {
|
||||
fqn := extractFQN(o)
|
||||
for _, mx := range mmx.Items {
|
||||
if MetaFQN(mx.ObjectMeta) == fqn {
|
||||
return &mx
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MetaFQN returns a fully qualified resource name.
|
||||
func MetaFQN(m metav1.ObjectMeta) string {
|
||||
if m.Namespace == "" {
|
||||
return m.Name
|
||||
}
|
||||
|
||||
return FQN(m.Namespace, m.Name)
|
||||
}
|
||||
|
||||
// FQN returns a fully qualified resource name.
|
||||
func FQN(ns, n string) string {
|
||||
if ns == "" {
|
||||
return n
|
||||
}
|
||||
return ns + "/" + n
|
||||
}
|
||||
|
||||
func extractFQN(o runtime.Object) string {
|
||||
u, ok := o.(*unstructured.Unstructured)
|
||||
if !ok {
|
||||
log.Error().Err(fmt.Errorf("expecting unstructured but got %T", o))
|
||||
return "na"
|
||||
}
|
||||
m, ok := u.Object["metadata"].(map[string]interface{})
|
||||
if !ok {
|
||||
log.Error().Err(fmt.Errorf("expecting interface map for metadata but got %T", u.Object["metadata"]))
|
||||
return "na"
|
||||
}
|
||||
|
||||
n, ok := m["name"].(string)
|
||||
if !ok {
|
||||
log.Error().Err(fmt.Errorf("expecting interface map for name but got %T", m["name"]))
|
||||
return "na"
|
||||
}
|
||||
|
||||
ns, ok := m["namespace"].(string)
|
||||
if !ok {
|
||||
return FQN("", n)
|
||||
}
|
||||
|
||||
return FQN(ns, n)
|
||||
}
|
||||
|
||||
func loggableContainers(s v1.PodStatus) []string {
|
||||
var rcos []string
|
||||
for _, c := range s.ContainerStatuses {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package model
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
@ -12,21 +12,38 @@ import (
|
|||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// PortForward represents a portforward model.
|
||||
var (
|
||||
_ Accessor = (*PortForward)(nil)
|
||||
_ Nuker = (*PortForward)(nil)
|
||||
)
|
||||
|
||||
// PortForward represents a port forward dao.
|
||||
type PortForward struct {
|
||||
Resource
|
||||
NonResource
|
||||
}
|
||||
|
||||
// Delete a portforward.
|
||||
func (p *PortForward) Delete(path string, cascade, force bool) error {
|
||||
ns, _ := client.Namespaced(path)
|
||||
auth, err := p.Client().CanI(ns, "v1/pods:portforward", []string{"delete"})
|
||||
if !auth || err != nil {
|
||||
return err
|
||||
}
|
||||
p.Factory.DeleteForwarder(path)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// List returns a collection of screen dumps.
|
||||
func (c *PortForward) List(ctx context.Context) ([]runtime.Object, error) {
|
||||
func (c *PortForward) List(ctx context.Context, _ string) ([]runtime.Object, error) {
|
||||
config, ok := ctx.Value(internal.KeyBenchCfg).(*config.Bench)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no benchconfig found in context")
|
||||
}
|
||||
|
||||
cc := config.Benchmarks.Containers
|
||||
oo := make([]runtime.Object, 0, len(c.factory.Forwarders()))
|
||||
for _, f := range c.factory.Forwarders() {
|
||||
oo := make([]runtime.Object, 0, len(c.Factory.Forwarders()))
|
||||
for _, f := range c.Factory.Forwarders() {
|
||||
cfg := render.BenchCfg{
|
||||
C: config.Benchmarks.Defaults.C,
|
||||
N: config.Benchmarks.Defaults.N,
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
package dao
|
||||
|
||||
import (
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
)
|
||||
|
||||
// PortForward represents a port forward dao.
|
||||
type PortForward struct {
|
||||
Generic
|
||||
}
|
||||
|
||||
var _ Accessor = (*PortForward)(nil)
|
||||
var _ Nuker = (*PortForward)(nil)
|
||||
|
||||
// Delete a portforward.
|
||||
func (p *PortForward) Delete(path string, cascade, force bool) error {
|
||||
ns, _ := client.Namespaced(path)
|
||||
auth, err := p.Client().CanI(ns, "v1/pods:portforward", []string{"delete"})
|
||||
if !auth || err != nil {
|
||||
return err
|
||||
}
|
||||
p.Factory.DeleteForwarder(path)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package model
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
@ -20,24 +20,28 @@ const (
|
|||
rGVR = "rbac.authorization.k8s.io/v1/roles"
|
||||
)
|
||||
|
||||
var (
|
||||
_ Accessor = (*Rbac)(nil)
|
||||
_ Nuker = (*Rbac)(nil)
|
||||
)
|
||||
|
||||
// Rbac represents a model for listing rbac resources.
|
||||
type Rbac struct {
|
||||
Resource
|
||||
}
|
||||
|
||||
// List lists out rbac resources.
|
||||
func (r *Rbac) List(ctx context.Context) ([]runtime.Object, error) {
|
||||
func (r *Rbac) List(ctx context.Context, ns string) ([]runtime.Object, error) {
|
||||
gvr, ok := ctx.Value(internal.KeyGVR).(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expecting a context gvr")
|
||||
}
|
||||
r.gvr = gvr
|
||||
path, ok := ctx.Value(internal.KeyPath).(string)
|
||||
if !ok || path == "" {
|
||||
return r.Resource.List(ctx)
|
||||
return r.Resource.List(ctx, ns)
|
||||
}
|
||||
|
||||
res := client.NewGVR(r.gvr)
|
||||
res := client.NewGVR(gvr)
|
||||
switch res.ToR() {
|
||||
case "clusterrolebindings":
|
||||
return r.loadClusterRoleBinding(path)
|
||||
|
|
@ -53,7 +57,7 @@ func (r *Rbac) List(ctx context.Context) ([]runtime.Object, error) {
|
|||
}
|
||||
|
||||
func (r *Rbac) loadClusterRoleBinding(path string) ([]runtime.Object, error) {
|
||||
o, err := r.factory.Get(crbGVR, path, true, labels.Everything())
|
||||
o, err := r.Factory.Get(crbGVR, path, true, labels.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -64,7 +68,7 @@ func (r *Rbac) loadClusterRoleBinding(path string) ([]runtime.Object, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
crbo, err := r.factory.Get(crGVR, client.FQN("-", crb.RoleRef.Name), true, labels.Everything())
|
||||
crbo, err := r.Factory.Get(crGVR, client.FQN("-", crb.RoleRef.Name), true, labels.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -74,11 +78,11 @@ func (r *Rbac) loadClusterRoleBinding(path string) ([]runtime.Object, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return asRuntimeObjects(parseRules(render.ClusterScope, "-", cr.Rules)), nil
|
||||
return asRuntimeObjects(parseRules(client.ClusterScope, "-", cr.Rules)), nil
|
||||
}
|
||||
|
||||
func (r *Rbac) loadRoleBinding(path string) ([]runtime.Object, error) {
|
||||
o, err := r.factory.Get(rbGVR, path, true, labels.Everything())
|
||||
o, err := r.Factory.Get(rbGVR, path, true, labels.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -89,7 +93,7 @@ func (r *Rbac) loadRoleBinding(path string) ([]runtime.Object, error) {
|
|||
}
|
||||
|
||||
if rb.RoleRef.Kind == "ClusterRole" {
|
||||
o, e := r.factory.Get(crGVR, client.FQN("-", rb.RoleRef.Name), true, labels.Everything())
|
||||
o, e := r.Factory.Get(crGVR, client.FQN("-", rb.RoleRef.Name), true, labels.Everything())
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
|
|
@ -98,10 +102,10 @@ func (r *Rbac) loadRoleBinding(path string) ([]runtime.Object, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return asRuntimeObjects(parseRules(render.ClusterScope, "-", cr.Rules)), nil
|
||||
return asRuntimeObjects(parseRules(client.ClusterScope, "-", cr.Rules)), nil
|
||||
}
|
||||
|
||||
ro, err := r.factory.Get(rGVR, client.FQN(rb.Namespace, rb.RoleRef.Name), true, labels.Everything())
|
||||
ro, err := r.Factory.Get(rGVR, client.FQN(rb.Namespace, rb.RoleRef.Name), true, labels.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -111,11 +115,11 @@ func (r *Rbac) loadRoleBinding(path string) ([]runtime.Object, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return asRuntimeObjects(parseRules(render.ClusterScope, "-", role.Rules)), nil
|
||||
return asRuntimeObjects(parseRules(client.ClusterScope, "-", role.Rules)), nil
|
||||
}
|
||||
|
||||
func (r *Rbac) loadClusterRole(path string) ([]runtime.Object, error) {
|
||||
o, err := r.factory.Get(crGVR, path, true, labels.Everything())
|
||||
o, err := r.Factory.Get(crGVR, path, true, labels.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -126,11 +130,11 @@ func (r *Rbac) loadClusterRole(path string) ([]runtime.Object, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return asRuntimeObjects(parseRules(render.ClusterScope, "-", cr.Rules)), nil
|
||||
return asRuntimeObjects(parseRules(client.ClusterScope, "-", cr.Rules)), nil
|
||||
}
|
||||
|
||||
func (r *Rbac) loadRole(path string) ([]runtime.Object, error) {
|
||||
o, err := r.factory.Get(rGVR, path, true, labels.Everything())
|
||||
o, err := r.Factory.Get(rGVR, path, true, labels.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -141,7 +145,7 @@ func (r *Rbac) loadRole(path string) ([]runtime.Object, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return asRuntimeObjects(parseRules(render.ClusterScope, "-", ro.Rules)), nil
|
||||
return asRuntimeObjects(parseRules(client.ClusterScope, "-", ro.Rules)), nil
|
||||
}
|
||||
|
||||
func asRuntimeObjects(rr render.Policies) []runtime.Object {
|
||||
|
|
@ -152,3 +156,25 @@ func asRuntimeObjects(rr render.Policies) []runtime.Object {
|
|||
|
||||
return oo
|
||||
}
|
||||
|
||||
func parseRules(ns, binding string, rules []rbacv1.PolicyRule) render.Policies {
|
||||
pp := make(render.Policies, 0, len(rules))
|
||||
for _, rule := range rules {
|
||||
for _, grp := range rule.APIGroups {
|
||||
for _, res := range rule.Resources {
|
||||
for _, na := range rule.ResourceNames {
|
||||
pp = pp.Upsert(render.NewPolicyRes(ns, binding, FQN(res, na), grp, rule.Verbs))
|
||||
}
|
||||
pp = pp.Upsert(render.NewPolicyRes(ns, binding, FQN(grp, res), grp, rule.Verbs))
|
||||
}
|
||||
}
|
||||
for _, nres := range rule.NonResourceURLs {
|
||||
if nres[0] != '/' {
|
||||
nres = "/" + nres
|
||||
}
|
||||
pp = pp.Upsert(render.NewPolicyRes(ns, binding, nres, "n/a", rule.Verbs))
|
||||
}
|
||||
}
|
||||
|
||||
return pp
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
package model
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/dao"
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/rs/zerolog/log"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
|
|
@ -14,17 +14,18 @@ import (
|
|||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
var (
|
||||
_ Accessor = (*Policy)(nil)
|
||||
_ Nuker = (*Policy)(nil)
|
||||
)
|
||||
|
||||
// Policy represent rbac policy.
|
||||
type Policy struct {
|
||||
Resource
|
||||
}
|
||||
|
||||
// List returns available policies.
|
||||
func (p *Policy) List(ctx context.Context) ([]runtime.Object, error) {
|
||||
gvr, ok := ctx.Value(internal.KeyGVR).(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expecting a context gvr")
|
||||
}
|
||||
func (p *Policy) List(ctx context.Context, ns string) ([]runtime.Object, error) {
|
||||
kind, ok := ctx.Value(internal.KeySubjectKind).(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expecting a context subject kind")
|
||||
|
|
@ -34,7 +35,6 @@ func (p *Policy) List(ctx context.Context) ([]runtime.Object, error) {
|
|||
return nil, fmt.Errorf("expecting a context subject name")
|
||||
}
|
||||
|
||||
p.gvr = gvr
|
||||
crps, err := p.loadClusterRoleBinding(kind, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -56,7 +56,7 @@ func (p *Policy) List(ctx context.Context) ([]runtime.Object, error) {
|
|||
}
|
||||
|
||||
func (p *Policy) loadClusterRoleBinding(kind, name string) (render.Policies, error) {
|
||||
crbs, err := fetchClusterRoleBindings(p.factory)
|
||||
crbs, err := fetchClusterRoleBindings(p.Factory)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -118,8 +118,8 @@ func (p *Policy) loadRoleBinding(kind, name string) (render.Policies, error) {
|
|||
return rows, nil
|
||||
}
|
||||
|
||||
func fetchClusterRoleBindings(f dao.Factory) ([]rbacv1.ClusterRoleBinding, error) {
|
||||
oo, err := f.List(crbGVR, render.ClusterScope, true, labels.Everything())
|
||||
func fetchClusterRoleBindings(f Factory) ([]rbacv1.ClusterRoleBinding, error) {
|
||||
oo, err := f.List(crbGVR, client.ClusterScope, false, labels.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -136,8 +136,8 @@ func fetchClusterRoleBindings(f dao.Factory) ([]rbacv1.ClusterRoleBinding, error
|
|||
return crbs, nil
|
||||
}
|
||||
|
||||
func fetchRoleBindings(f dao.Factory) ([]rbacv1.RoleBinding, error) {
|
||||
oo, err := f.List(rbGVR, render.ClusterScope, true, labels.Everything())
|
||||
func fetchRoleBindings(f Factory) ([]rbacv1.RoleBinding, error) {
|
||||
oo, err := f.List(rbGVR, client.ClusterScope, false, labels.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -155,7 +155,7 @@ func fetchRoleBindings(f dao.Factory) ([]rbacv1.RoleBinding, error) {
|
|||
}
|
||||
|
||||
func (p *Policy) fetchRoleBindingSubjects(kind, name string) ([]string, error) {
|
||||
rbs, err := fetchRoleBindings(p.factory)
|
||||
rbs, err := fetchRoleBindings(p.Factory)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -174,7 +174,7 @@ func (p *Policy) fetchRoleBindingSubjects(kind, name string) ([]string, error) {
|
|||
func (p *Policy) fetchClusterRoles() ([]rbacv1.ClusterRole, error) {
|
||||
const gvr = "rbac.authorization.k8s.io/v1/clusterroles"
|
||||
|
||||
oo, err := p.factory.List(gvr, render.ClusterScope, true, labels.Everything())
|
||||
oo, err := p.Factory.List(gvr, client.ClusterScope, false, labels.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -194,7 +194,7 @@ func (p *Policy) fetchClusterRoles() ([]rbacv1.ClusterRole, error) {
|
|||
func (p *Policy) fetchRoles() ([]rbacv1.Role, error) {
|
||||
const gvr = "rbac.authorization.k8s.io/v1/roles"
|
||||
|
||||
oo, err := p.factory.List(gvr, render.AllNamespaces, true, labels.Everything())
|
||||
oo, err := p.Factory.List(gvr, client.AllNamespaces, false, labels.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -210,34 +210,3 @@ func (p *Policy) fetchRoles() ([]rbacv1.Role, error) {
|
|||
|
||||
return rr, nil
|
||||
}
|
||||
|
||||
func in(nn []string, match string) bool {
|
||||
for _, n := range nn {
|
||||
if n == match {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func parseRules(ns, binding string, rules []rbacv1.PolicyRule) render.Policies {
|
||||
pp := make(render.Policies, 0, len(rules))
|
||||
for _, rule := range rules {
|
||||
for _, grp := range rule.APIGroups {
|
||||
for _, res := range rule.Resources {
|
||||
for _, na := range rule.ResourceNames {
|
||||
pp = pp.Upsert(render.NewPolicyRes(ns, binding, FQN(res, na), grp, rule.Verbs))
|
||||
}
|
||||
pp = pp.Upsert(render.NewPolicyRes(ns, binding, FQN(grp, res), grp, rule.Verbs))
|
||||
}
|
||||
}
|
||||
for _, nres := range rule.NonResourceURLs {
|
||||
if nres[0] != '/' {
|
||||
nres = "/" + nres
|
||||
}
|
||||
pp = pp.Upsert(render.NewPolicyRes(ns, binding, nres, "n/a", rule.Verbs))
|
||||
}
|
||||
}
|
||||
|
||||
return pp
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package model
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
@ -9,13 +9,18 @@ import (
|
|||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
var (
|
||||
_ Accessor = (*Subject)(nil)
|
||||
_ Nuker = (*Subject)(nil)
|
||||
)
|
||||
|
||||
// Subject represents a subject model.
|
||||
type Subject struct {
|
||||
Resource
|
||||
}
|
||||
|
||||
// List returns a collection of subjects.
|
||||
func (s *Subject) List(ctx context.Context) ([]runtime.Object, error) {
|
||||
func (s *Subject) List(ctx context.Context, ns string) ([]runtime.Object, error) {
|
||||
kind, ok := ctx.Value(internal.KeySubjectKind).(string)
|
||||
if !ok {
|
||||
return nil, errors.New("expecting a SubjectKind")
|
||||
|
|
@ -31,22 +36,30 @@ func (s *Subject) List(ctx context.Context) ([]runtime.Object, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return append(crbs, rbs...), nil
|
||||
for _, rb := range rbs {
|
||||
crbs = crbs.Upsert(rb)
|
||||
}
|
||||
|
||||
oo := make([]runtime.Object, len(crbs))
|
||||
for i, o := range crbs {
|
||||
oo[i] = o
|
||||
}
|
||||
return oo, nil
|
||||
}
|
||||
|
||||
func (s *Subject) listClusterRoleBindings(kind string) ([]runtime.Object, error) {
|
||||
crbs, err := fetchClusterRoleBindings(s.factory)
|
||||
func (s *Subject) listClusterRoleBindings(kind string) (render.Subjects, error) {
|
||||
crbs, err := fetchClusterRoleBindings(s.Factory)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
oo := make([]runtime.Object, 0, len(crbs))
|
||||
oo := make(render.Subjects, 0, len(crbs))
|
||||
for _, crb := range crbs {
|
||||
for _, su := range crb.Subjects {
|
||||
if su.Kind != kind || inSubjectRes(oo, su.Name) {
|
||||
if su.Kind != kind {
|
||||
continue
|
||||
}
|
||||
oo = append(oo, render.SubjectRef{
|
||||
oo = oo.Upsert(render.SubjectRes{
|
||||
Name: su.Name,
|
||||
Kind: "ClusterRoleBinding",
|
||||
FirstLocation: crb.Name,
|
||||
|
|
@ -57,19 +70,19 @@ func (s *Subject) listClusterRoleBindings(kind string) ([]runtime.Object, error)
|
|||
return oo, nil
|
||||
}
|
||||
|
||||
func (s *Subject) listRoleBindings(kind string) ([]runtime.Object, error) {
|
||||
rbs, err := fetchRoleBindings(s.factory)
|
||||
func (s *Subject) listRoleBindings(kind string) (render.Subjects, error) {
|
||||
rbs, err := fetchRoleBindings(s.Factory)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
oo := make([]runtime.Object, 0, len(rbs))
|
||||
oo := make(render.Subjects, 0, len(rbs))
|
||||
for _, rb := range rbs {
|
||||
for _, su := range rb.Subjects {
|
||||
if su.Kind != kind || inSubjectRes(oo, su.Name) {
|
||||
if su.Kind != kind {
|
||||
continue
|
||||
}
|
||||
oo = append(oo, render.SubjectRef{
|
||||
oo = oo.Upsert(render.SubjectRes{
|
||||
Name: su.Name,
|
||||
Kind: "RoleBinding",
|
||||
FirstLocation: rb.Name,
|
||||
|
|
@ -79,19 +92,3 @@ func (s *Subject) listRoleBindings(kind string) ([]runtime.Object, error) {
|
|||
|
||||
return oo, nil
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Helpers...
|
||||
|
||||
func inSubjectRes(oo []runtime.Object, match string) bool {
|
||||
for _, o := range oo {
|
||||
res, ok := o.(render.SubjectRef)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if res.Name == match {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
@ -12,12 +12,6 @@ import (
|
|||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// ResourceMetas represents a collection of resource metadata.
|
||||
type ResourceMetas map[client.GVR]metav1.APIResource
|
||||
|
||||
// Accessors represents a collection of dao accessors.
|
||||
type Accessors map[client.GVR]Accessor
|
||||
|
||||
var resMetas = ResourceMetas{}
|
||||
|
||||
// AccessorFor returns a client accessor for a resource if registered.
|
||||
|
|
@ -38,6 +32,7 @@ func AccessorFor(f Factory, gvr client.GVR) (Accessor, error) {
|
|||
client.NewGVR("apps/v1/statefulsets"): &StatefulSet{},
|
||||
client.NewGVR("batch/v1beta1/cronjobs"): &CronJob{},
|
||||
client.NewGVR("batch/v1/jobs"): &Job{},
|
||||
client.NewGVR("charts"): &Chart{},
|
||||
}
|
||||
|
||||
r, ok := m[gvr]
|
||||
|
|
@ -75,6 +70,17 @@ func MetaFor(gvr client.GVR) (metav1.APIResource, error) {
|
|||
return m, nil
|
||||
}
|
||||
|
||||
// IsK8sMeta checks for non resource meta.
|
||||
func IsK8sMeta(m metav1.APIResource) bool {
|
||||
for _, c := range m.Categories {
|
||||
if c == "k9s" || c == "helm" {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// IsK9sMeta checks for non resource meta.
|
||||
func IsK9sMeta(m metav1.APIResource) bool {
|
||||
for _, c := range m.Categories {
|
||||
|
|
@ -100,6 +106,12 @@ func LoadResources(f Factory) error {
|
|||
|
||||
// BOZO!! Need contermeasure for direct commands!
|
||||
func loadNonResource(m ResourceMetas) {
|
||||
loadK9s(m)
|
||||
loadRBAC(m)
|
||||
loadHelm(m)
|
||||
}
|
||||
|
||||
func loadK9s(m ResourceMetas) {
|
||||
m[client.NewGVR("aliases")] = metav1.APIResource{
|
||||
Name: "aliases",
|
||||
Kind: "Aliases",
|
||||
|
|
@ -138,8 +150,16 @@ func loadNonResource(m ResourceMetas) {
|
|||
Kind: "Containers",
|
||||
Categories: []string{"k9s"},
|
||||
}
|
||||
}
|
||||
|
||||
loadRBAC(m)
|
||||
func loadHelm(m ResourceMetas) {
|
||||
m[client.NewGVR("charts")] = metav1.APIResource{
|
||||
Name: "charts",
|
||||
Kind: "Charts",
|
||||
Namespaced: true,
|
||||
Verbs: []string{"delete"},
|
||||
Categories: []string{"helm"},
|
||||
}
|
||||
}
|
||||
|
||||
func loadRBAC(m ResourceMetas) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
var (
|
||||
_ Accessor = (*Resource)(nil)
|
||||
_ Describer = (*Resource)(nil)
|
||||
_ Nuker = (*Resource)(nil)
|
||||
)
|
||||
|
||||
// Resource represents an informer based resource.
|
||||
type Resource struct {
|
||||
Generic
|
||||
}
|
||||
|
||||
// ToYAML returns a resource yaml.
|
||||
func (r *Resource) ToYAML(path string) (string, error) {
|
||||
o, err := r.Get(context.Background(), path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
raw, err := ToYAML(o)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to marshal resource %s", err)
|
||||
}
|
||||
return raw, nil
|
||||
}
|
||||
|
||||
// Get returns a resource instance if found, else an error.
|
||||
func (r *Resource) Get(ctx context.Context, path string) (runtime.Object, error) {
|
||||
return r.Factory.Get(r.gvr.String(), path, true, labels.Everything())
|
||||
}
|
||||
|
||||
// List returns a collection of nodes.
|
||||
func (r *Resource) List(ctx context.Context, ns string) ([]runtime.Object, error) {
|
||||
strLabel, ok := ctx.Value(internal.KeyLabels).(string)
|
||||
lsel := labels.Everything()
|
||||
if sel, err := labels.ConvertSelectorToLabelsMap(strLabel); ok && err == nil {
|
||||
lsel = sel.AsSelector()
|
||||
}
|
||||
|
||||
return r.Factory.List(r.gvr.String(), ns, true, lsel)
|
||||
}
|
||||
|
|
@ -1,18 +1,47 @@
|
|||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
var (
|
||||
_ Accessor = (*ScreenDump)(nil)
|
||||
_ Nuker = (*ScreenDump)(nil)
|
||||
)
|
||||
|
||||
// ScreenDump represents a scraped resources.
|
||||
type ScreenDump struct {
|
||||
Generic
|
||||
NonResource
|
||||
}
|
||||
|
||||
var _ Accessor = (*ScreenDump)(nil)
|
||||
var _ Nuker = (*ScreenDump)(nil)
|
||||
|
||||
// Delete a ScreenDump.
|
||||
func (d *ScreenDump) Delete(path string, cascade, force bool) error {
|
||||
return os.Remove(path)
|
||||
}
|
||||
|
||||
// List returns a collection of screen dumps.
|
||||
func (c *ScreenDump) List(ctx context.Context, _ string) ([]runtime.Object, error) {
|
||||
dir, ok := ctx.Value(internal.KeyDir).(string)
|
||||
if !ok {
|
||||
return nil, errors.New("no screendump dir found in context")
|
||||
}
|
||||
|
||||
ff, err := ioutil.ReadDir(dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
oo := make([]runtime.Object, len(ff))
|
||||
for i, f := range ff {
|
||||
oo[i] = render.FileRes{File: f, Dir: dir}
|
||||
}
|
||||
|
||||
return oo, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,16 +15,19 @@ import (
|
|||
"k8s.io/kubectl/pkg/polymorphichelpers"
|
||||
)
|
||||
|
||||
var (
|
||||
_ Accessor = (*StatefulSet)(nil)
|
||||
_ Nuker = (*StatefulSet)(nil)
|
||||
_ Loggable = (*StatefulSet)(nil)
|
||||
_ Restartable = (*StatefulSet)(nil)
|
||||
_ Scalable = (*StatefulSet)(nil)
|
||||
)
|
||||
|
||||
// StatefulSet represents a K8s sts.
|
||||
type StatefulSet struct {
|
||||
Generic
|
||||
Resource
|
||||
}
|
||||
|
||||
var _ Accessor = (*StatefulSet)(nil)
|
||||
var _ Loggable = (*StatefulSet)(nil)
|
||||
var _ Restartable = (*StatefulSet)(nil)
|
||||
var _ Scalable = (*StatefulSet)(nil)
|
||||
|
||||
// Scale a StatefulSet.
|
||||
func (s *StatefulSet) Scale(path string, replicas int32) error {
|
||||
ns, n := client.Namespaced(path)
|
||||
|
|
@ -44,7 +47,7 @@ func (s *StatefulSet) Scale(path string, replicas int32) error {
|
|||
|
||||
// Restart a StatefulSet rollout.
|
||||
func (s *StatefulSet) Restart(path string) error {
|
||||
o, err := s.Get(s.gvr.String(), path, true, labels.Everything())
|
||||
o, err := s.Factory.Get(s.gvr.String(), path, true, labels.Everything())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -70,7 +73,7 @@ func (s *StatefulSet) Restart(path string) error {
|
|||
|
||||
// TailLogs tail logs for all pods represented by this StatefulSet.
|
||||
func (s *StatefulSet) TailLogs(ctx context.Context, c chan<- string, opts LogOptions) error {
|
||||
o, err := s.Get(s.gvr.String(), opts.Path, true, labels.Everything())
|
||||
o, err := s.Factory.Get(s.gvr.String(), opts.Path, true, labels.Everything())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,17 +11,19 @@ import (
|
|||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
var (
|
||||
_ Accessor = (*Service)(nil)
|
||||
_ Loggable = (*Service)(nil)
|
||||
)
|
||||
|
||||
// Service represents a k8s service.
|
||||
type Service struct {
|
||||
Generic
|
||||
Resource
|
||||
}
|
||||
|
||||
var _ Accessor = (*Service)(nil)
|
||||
var _ Loggable = (*Service)(nil)
|
||||
|
||||
// TailLogs tail logs for all pods represented by this Service.
|
||||
func (s *Service) TailLogs(ctx context.Context, c chan<- string, opts LogOptions) error {
|
||||
o, err := s.Get(s.gvr.String(), opts.Path, true, labels.Everything())
|
||||
o, err := s.Factory.Get(s.gvr.String(), opts.Path, true, labels.Everything())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"apiVersion": "rbac.authorization.k8s.io/v1",
|
||||
"kind": "ClusterRoleBinding",
|
||||
"metadata": {
|
||||
"annotations": {
|
||||
"kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"rbac.authorization.k8s.io/v1\",\"kind\":\"ClusterRoleBinding\",\"metadata\":{\"annotations\":{},\"name\":\"blee\"},\"roleRef\":{\"apiGroup\":\"rbac.authorization.k8s.io\",\"kind\":\"ClusterRole\",\"name\":\"blee\"},\"subjects\":[{\"apiGroup\":\"rbac.authorization.k8s.io\",\"kind\":\"User\",\"name\":\"fernand\"}]}\n"
|
||||
},
|
||||
"creationTimestamp": "2019-06-04T16:48:35Z",
|
||||
"name": "blee",
|
||||
"resourceVersion": "26689100",
|
||||
"selfLink": "/apis/rbac.authorization.k8s.io/v1/clusterrolebindings/blee",
|
||||
"uid": "97e5f84d-86e8-11e9-a8e8-42010a80015b"
|
||||
},
|
||||
"roleRef": {
|
||||
"apiGroup": "rbac.authorization.k8s.io",
|
||||
"kind": "ClusterRole",
|
||||
"name": "blee"
|
||||
},
|
||||
"subjects": [
|
||||
{
|
||||
"apiGroup": "rbac.authorization.k8s.io",
|
||||
"kind": "User",
|
||||
"name": "fernand"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -6,12 +6,19 @@ import (
|
|||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/watch"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/informers"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// ResourceMetas represents a collection of resource metadata.
|
||||
type ResourceMetas map[client.GVR]metav1.APIResource
|
||||
|
||||
// Accessors represents a collection of dao accessors.
|
||||
type Accessors map[client.GVR]Accessor
|
||||
|
||||
// Factory represents a resource factory.
|
||||
type Factory interface {
|
||||
// Client retrieves an api client.
|
||||
|
|
@ -39,12 +46,27 @@ type Factory interface {
|
|||
Forwarders() watch.Forwarders
|
||||
}
|
||||
|
||||
// Getter represents a resource getter.
|
||||
type Getter interface {
|
||||
// Get return a given resource.
|
||||
Get(ctx context.Context, path string) (runtime.Object, error)
|
||||
}
|
||||
|
||||
// Lister represents a resource lister.
|
||||
type Lister interface {
|
||||
// List returns a resource collection.
|
||||
List(ctx context.Context, ns string) ([]runtime.Object, error)
|
||||
}
|
||||
|
||||
// Accessor represents an accessible k8s resource.
|
||||
type Accessor interface {
|
||||
Nuker
|
||||
Lister
|
||||
Getter
|
||||
|
||||
// Init the resource with a factory object.
|
||||
Init(Factory, client.GVR)
|
||||
|
||||
GVR() string
|
||||
}
|
||||
|
||||
// Loggable represents resources with logs.
|
||||
|
|
@ -53,6 +75,15 @@ type Loggable interface {
|
|||
TailLogs(ctx context.Context, c chan<- string, opts LogOptions) error
|
||||
}
|
||||
|
||||
// Describer describes a resource.
|
||||
type Describer interface {
|
||||
// Describe describes a resource.
|
||||
Describe(path string) (string, error)
|
||||
|
||||
// ToYAML dumps a resource to YAML.
|
||||
ToYAML(path string) (string, error)
|
||||
}
|
||||
|
||||
// Scalable represents resources that can scale.
|
||||
type Scalable interface {
|
||||
// Scale scales a resource up or down.
|
||||
|
|
|
|||
|
|
@ -1,43 +0,0 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"sort"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/config"
|
||||
"github.com/derailed/k9s/internal/dao"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// Alias represents a collection of aliases.
|
||||
type Alias struct {
|
||||
Resource
|
||||
}
|
||||
|
||||
// List returns a collection of screen dumps.
|
||||
func (b *Alias) List(ctx context.Context) ([]runtime.Object, error) {
|
||||
a, ok := ctx.Value(internal.KeyAliases).(*dao.Alias)
|
||||
if !ok {
|
||||
return nil, errors.New("no aliases found in context")
|
||||
}
|
||||
|
||||
m := make(config.ShortNames, len(a.Alias))
|
||||
for alias, gvr := range a.Alias {
|
||||
if _, ok := m[gvr]; ok {
|
||||
m[gvr] = append(m[gvr], alias)
|
||||
} else {
|
||||
m[gvr] = []string{alias}
|
||||
}
|
||||
}
|
||||
|
||||
oo := make([]runtime.Object, 0, len(m))
|
||||
for gvr, aliases := range m {
|
||||
sort.StringSlice(aliases).Sort()
|
||||
oo = append(oo, render.AliasRes{GVR: gvr, Aliases: aliases})
|
||||
}
|
||||
|
||||
return oo, nil
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// Benchmark represents a collection of benchmarks.
|
||||
type Benchmark struct {
|
||||
Resource
|
||||
}
|
||||
|
||||
// List returns a collection of screen dumps.
|
||||
func (b *Benchmark) List(ctx context.Context) ([]runtime.Object, error) {
|
||||
dir, ok := ctx.Value(internal.KeyDir).(string)
|
||||
if !ok {
|
||||
return nil, errors.New("no benchmark dir found in context")
|
||||
}
|
||||
|
||||
ff, err := ioutil.ReadDir(dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
oo := make([]runtime.Object, len(ff))
|
||||
for i, f := range ff {
|
||||
oo[i] = render.BenchInfo{File: f, Path: filepath.Join(dir, f.Name())}
|
||||
}
|
||||
|
||||
return oo, nil
|
||||
}
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
package model_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/model"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestBenchmarkList(t *testing.T) {
|
||||
a := model.Benchmark{}
|
||||
a.Init(render.ClusterScope, "benchmarks", makeFactory())
|
||||
|
||||
ctx := context.WithValue(context.Background(), internal.KeyDir, "test_assets/bench")
|
||||
oo, err := a.List(ctx)
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 1, len(oo))
|
||||
assert.Equal(t, "test_assets/bench/default_fred_1577308050814961000.txt", oo[0].(render.BenchInfo).Path)
|
||||
}
|
||||
|
||||
func TestBenchmarkHydrate(t *testing.T) {
|
||||
a := model.Benchmark{}
|
||||
a.Init(render.ClusterScope, "benchmarks", makeFactory())
|
||||
|
||||
ctx := context.WithValue(context.Background(), internal.KeyDir, "test_assets/bench")
|
||||
oo, err := a.List(ctx)
|
||||
assert.Nil(t, err)
|
||||
|
||||
rr := make(render.Rows, len(oo))
|
||||
assert.Nil(t, a.Hydrate(oo, rr, render.Benchmark{}))
|
||||
assert.Equal(t, 1, len(rr))
|
||||
assert.Equal(t, "test_assets/bench/default_fred_1577308050814961000.txt", rr[0].ID)
|
||||
assert.Equal(t, render.Fields{
|
||||
"default",
|
||||
"fred",
|
||||
"fail",
|
||||
"816.6403",
|
||||
"0.0122",
|
||||
"0",
|
||||
"0",
|
||||
"default_fred_1577308050814961000.txt",
|
||||
},
|
||||
rr[0].Fields[:len(rr[0].Fields)-1],
|
||||
)
|
||||
}
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/rs/zerolog/log"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
mv1beta1 "k8s.io/metrics/pkg/apis/metrics/v1beta1"
|
||||
)
|
||||
|
||||
// Container represents a container model.
|
||||
type Container struct {
|
||||
Resource
|
||||
|
||||
pod *v1.Pod
|
||||
}
|
||||
|
||||
// List returns a collection of containers
|
||||
func (c *Container) List(ctx context.Context) ([]runtime.Object, error) {
|
||||
c.pod = nil
|
||||
path, ok := ctx.Value(internal.KeyPath).(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no context path for %q", c.gvr)
|
||||
}
|
||||
ns, _ := render.Namespaced(path)
|
||||
c.namespace = ns
|
||||
o, err := c.factory.Get("v1/pods", path, true, labels.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var po v1.Pod
|
||||
err = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &po)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.pod = &po
|
||||
res := make([]runtime.Object, 0, len(po.Spec.InitContainers)+len(po.Spec.Containers))
|
||||
mx := client.NewMetricsServer(c.factory.Client())
|
||||
var pmx *mv1beta1.PodMetrics
|
||||
if c.factory.Client() != nil {
|
||||
var err error
|
||||
pmx, err = mx.FetchPodMetrics(c.namespace, c.pod.Name)
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msgf("No metrics found for pod %q:%q", c.namespace, c.pod.Name)
|
||||
}
|
||||
}
|
||||
|
||||
for _, co := range po.Spec.InitContainers {
|
||||
res = append(res, makeContainerRes(co, po, pmx, true))
|
||||
}
|
||||
for _, co := range po.Spec.Containers {
|
||||
res = append(res, makeContainerRes(co, po, pmx, false))
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Helpers...
|
||||
|
||||
func makeContainerRes(co v1.Container, po v1.Pod, pmx *mv1beta1.PodMetrics, isInit bool) render.ContainerRes {
|
||||
cmx, err := containerMetrics(co.Name, pmx)
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msgf("Container metrics for %s", co.Name)
|
||||
}
|
||||
|
||||
return render.ContainerRes{
|
||||
Container: co,
|
||||
Status: getContainerStatus(co.Name, po.Status),
|
||||
Metrics: cmx,
|
||||
IsInit: isInit,
|
||||
Age: po.ObjectMeta.CreationTimestamp,
|
||||
}
|
||||
}
|
||||
|
||||
func containerMetrics(n string, mx runtime.Object) (*mv1beta1.ContainerMetrics, error) {
|
||||
pmx, ok := mx.(*mv1beta1.PodMetrics)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expecting podmetrics but got `%T", mx)
|
||||
}
|
||||
if pmx == nil {
|
||||
return nil, fmt.Errorf("no metrics for container %s", n)
|
||||
}
|
||||
for _, m := range pmx.Containers {
|
||||
if m.Name == n {
|
||||
return &m, nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func getContainerStatus(co string, status v1.PodStatus) *v1.ContainerStatus {
|
||||
for _, c := range status.ContainerStatuses {
|
||||
if c.Name == co {
|
||||
return &c
|
||||
}
|
||||
}
|
||||
|
||||
for _, c := range status.InitContainerStatuses {
|
||||
if c.Name == co {
|
||||
return &c
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// Context represents a kube context model.
|
||||
type Context struct {
|
||||
Resource
|
||||
}
|
||||
|
||||
// List returns a collection of node resources.
|
||||
func (c *Context) List(_ context.Context) ([]runtime.Object, error) {
|
||||
cfg := c.factory.Client().Config()
|
||||
ctxs, err := cfg.Contexts()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cc := make([]runtime.Object, 0, len(ctxs))
|
||||
for name, ctx := range ctxs {
|
||||
cc = append(cc, render.NewNamedContext(cfg, name, ctx))
|
||||
}
|
||||
|
||||
return cc, nil
|
||||
}
|
||||
|
|
@ -1,150 +0,0 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/rs/zerolog/log"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
const gvFmt = "application/json;as=Table;v=%s;g=%s, application/json"
|
||||
|
||||
// Generic represents a generic model.
|
||||
type Generic struct {
|
||||
Resource
|
||||
|
||||
table *metav1beta1.Table
|
||||
}
|
||||
|
||||
// List returns a collection of node resources.
|
||||
func (g *Generic) Get(ctx context.Context, path string) (runtime.Object, error) {
|
||||
var opts metav1.GetOptions
|
||||
|
||||
ns, n := client.Namespaced(path)
|
||||
gvr := client.NewGVR(g.gvr)
|
||||
req := g.factory.Client().DynDialOrDie().Resource(gvr.AsGVR())
|
||||
if ns == "" {
|
||||
return req.Get(n, opts)
|
||||
}
|
||||
|
||||
return req.Namespace(ns).Get(n, opts)
|
||||
}
|
||||
|
||||
// List returns a collection of node resources.
|
||||
func (g *Generic) List(ctx context.Context) ([]runtime.Object, error) {
|
||||
// Ensures the factory is tracking this resource
|
||||
_, err := g.factory.CanForResource(g.namespace, g.gvr, []string{"list"})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gvr := client.NewGVR(g.gvr)
|
||||
fcodec, codec := g.codec(gvr.AsGV())
|
||||
|
||||
c, err := g.client(fcodec, gvr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ns := g.namespace
|
||||
if g.namespace == render.ClusterScope {
|
||||
ns = render.AllNamespaces
|
||||
}
|
||||
|
||||
log.Debug().Msgf("GENERIC LIST %q:%q", g.namespace, g.gvr)
|
||||
o, err := c.Get().
|
||||
SetHeader("Accept", fmt.Sprintf(gvFmt, metav1beta1.SchemeGroupVersion.Version, metav1beta1.GroupName)).
|
||||
Resource(gvr.ToR()).
|
||||
VersionedParams(&metav1beta1.TableOptions{}, codec).
|
||||
Namespace(ns).
|
||||
Do().
|
||||
Get()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
table, ok := o.(*metav1beta1.Table)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expecting table but got %T", o)
|
||||
}
|
||||
g.table = table
|
||||
res := make([]runtime.Object, len(g.table.Rows))
|
||||
for i := range g.table.Rows {
|
||||
res[i] = RowRes{&g.table.Rows[i]}
|
||||
}
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
// Hydrate returns nodes as rows.
|
||||
func (g *Generic) Hydrate(oo []runtime.Object, rr render.Rows, re Renderer) error {
|
||||
gr, ok := re.(*render.Generic)
|
||||
if !ok {
|
||||
return fmt.Errorf("expecting generic renderer for %s but got %T", g.gvr, re)
|
||||
}
|
||||
gr.SetTable(g.table)
|
||||
for i, o := range oo {
|
||||
res, ok := o.(RowRes)
|
||||
if !ok {
|
||||
return fmt.Errorf("expecting RowRes but got %#v", o)
|
||||
}
|
||||
if err := gr.Render(res.TableRow, g.namespace, &rr[i]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Helpers...
|
||||
|
||||
func (g *Generic) client(codec serializer.CodecFactory, gvr client.GVR) (*rest.RESTClient, error) {
|
||||
crConfig := g.factory.Client().RestConfigOrDie()
|
||||
gv := gvr.AsGV()
|
||||
crConfig.GroupVersion = &gv
|
||||
crConfig.APIPath = "/apis"
|
||||
if len(gvr.ToG()) == 0 {
|
||||
crConfig.APIPath = "/api"
|
||||
}
|
||||
crConfig.NegotiatedSerializer = codec.WithoutConversion()
|
||||
|
||||
crRestClient, err := rest.RESTClientFor(crConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return crRestClient, nil
|
||||
}
|
||||
|
||||
func (r *Resource) codec(gv schema.GroupVersion) (serializer.CodecFactory, runtime.ParameterCodec) {
|
||||
scheme := runtime.NewScheme()
|
||||
metav1.AddToGroupVersion(scheme, gv)
|
||||
scheme.AddKnownTypes(gv, &metav1beta1.Table{}, &metav1beta1.TableOptions{})
|
||||
scheme.AddKnownTypes(metav1beta1.SchemeGroupVersion, &metav1beta1.Table{}, &metav1beta1.TableOptions{})
|
||||
|
||||
return serializer.NewCodecFactory(scheme), runtime.NewParameterCodec(scheme)
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// RowRes represents a table row.
|
||||
type RowRes struct {
|
||||
*metav1beta1.TableRow
|
||||
}
|
||||
|
||||
// GetObjectKind returns a schema object.
|
||||
func (r RowRes) GetObjectKind() schema.ObjectKind {
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyObject returns a container copy.
|
||||
func (r RowRes) DeepCopyObject() runtime.Object {
|
||||
return r
|
||||
}
|
||||
|
|
@ -1,42 +1,11 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/derailed/tview"
|
||||
runewidth "github.com/mattn/go-runewidth"
|
||||
"github.com/rs/zerolog/log"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
func extractFQN(o runtime.Object) string {
|
||||
u, ok := o.(*unstructured.Unstructured)
|
||||
if !ok {
|
||||
log.Error().Err(fmt.Errorf("expecting unstructured but got %T", o))
|
||||
return "na"
|
||||
}
|
||||
m, ok := u.Object["metadata"].(map[string]interface{})
|
||||
if !ok {
|
||||
log.Error().Err(fmt.Errorf("expecting interface map for metadata but got %T", u.Object["metadata"]))
|
||||
return "na"
|
||||
}
|
||||
|
||||
n, ok := m["name"].(string)
|
||||
if !ok {
|
||||
log.Error().Err(fmt.Errorf("expecting interface map for name but got %T", m["name"]))
|
||||
return "na"
|
||||
}
|
||||
|
||||
ns, ok := m["namespace"].(string)
|
||||
if !ok {
|
||||
return FQN("", n)
|
||||
}
|
||||
|
||||
return FQN(ns, n)
|
||||
}
|
||||
|
||||
// MetaFQN returns a fully qualified resource name.
|
||||
func MetaFQN(m metav1.ObjectMeta) string {
|
||||
if m.Namespace == "" {
|
||||
|
|
|
|||
|
|
@ -1,69 +0,0 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/rs/zerolog/log"
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// Job represents a collections of jobs.
|
||||
type Job struct {
|
||||
Resource
|
||||
}
|
||||
|
||||
// List returns a collection of screen dumps.
|
||||
func (c *Job) List(ctx context.Context) ([]runtime.Object, error) {
|
||||
uid, ok := ctx.Value(internal.KeyUID).(string)
|
||||
if !ok {
|
||||
log.Debug().Msgf("NO UID in context")
|
||||
}
|
||||
path, ok := ctx.Value(internal.KeyPath).(string)
|
||||
if !ok {
|
||||
return nil, errors.New("no cronjob path found in context")
|
||||
}
|
||||
|
||||
log.Debug().Msgf("Listing jobs %q %q--%q", c.gvr, uid, path)
|
||||
oo, err := c.Resource.List(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if uid == "" {
|
||||
return oo, nil
|
||||
}
|
||||
|
||||
_, cronName := client.Namespaced(path)
|
||||
jj := make([]runtime.Object, 0, len(oo))
|
||||
for _, j := range oo {
|
||||
var job batchv1.Job
|
||||
err = runtime.DefaultUnstructuredConverter.FromUnstructured(j.(*unstructured.Unstructured).Object, &job)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Debug().Msgf("Looking at job %q -- %q", job.Name, cronName)
|
||||
if !isNamedAfter(cronName, job.Name) {
|
||||
continue
|
||||
}
|
||||
log.Debug().Msgf("GOT Job %s -- %#v -- %q -- %q", job.Name, job.Labels, uid, path)
|
||||
jj = append(jj, j)
|
||||
}
|
||||
|
||||
return jj, nil
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Helpers...
|
||||
|
||||
func isNamedAfter(p, n string) bool {
|
||||
tokens := strings.Split(n, "-")
|
||||
if len(tokens) == 0 || tokens[0] != p {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
package model_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/derailed/k9s/internal/model"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
func TestNodeHydrate(t *testing.T) {
|
||||
f := makeFactory()
|
||||
var no model.Node
|
||||
no.Init("", "v1/nodes", f)
|
||||
|
||||
o := render.NodeWithMetrics{Raw: load(t, "n1")}
|
||||
rr := make(render.Rows, 1)
|
||||
assert.Nil(t, no.Hydrate([]runtime.Object{&o}, rr, render.Node{}))
|
||||
assert.Equal(t, 1, len(rr))
|
||||
assert.Equal(t, "minikube", rr[0].ID)
|
||||
assert.Equal(t, render.Fields{
|
||||
"minikube",
|
||||
"Ready",
|
||||
"master",
|
||||
"v1.17.0",
|
||||
"4.19.81",
|
||||
"192.168.64.6",
|
||||
"<none>",
|
||||
"n/a",
|
||||
"n/a",
|
||||
"n/a",
|
||||
"n/a",
|
||||
"n/a",
|
||||
"n/a",
|
||||
}, rr[0].Fields[:len(rr[0].Fields)-1])
|
||||
}
|
||||
|
||||
func BenchmarkNodeHydrate(b *testing.B) {
|
||||
f := makeFactory()
|
||||
var no model.Node
|
||||
no.Init("", "v1/nodes", f)
|
||||
o := load(b, "n1")
|
||||
rr := make(render.Rows, 1)
|
||||
|
||||
oo := []runtime.Object{&render.NodeWithMetrics{Raw: o}}
|
||||
re := render.Node{}
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
no.Hydrate(oo, rr, re)
|
||||
}
|
||||
}
|
||||
|
||||
// Helpers...
|
||||
|
||||
func load(t assert.TestingT, n string) *unstructured.Unstructured {
|
||||
raw, err := ioutil.ReadFile(fmt.Sprintf("test_assets/%s.json", n))
|
||||
assert.Nil(t, err)
|
||||
|
||||
var o unstructured.Unstructured
|
||||
err = json.Unmarshal(raw, &o)
|
||||
assert.Nil(t, err)
|
||||
|
||||
return &o
|
||||
}
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/rs/zerolog/log"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
mv1beta1 "k8s.io/metrics/pkg/apis/metrics/v1beta1"
|
||||
)
|
||||
|
||||
// Pod represents a pod model.
|
||||
type Pod struct {
|
||||
Resource
|
||||
}
|
||||
|
||||
// List returns a collection of nodes.
|
||||
func (p *Pod) List(ctx context.Context) ([]runtime.Object, error) {
|
||||
oo, err := p.Resource.List(ctx)
|
||||
if err != nil {
|
||||
return oo, err
|
||||
}
|
||||
|
||||
pmx, ok := ctx.Value(internal.KeyMetrics).(*mv1beta1.PodMetricsList)
|
||||
if !ok {
|
||||
log.Warn().Msgf("expecting context PodMetricsList")
|
||||
}
|
||||
|
||||
sel, ok := ctx.Value(internal.KeyFields).(string)
|
||||
if !ok {
|
||||
return oo, nil
|
||||
}
|
||||
fsel, err := labels.ConvertSelectorToLabelsMap(sel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nodeName := fsel["spec.nodeName"]
|
||||
|
||||
var res []runtime.Object
|
||||
for _, o := range oo {
|
||||
u, ok := o.(*unstructured.Unstructured)
|
||||
if !ok {
|
||||
return res, fmt.Errorf("expecting *unstructured.Unstructured but got `%T", o)
|
||||
}
|
||||
if nodeName == "" {
|
||||
res = append(res, &render.PodWithMetrics{Raw: u, MX: podMetricsFor(o, pmx)})
|
||||
continue
|
||||
}
|
||||
|
||||
spec, ok := u.Object["spec"].(map[string]interface{})
|
||||
if !ok {
|
||||
return res, fmt.Errorf("expecting interface map but got `%T", o)
|
||||
}
|
||||
if spec["nodeName"] == nodeName {
|
||||
res = append(res, &render.PodWithMetrics{Raw: u, MX: podMetricsFor(o, pmx)})
|
||||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Hydrate returns pod resources as rows.
|
||||
func (p *Pod) Hydrate(oo []runtime.Object, rr render.Rows, re Renderer) error {
|
||||
var index int
|
||||
for _, o := range oo {
|
||||
po, ok := o.(*render.PodWithMetrics)
|
||||
if !ok {
|
||||
return fmt.Errorf("expecting *PodWithMetric but got %T", po)
|
||||
}
|
||||
var row render.Row
|
||||
if err := re.Render(po, p.namespace, &row); err != nil {
|
||||
return err
|
||||
}
|
||||
rr[index] = row
|
||||
index++
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Helpers...
|
||||
|
||||
func podMetricsFor(o runtime.Object, mmx *mv1beta1.PodMetricsList) *mv1beta1.PodMetrics {
|
||||
fqn := extractFQN(o)
|
||||
for _, mx := range mmx.Items {
|
||||
if MetaFQN(mx.ObjectMeta) == fqn {
|
||||
return &mx
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
package model_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/derailed/k9s/internal/model"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
func TestPodHydrate(t *testing.T) {
|
||||
f := makeFactory()
|
||||
var po model.Pod
|
||||
po.Init("", "v1/pods", f)
|
||||
|
||||
o := render.PodWithMetrics{Raw: load(t, "p1")}
|
||||
rr := make(render.Rows, 1)
|
||||
assert.Nil(t, po.Hydrate([]runtime.Object{&o}, rr, render.Pod{}))
|
||||
assert.Equal(t, 1, len(rr))
|
||||
assert.Equal(t, "default/nginx-7fb78fb6d8-2w75j", rr[0].ID)
|
||||
assert.Equal(t, render.Fields{
|
||||
"default",
|
||||
"nginx-7fb78fb6d8-2w75j",
|
||||
"1/1",
|
||||
"Running",
|
||||
"0",
|
||||
"n/a",
|
||||
"n/a",
|
||||
"n/a",
|
||||
"n/a",
|
||||
"10.44.0.229",
|
||||
"gke-k9s-default-pool-0fa2fb89-lbtf",
|
||||
"GA",
|
||||
}, rr[0].Fields[:len(rr[0].Fields)-1])
|
||||
}
|
||||
|
||||
func BenchmarkPodHydrate(b *testing.B) {
|
||||
f := makeFactory()
|
||||
var po model.Pod
|
||||
po.Init("", "v1/pods", f)
|
||||
o := load(b, "p1")
|
||||
rr := make(render.Rows, 1)
|
||||
|
||||
oo := []runtime.Object{&render.PodWithMetrics{Raw: o}}
|
||||
re := render.Pod{}
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
po.Hydrate(oo, rr, re)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"github.com/derailed/k9s/internal/dao"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
)
|
||||
|
||||
|
|
@ -8,44 +9,48 @@ import (
|
|||
// BOZO!! Break up deps and merge into single registrar
|
||||
var Registry = map[string]ResourceMeta{
|
||||
// Custom...
|
||||
"charts": {
|
||||
DAO: &dao.Chart{},
|
||||
Renderer: &render.Chart{},
|
||||
},
|
||||
"containers": {
|
||||
Model: &Container{},
|
||||
DAO: &dao.Container{},
|
||||
Renderer: &render.Container{},
|
||||
},
|
||||
"contexts": {
|
||||
Model: &Context{},
|
||||
DAO: &dao.Context{},
|
||||
Renderer: &render.Context{},
|
||||
},
|
||||
"screendumps": {
|
||||
Model: &ScreenDump{},
|
||||
DAO: &dao.ScreenDump{},
|
||||
Renderer: &render.ScreenDump{},
|
||||
},
|
||||
"rbac": {
|
||||
Model: &Rbac{},
|
||||
DAO: &dao.Rbac{},
|
||||
Renderer: &render.Rbac{},
|
||||
},
|
||||
"policy": {
|
||||
Model: &Policy{},
|
||||
DAO: &dao.Policy{},
|
||||
Renderer: &render.Policy{},
|
||||
},
|
||||
"users": {
|
||||
Model: &Subject{},
|
||||
DAO: &dao.Subject{},
|
||||
Renderer: &render.Subject{},
|
||||
},
|
||||
"groups": {
|
||||
Model: &Subject{},
|
||||
DAO: &dao.Subject{},
|
||||
Renderer: &render.Subject{},
|
||||
},
|
||||
"portforwards": {
|
||||
Model: &PortForward{},
|
||||
DAO: &dao.PortForward{},
|
||||
Renderer: &render.PortForward{},
|
||||
},
|
||||
"benchmarks": {
|
||||
Model: &Benchmark{},
|
||||
DAO: &dao.Benchmark{},
|
||||
Renderer: &render.Benchmark{},
|
||||
},
|
||||
"aliases": {
|
||||
Model: &Alias{},
|
||||
DAO: &dao.Alias{},
|
||||
Renderer: &render.Alias{},
|
||||
},
|
||||
|
||||
|
|
@ -57,14 +62,14 @@ var Registry = map[string]ResourceMeta{
|
|||
Renderer: &render.Event{},
|
||||
},
|
||||
"v1/pods": {
|
||||
Model: &Pod{},
|
||||
DAO: &dao.Pod{},
|
||||
Renderer: &render.Pod{},
|
||||
},
|
||||
"v1/namespaces": {
|
||||
Renderer: &render.Namespace{},
|
||||
},
|
||||
"v1/nodes": {
|
||||
Model: &Node{},
|
||||
DAO: &dao.Node{},
|
||||
Renderer: &render.Node{},
|
||||
},
|
||||
"v1/services": {
|
||||
|
|
@ -73,6 +78,12 @@ var Registry = map[string]ResourceMeta{
|
|||
"v1/serviceaccounts": {
|
||||
Renderer: &render.ServiceAccount{},
|
||||
},
|
||||
"v1/persistentvolumes": {
|
||||
Renderer: &render.PersistentVolume{},
|
||||
},
|
||||
"v1/persistentvolumeclaims": {
|
||||
Renderer: &render.PersistentVolumeClaim{},
|
||||
},
|
||||
|
||||
// Apps...
|
||||
"apps/v1/deployments": {
|
||||
|
|
@ -98,37 +109,40 @@ var Registry = map[string]ResourceMeta{
|
|||
"extensions/v1beta1/networkpolicies": {
|
||||
Renderer: &render.NetworkPolicy{},
|
||||
},
|
||||
"networking.k8s.io/v1/networkpolicies": {
|
||||
Renderer: &render.NetworkPolicy{},
|
||||
},
|
||||
|
||||
// Batch...
|
||||
"batch/v1beta1/cronjobs": {
|
||||
Renderer: &render.CronJob{},
|
||||
},
|
||||
"batch/v1/jobs": {
|
||||
Model: &Job{},
|
||||
DAO: &dao.Job{},
|
||||
Renderer: &render.Job{},
|
||||
},
|
||||
|
||||
// Autoscaling...
|
||||
"autoscaling/v1/horizontalpodautoscalers": {
|
||||
Model: &HorizontalPodAutoscaler{},
|
||||
DAO: &dao.HorizontalPodAutoscaler{},
|
||||
Renderer: &render.HorizontalPodAutoscaler{},
|
||||
},
|
||||
"autoscaling/v2beta1/horizontalpodautoscalers": {
|
||||
Model: &HorizontalPodAutoscaler{},
|
||||
DAO: &dao.HorizontalPodAutoscaler{},
|
||||
Renderer: &render.HorizontalPodAutoscaler{},
|
||||
},
|
||||
"autoscaling/v2beta2/horizontalpodautoscalers": {
|
||||
Model: &HorizontalPodAutoscaler{},
|
||||
DAO: &dao.HorizontalPodAutoscaler{},
|
||||
Renderer: &render.HorizontalPodAutoscaler{},
|
||||
},
|
||||
|
||||
// CRDs...
|
||||
"apiextensions.k8s.io/v1/customresourcedefinitions": {
|
||||
Model: &CustomResourceDefinition{},
|
||||
DAO: &dao.CustomResourceDefinition{},
|
||||
Renderer: &render.CustomResourceDefinition{},
|
||||
},
|
||||
"apiextensions.k8s.io/v1beta1/customresourcedefinitions": {
|
||||
Model: &CustomResourceDefinition{},
|
||||
DAO: &dao.CustomResourceDefinition{},
|
||||
Renderer: &render.CustomResourceDefinition{},
|
||||
},
|
||||
|
||||
|
|
@ -144,7 +158,7 @@ var Registry = map[string]ResourceMeta{
|
|||
|
||||
// RBAC...
|
||||
"rbac.authorization.k8s.io/v1/clusterroles": {
|
||||
Model: &Rbac{},
|
||||
DAO: &dao.Rbac{},
|
||||
Renderer: &render.ClusterRole{},
|
||||
},
|
||||
"rbac.authorization.k8s.io/v1/clusterrolebindings": {
|
||||
|
|
|
|||
|
|
@ -1,49 +0,0 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/dao"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// Resource represents a generic resource model.
|
||||
type Resource struct {
|
||||
namespace, gvr string
|
||||
factory dao.Factory
|
||||
}
|
||||
|
||||
// Init initializes the model.
|
||||
func (r *Resource) Init(ns, gvr string, f dao.Factory) {
|
||||
r.namespace, r.gvr, r.factory = ns, gvr, f
|
||||
}
|
||||
|
||||
// Get returns a resource instance if found, else an error.
|
||||
func (r *Resource) Get(ctx context.Context, path string) (runtime.Object, error) {
|
||||
return r.factory.Get(r.gvr, path, true, labels.Everything())
|
||||
}
|
||||
|
||||
// List returns a collection of nodes.
|
||||
func (r *Resource) List(ctx context.Context) ([]runtime.Object, error) {
|
||||
strLabel, ok := ctx.Value(internal.KeyLabels).(string)
|
||||
lsel := labels.Everything()
|
||||
if sel, err := labels.ConvertSelectorToLabelsMap(strLabel); ok && err == nil {
|
||||
lsel = sel.AsSelector()
|
||||
}
|
||||
|
||||
return r.factory.List(r.gvr, r.namespace, true, lsel)
|
||||
}
|
||||
|
||||
// Hydrate renders all rows.
|
||||
func (r *Resource) Hydrate(oo []runtime.Object, rr render.Rows, re Renderer) error {
|
||||
for i, o := range oo {
|
||||
if err := re.Render(o, r.namespace, &rr[i]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// ScreenDump represents a collections of screendumps.
|
||||
type ScreenDump struct {
|
||||
Resource
|
||||
}
|
||||
|
||||
// List returns a collection of screen dumps.
|
||||
func (c *ScreenDump) List(ctx context.Context) ([]runtime.Object, error) {
|
||||
dir, ok := ctx.Value(internal.KeyDir).(string)
|
||||
if !ok {
|
||||
return nil, errors.New("no screendump dir found in context")
|
||||
}
|
||||
|
||||
ff, err := ioutil.ReadDir(dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
oo := make([]runtime.Object, len(ff))
|
||||
for i, f := range ff {
|
||||
oo[i] = render.FileRes{File: f, Dir: dir}
|
||||
}
|
||||
|
||||
return oo, nil
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/dao"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
|
@ -41,6 +42,26 @@ func NewTable(gvr string) *Table {
|
|||
}
|
||||
}
|
||||
|
||||
// AddListener adds a new model listener.
|
||||
func (t *Table) AddListener(l TableListener) {
|
||||
t.listeners = append(t.listeners, l)
|
||||
}
|
||||
|
||||
// RemoveListener delete a listener from the list.
|
||||
func (t *Table) RemoveListener(l TableListener) {
|
||||
victim := -1
|
||||
for i, lis := range t.listeners {
|
||||
if lis == l {
|
||||
victim = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if victim >= 0 {
|
||||
t.listeners = append(t.listeners[:victim], t.listeners[victim+1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
// Watch initiates model updates.
|
||||
func (t *Table) Watch(ctx context.Context) {
|
||||
t.Refresh(ctx)
|
||||
|
|
@ -49,14 +70,57 @@ func (t *Table) Watch(ctx context.Context) {
|
|||
|
||||
// Get returns a resource instance if found, else an error.
|
||||
func (t *Table) Get(ctx context.Context, path string) (runtime.Object, error) {
|
||||
meta := t.resourceMeta()
|
||||
factory, ok := ctx.Value(internal.KeyFactory).(dao.Factory)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected Factory in context but got %T", ctx.Value(internal.KeyFactory))
|
||||
meta, err := t.getMeta(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
meta.Model.Init(t.namespace, t.gvr, factory)
|
||||
|
||||
return meta.Model.Get(ctx, path)
|
||||
return meta.DAO.Get(ctx, path)
|
||||
}
|
||||
|
||||
func (t *Table) Delete(ctx context.Context, path string, cascade, force bool) error {
|
||||
log.Debug().Msgf("TABLE DELETE %q", path)
|
||||
meta, err := t.getMeta(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nuker, ok := meta.DAO.(dao.Nuker)
|
||||
if !ok {
|
||||
return fmt.Errorf("no nuker for %q", meta.DAO.GVR())
|
||||
}
|
||||
|
||||
return nuker.Delete(path, cascade, force)
|
||||
}
|
||||
|
||||
// Describe describes a given resource.
|
||||
func (t *Table) Describe(ctx context.Context, path string) (string, error) {
|
||||
meta, err := t.getMeta(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
desc, ok := meta.DAO.(dao.Describer)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("no describer for %q", meta.DAO.GVR())
|
||||
}
|
||||
|
||||
return desc.Describe(path)
|
||||
}
|
||||
|
||||
// ToYAML returns a resource yaml.
|
||||
func (t *Table) ToYAML(ctx context.Context, path string) (string, error) {
|
||||
meta, err := t.getMeta(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
desc, ok := meta.DAO.(dao.Describer)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("no describer for %q", meta.DAO.GVR())
|
||||
}
|
||||
|
||||
return desc.ToYAML(path)
|
||||
}
|
||||
|
||||
// Refresh update the model now.
|
||||
|
|
@ -82,7 +146,7 @@ func (t *Table) SetRefreshRate(d time.Duration) {
|
|||
|
||||
// ClusterWide checks if resource is scope for all namespaces.
|
||||
func (t *Table) ClusterWide() bool {
|
||||
return t.namespace == render.AllNamespaces
|
||||
return client.IsClusterWide(t.namespace)
|
||||
}
|
||||
|
||||
// InNamespace checks if current namespace matches desired namespace.
|
||||
|
|
@ -113,7 +177,6 @@ func (t *Table) updater(ctx context.Context) {
|
|||
}
|
||||
|
||||
func (t *Table) refresh(ctx context.Context) {
|
||||
log.Debug().Msgf("RECONCILING")
|
||||
if !atomic.CompareAndSwapInt32(&t.inUpdate, 0, 1) {
|
||||
log.Debug().Msgf("Dropping update...")
|
||||
return
|
||||
|
|
@ -128,62 +191,14 @@ func (t *Table) refresh(ctx context.Context) {
|
|||
t.fireTableChanged(*t.data)
|
||||
}
|
||||
|
||||
// AddListener adds a new model listener.
|
||||
func (t *Table) AddListener(l TableListener) {
|
||||
t.listeners = append(t.listeners, l)
|
||||
}
|
||||
|
||||
// RemoveListener delete a listener from the list.
|
||||
func (t *Table) RemoveListener(l TableListener) {
|
||||
victim := -1
|
||||
for i, lis := range t.listeners {
|
||||
if lis == l {
|
||||
victim = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if victim >= 0 {
|
||||
t.listeners = append(t.listeners[:victim], t.listeners[victim+1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Table) fireTableChanged(data render.TableData) {
|
||||
for _, l := range t.listeners {
|
||||
l.TableDataChanged(data)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Table) fireTableLoadFailed(err error) {
|
||||
for _, l := range t.listeners {
|
||||
l.TableLoadFailed(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Table) list(ctx context.Context, l Lister) ([]runtime.Object, error) {
|
||||
func (t *Table) list(ctx context.Context, a dao.Accessor) ([]runtime.Object, error) {
|
||||
factory, ok := ctx.Value(internal.KeyFactory).(dao.Factory)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected Factory in context but got %T", ctx.Value(internal.KeyFactory))
|
||||
}
|
||||
l.Init(t.namespace, t.gvr, factory)
|
||||
a.Init(factory, client.NewGVR(t.gvr))
|
||||
|
||||
return l.List(ctx)
|
||||
}
|
||||
|
||||
func (t *Table) resourceMeta() ResourceMeta {
|
||||
meta, ok := Registry[t.gvr]
|
||||
if !ok {
|
||||
log.Debug().Msgf("Resource %s not found in registry. Going generic!", t.gvr)
|
||||
meta = ResourceMeta{
|
||||
Model: &Generic{},
|
||||
Renderer: &render.Generic{},
|
||||
}
|
||||
}
|
||||
if meta.Model == nil {
|
||||
meta.Model = &Resource{}
|
||||
}
|
||||
|
||||
return meta
|
||||
return a.List(ctx, t.namespace)
|
||||
}
|
||||
|
||||
func (t *Table) reconcile(ctx context.Context) error {
|
||||
|
|
@ -192,14 +207,14 @@ func (t *Table) reconcile(ctx context.Context) error {
|
|||
}(time.Now())
|
||||
|
||||
meta := t.resourceMeta()
|
||||
oo, err := t.list(ctx, meta.Model)
|
||||
oo, err := t.list(ctx, meta.DAO)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Debug().Msgf("LIST returned %d rows", len(oo))
|
||||
|
||||
rows := make(render.Rows, len(oo))
|
||||
if err := meta.Model.Hydrate(oo, rows, meta.Renderer); err != nil {
|
||||
if err := hydrate(t.namespace, oo, rows, meta.Renderer); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -216,3 +231,54 @@ func (t *Table) reconcile(ctx context.Context) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Table) getMeta(ctx context.Context) (ResourceMeta, error) {
|
||||
meta := t.resourceMeta()
|
||||
factory, ok := ctx.Value(internal.KeyFactory).(dao.Factory)
|
||||
if !ok {
|
||||
return ResourceMeta{}, fmt.Errorf("expected Factory in context but got %T", ctx.Value(internal.KeyFactory))
|
||||
}
|
||||
meta.DAO.Init(factory, client.NewGVR(t.gvr))
|
||||
|
||||
return meta, nil
|
||||
}
|
||||
|
||||
func (t *Table) resourceMeta() ResourceMeta {
|
||||
meta, ok := Registry[t.gvr]
|
||||
if !ok {
|
||||
log.Debug().Msgf("Resource %s not found in registry. Going generic!", t.gvr)
|
||||
meta = ResourceMeta{
|
||||
DAO: &dao.Generic{},
|
||||
Renderer: &render.Generic{},
|
||||
}
|
||||
}
|
||||
if meta.DAO == nil {
|
||||
meta.DAO = &dao.Resource{}
|
||||
}
|
||||
|
||||
return meta
|
||||
}
|
||||
|
||||
func (t *Table) fireTableChanged(data render.TableData) {
|
||||
for _, l := range t.listeners {
|
||||
l.TableDataChanged(data)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Table) fireTableLoadFailed(err error) {
|
||||
for _, l := range t.listeners {
|
||||
l.TableLoadFailed(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Helpers...
|
||||
|
||||
func hydrate(ns string, oo []runtime.Object, rr render.Rows, re Renderer) error {
|
||||
for i, o := range oo {
|
||||
if err := re.Render(o, ns, &rr[i]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package model
|
|||
import (
|
||||
"context"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/dao"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/derailed/tview"
|
||||
|
|
@ -54,23 +55,40 @@ type Renderer interface {
|
|||
ColorerFunc() render.ColorerFunc
|
||||
}
|
||||
|
||||
// Lister represents a resource lister.
|
||||
type Lister interface {
|
||||
// Init initializes a resource.
|
||||
Init(ns, gvr string, f dao.Factory)
|
||||
|
||||
type Cruder interface {
|
||||
// List returns a collection of resources.
|
||||
List(context.Context) ([]runtime.Object, error)
|
||||
List(ctx context.Context, ns string) ([]runtime.Object, error)
|
||||
|
||||
// Get returns a resource instance.
|
||||
Get(ctx context.Context, path string) (runtime.Object, error)
|
||||
|
||||
// Delete removes a resource.
|
||||
// Delete(ctx context.Context, path string) error
|
||||
}
|
||||
|
||||
// Lister represents a resource lister.
|
||||
type Lister interface {
|
||||
Cruder
|
||||
// Describer
|
||||
|
||||
// Init initializes a resource.
|
||||
Init(ns, gvr string, f dao.Factory)
|
||||
|
||||
// Hydrate converts resource rows into tabular data.
|
||||
Hydrate(oo []runtime.Object, rr render.Rows, r Renderer) error
|
||||
// Hydrate(oo []runtime.Object, rr render.Rows, r Renderer) error
|
||||
}
|
||||
|
||||
// Describer represents a resource describer.
|
||||
type Describer interface {
|
||||
// ToYAML return resource yaml.
|
||||
ToYAML(ctx context.Context, path string) (string, error)
|
||||
|
||||
// Describe returns a resource description.
|
||||
Describe(client client.Connection, gvr, path string) (string, error)
|
||||
}
|
||||
|
||||
// ResourceMeta represents model info about a resource.
|
||||
type ResourceMeta struct {
|
||||
Model Lister
|
||||
DAO dao.Accessor
|
||||
Renderer Renderer
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package render_test
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/gdamore/tcell"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
|
@ -18,15 +19,15 @@ func TestAliasColorer(t *testing.T) {
|
|||
e tcell.Color
|
||||
}{
|
||||
"addAll": {
|
||||
ns: render.AllNamespaces,
|
||||
ns: client.AllNamespaces,
|
||||
re: render.RowEvent{Kind: render.EventAdd, Row: r},
|
||||
e: tcell.ColorMediumSpringGreen},
|
||||
"deleteAll": {
|
||||
ns: render.AllNamespaces,
|
||||
ns: client.AllNamespaces,
|
||||
re: render.RowEvent{Kind: render.EventDelete, Row: r},
|
||||
e: tcell.ColorMediumSpringGreen},
|
||||
"updateAll": {
|
||||
ns: render.AllNamespaces,
|
||||
ns: client.AllNamespaces,
|
||||
re: render.RowEvent{Kind: render.EventUpdate, Row: r},
|
||||
e: tcell.ColorMediumSpringGreen,
|
||||
},
|
||||
|
|
@ -49,7 +50,7 @@ func TestAliasHeader(t *testing.T) {
|
|||
|
||||
var a render.Alias
|
||||
assert.Equal(t, h, a.Header("fred"))
|
||||
assert.Equal(t, h, a.Header(render.AllNamespaces))
|
||||
assert.Equal(t, h, a.Header(client.AllNamespaces))
|
||||
}
|
||||
|
||||
func TestAliasRender(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,82 @@
|
|||
package render
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/gdamore/tcell"
|
||||
"helm.sh/helm/v3/pkg/release"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// Chart renders a helm chart to screen.
|
||||
type Chart struct{}
|
||||
|
||||
// ColorerFunc colors a resource row.
|
||||
func (Chart) ColorerFunc() ColorerFunc {
|
||||
return func(ns string, re RowEvent) tcell.Color {
|
||||
return tcell.ColorMediumSpringGreen
|
||||
}
|
||||
}
|
||||
|
||||
// Header returns a header row.
|
||||
func (Chart) Header(ns string) HeaderRow {
|
||||
var h HeaderRow
|
||||
if client.IsAllNamespaces(ns) {
|
||||
h = append(h, Header{Name: "NAMESPACE"})
|
||||
}
|
||||
|
||||
return append(h,
|
||||
Header{Name: "NAME"},
|
||||
Header{Name: "REVISION"},
|
||||
Header{Name: "STATUS"},
|
||||
Header{Name: "CHART"},
|
||||
Header{Name: "APP VERSION"},
|
||||
Header{Name: "AGE", Decorator: AgeDecorator},
|
||||
)
|
||||
}
|
||||
|
||||
// Render renders a chart to screen.
|
||||
func (c Chart) Render(o interface{}, ns string, r *Row) error {
|
||||
h, ok := o.(ChartRes)
|
||||
if !ok {
|
||||
return fmt.Errorf("expected ChartRes, but got %T", o)
|
||||
}
|
||||
|
||||
r.ID = FQN(h.Release.Namespace, h.Release.Name)
|
||||
r.Fields = make(Fields, 0, len(c.Header(ns)))
|
||||
if client.IsAllNamespaces(ns) {
|
||||
r.Fields = append(r.Fields, h.Release.Namespace)
|
||||
}
|
||||
r.Fields = append(r.Fields,
|
||||
h.Release.Name,
|
||||
strconv.Itoa(h.Release.Version),
|
||||
h.Release.Info.Status.String(),
|
||||
h.Release.Chart.Metadata.Name+"-"+h.Release.Chart.Metadata.Version,
|
||||
h.Release.Chart.Metadata.AppVersion,
|
||||
toAge(metav1.Time{Time: h.Release.Info.LastDeployed.Time}),
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Helpers...
|
||||
|
||||
// ChartRes represents an alias resource.
|
||||
type ChartRes struct {
|
||||
Release *release.Release
|
||||
}
|
||||
|
||||
// GetObjectKind returns a schema object.
|
||||
func (ChartRes) GetObjectKind() schema.ObjectKind {
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyObject returns a container copy.
|
||||
func (h ChartRes) DeepCopyObject() runtime.Object {
|
||||
return h
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/tview"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
|
@ -21,7 +22,7 @@ func (ConfigMap) ColorerFunc() ColorerFunc {
|
|||
// Header returns a header row.
|
||||
func (ConfigMap) Header(ns string) HeaderRow {
|
||||
var h HeaderRow
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
h = append(h, Header{Name: "NAMESPACE"})
|
||||
}
|
||||
|
||||
|
|
@ -48,7 +49,7 @@ func (c ConfigMap) Render(o interface{}, ns string, r *Row) error {
|
|||
n, nss := extractMetaField(meta, "name"), extractMetaField(meta, "namespace")
|
||||
r.ID = FQN(nss, n)
|
||||
r.Fields = make(Fields, 0, len(c.Header(ns)))
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
r.Fields = append(r.Fields, nss)
|
||||
}
|
||||
|
||||
|
|
@ -79,7 +80,7 @@ func (c ConfigMap) Render(o interface{}, ns string, r *Row) error {
|
|||
|
||||
// r.ID = MetaFQN(cm.ObjectMeta)
|
||||
// r.Fields = make(Fields, 0, len(c.Header(ns)))
|
||||
// if isAllNamespace(ns) {
|
||||
// if client.IsAllNamespaces(ns) {
|
||||
// r.Fields = append(r.Fields, cm.Namespace)
|
||||
// }
|
||||
// r.Fields = append(r.Fields,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/tview"
|
||||
"github.com/gdamore/tcell"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
|
|
@ -95,7 +96,7 @@ func (c Container) Render(o interface{}, name string, r *Row) error {
|
|||
}
|
||||
|
||||
r.ID = co.Container.Name
|
||||
r.Fields = make(Fields, 0, len(c.Header(AllNamespaces)))
|
||||
r.Fields = make(Fields, 0, len(c.Header(client.AllNamespaces)))
|
||||
r.Fields = append(r.Fields,
|
||||
co.Container.Name,
|
||||
co.Container.Image,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/rs/zerolog/log"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
|
@ -41,7 +42,7 @@ func (CustomResourceDefinition) Render(o interface{}, ns string, r *Row) error {
|
|||
log.Error().Err(err).Msgf("Fields timestamp %v", err)
|
||||
}
|
||||
|
||||
r.ID = FQN(ClusterScope, extractMetaField(meta, "name"))
|
||||
r.ID = FQN(client.ClusterScope, extractMetaField(meta, "name"))
|
||||
r.Fields = Fields{
|
||||
extractMetaField(meta, "name"),
|
||||
toAge(metav1.Time{Time: t}),
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
batchv1beta1 "k8s.io/api/batch/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
|
@ -20,7 +21,7 @@ func (CronJob) ColorerFunc() ColorerFunc {
|
|||
// Header returns a header row.
|
||||
func (CronJob) Header(ns string) HeaderRow {
|
||||
var h HeaderRow
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
h = append(h, Header{Name: "NAMESPACE"})
|
||||
}
|
||||
|
||||
|
|
@ -53,7 +54,7 @@ func (c CronJob) Render(o interface{}, ns string, r *Row) error {
|
|||
|
||||
r.ID = MetaFQN(cj.ObjectMeta)
|
||||
r.Fields = make(Fields, 0, len(c.Header(ns)))
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
r.Fields = append(r.Fields, cj.Namespace)
|
||||
}
|
||||
r.Fields = append(r.Fields,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/tview"
|
||||
"github.com/gdamore/tcell"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
|
|
@ -24,7 +25,7 @@ func (Deployment) ColorerFunc() ColorerFunc {
|
|||
}
|
||||
|
||||
markCol := 2
|
||||
if ns != AllNamespaces {
|
||||
if !client.IsAllNamespaces(ns) {
|
||||
markCol = 1
|
||||
}
|
||||
tokens := strings.Split(r.Row.Fields[markCol], "/")
|
||||
|
|
@ -39,7 +40,7 @@ func (Deployment) ColorerFunc() ColorerFunc {
|
|||
// Header returns a header row.
|
||||
func (Deployment) Header(ns string) HeaderRow {
|
||||
var h HeaderRow
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
h = append(h, Header{Name: "NAMESPACE"})
|
||||
}
|
||||
|
||||
|
|
@ -67,7 +68,7 @@ func (d Deployment) Render(o interface{}, ns string, r *Row) error {
|
|||
|
||||
r.ID = MetaFQN(dp.ObjectMeta)
|
||||
r.Fields = make(Fields, 0, len(d.Header(ns)))
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
r.Fields = append(r.Fields, dp.Namespace)
|
||||
}
|
||||
r.Fields = append(r.Fields,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/tview"
|
||||
"github.com/gdamore/tcell"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
|
|
@ -24,7 +25,7 @@ func (DaemonSet) ColorerFunc() ColorerFunc {
|
|||
}
|
||||
|
||||
markCol := 2
|
||||
if ns != AllNamespaces {
|
||||
if !client.IsAllNamespaces(ns) {
|
||||
markCol = 1
|
||||
}
|
||||
if strings.TrimSpace(r.Row.Fields[markCol]) != strings.TrimSpace(r.Row.Fields[markCol+2]) {
|
||||
|
|
@ -38,7 +39,7 @@ func (DaemonSet) ColorerFunc() ColorerFunc {
|
|||
// Header returns a header row.
|
||||
func (DaemonSet) Header(ns string) HeaderRow {
|
||||
var h HeaderRow
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
h = append(h, Header{Name: "NAMESPACE"})
|
||||
}
|
||||
|
||||
|
|
@ -67,7 +68,7 @@ func (d DaemonSet) Render(o interface{}, ns string, r *Row) error {
|
|||
|
||||
r.ID = MetaFQN(ds.ObjectMeta)
|
||||
r.Fields = make(Fields, 0, len(d.Header(ns)))
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
r.Fields = append(r.Fields, ds.Namespace)
|
||||
}
|
||||
r.Fields = append(r.Fields,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
|
@ -21,7 +22,7 @@ func (Endpoints) ColorerFunc() ColorerFunc {
|
|||
// Header returns a header row.
|
||||
func (Endpoints) Header(ns string) HeaderRow {
|
||||
var h HeaderRow
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
h = append(h, Header{Name: "NAMESPACE"})
|
||||
}
|
||||
|
||||
|
|
@ -46,7 +47,7 @@ func (e Endpoints) Render(o interface{}, ns string, r *Row) error {
|
|||
|
||||
r.ID = MetaFQN(ep.ObjectMeta)
|
||||
r.Fields = make(Fields, 0, len(e.Header(ns)))
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
r.Fields = append(r.Fields, ep.Namespace)
|
||||
}
|
||||
r.Fields = append(r.Fields,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/tview"
|
||||
"github.com/gdamore/tcell"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
|
|
@ -21,7 +22,7 @@ func (Event) ColorerFunc() ColorerFunc {
|
|||
c := DefaultColorer(ns, r)
|
||||
|
||||
markCol := 3
|
||||
if ns != AllNamespaces {
|
||||
if !client.IsAllNamespaces(ns) {
|
||||
markCol = 2
|
||||
}
|
||||
switch strings.TrimSpace(r.Row.Fields[markCol]) {
|
||||
|
|
@ -38,7 +39,7 @@ func (Event) ColorerFunc() ColorerFunc {
|
|||
// Header returns a header rbw.
|
||||
func (Event) Header(ns string) HeaderRow {
|
||||
var h HeaderRow
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
h = append(h, Header{Name: "NAMESPACE"})
|
||||
}
|
||||
|
||||
|
|
@ -66,7 +67,7 @@ func (e Event) Render(o interface{}, ns string, r *Row) error {
|
|||
|
||||
r.ID = MetaFQN(ev.ObjectMeta)
|
||||
r.Fields = make(Fields, 0, len(e.Header(ns)))
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
r.Fields = append(r.Fields, ev.Namespace)
|
||||
}
|
||||
r.Fields = append(r.Fields,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
|
||||
)
|
||||
|
||||
|
|
@ -35,7 +36,7 @@ func (g *Generic) Header(ns string) HeaderRow {
|
|||
}
|
||||
|
||||
h := make(HeaderRow, 0, len(g.table.ColumnDefinitions))
|
||||
if ns == "" {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
h = append(h, Header{Name: "NAMESPACE"})
|
||||
}
|
||||
for i, c := range g.table.ColumnDefinitions {
|
||||
|
|
@ -59,22 +60,19 @@ func (g *Generic) Render(o interface{}, ns string, r *Row) error {
|
|||
return fmt.Errorf("expecting a TableRow but got %T", o)
|
||||
}
|
||||
|
||||
var nns = AllNamespaces
|
||||
if ns != ClusterScope {
|
||||
var err error
|
||||
nns, err = extractNamespace(row.Object.Raw)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, nns, err := resourceNS(row.Object.Raw)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
n, ok := row.Cells[0].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("expecting row id to be a string but got %#v", row.Cells[0])
|
||||
return fmt.Errorf("expecting row 0 to be a string but got %T", row.Cells[0])
|
||||
}
|
||||
|
||||
r.ID = FQN(nns, n)
|
||||
r.Fields = make(Fields, 0, len(g.Header(ns)))
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) && nns != "" {
|
||||
r.Fields = append(r.Fields, nns)
|
||||
}
|
||||
var ageCell interface{}
|
||||
|
|
@ -95,21 +93,26 @@ func (g *Generic) Render(o interface{}, ns string, r *Row) error {
|
|||
// ----------------------------------------------------------------------------
|
||||
// Helpers...
|
||||
|
||||
func extractNamespace(raw []byte) (string, error) {
|
||||
func resourceNS(raw []byte) (bool, string, error) {
|
||||
var obj map[string]interface{}
|
||||
err := json.Unmarshal(raw, &obj)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return false, "", err
|
||||
}
|
||||
|
||||
meta, ok := obj["metadata"].(map[string]interface{})
|
||||
if !ok {
|
||||
return "", errors.New("no metadata found on generic resource")
|
||||
}
|
||||
ns, ok := meta["namespace"].(string)
|
||||
if !ok {
|
||||
return "", errors.New("invalid namespace found on generic metadata")
|
||||
return false, "", errors.New("no metadata found on generic resource")
|
||||
}
|
||||
|
||||
return ns, nil
|
||||
ns, ok := meta["namespace"]
|
||||
if !ok {
|
||||
return true, "", nil
|
||||
}
|
||||
|
||||
nns, ok := ns.(string)
|
||||
if !ok {
|
||||
return false, "", fmt.Errorf("expecting namespace string type but got %T", ns)
|
||||
}
|
||||
return false, nns, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package render_test
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/stretchr/testify/assert"
|
||||
metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
|
||||
|
|
@ -17,8 +18,8 @@ func TestGenericRender(t *testing.T) {
|
|||
eFields render.Fields
|
||||
eHeader render.HeaderRow
|
||||
}{
|
||||
"specific_ns": {
|
||||
ns: "blee",
|
||||
"withNS": {
|
||||
ns: "ns1",
|
||||
table: makeNSGeneric(),
|
||||
eID: "ns1/c1",
|
||||
eFields: render.Fields{"c1", "c2", "c3"},
|
||||
|
|
@ -28,9 +29,9 @@ func TestGenericRender(t *testing.T) {
|
|||
render.Header{Name: "C"},
|
||||
},
|
||||
},
|
||||
"all_ns": {
|
||||
ns: "",
|
||||
table: makeAllNSGeneric(),
|
||||
"nsAll": {
|
||||
ns: client.NamespaceAll,
|
||||
table: makeNSGeneric(),
|
||||
eID: "ns1/c1",
|
||||
eFields: render.Fields{"ns1", "c1", "c2", "c3"},
|
||||
eHeader: render.HeaderRow{
|
||||
|
|
@ -40,9 +41,21 @@ func TestGenericRender(t *testing.T) {
|
|||
render.Header{Name: "C"},
|
||||
},
|
||||
},
|
||||
"cluster": {
|
||||
ns: "-",
|
||||
table: makeClusterGeneric(),
|
||||
"AllNS": {
|
||||
ns: client.AllNamespaces,
|
||||
table: makeNSGeneric(),
|
||||
eID: "ns1/c1",
|
||||
eFields: render.Fields{"ns1", "c1", "c2", "c3"},
|
||||
eHeader: render.HeaderRow{
|
||||
render.Header{Name: "NAMESPACE"},
|
||||
render.Header{Name: "A"},
|
||||
render.Header{Name: "B"},
|
||||
render.Header{Name: "C"},
|
||||
},
|
||||
},
|
||||
"clusterWide": {
|
||||
ns: client.ClusterScope,
|
||||
table: makeNoNSGeneric(),
|
||||
eID: "c1",
|
||||
eFields: render.Fields{"c1", "c2", "c3"},
|
||||
eHeader: render.HeaderRow{
|
||||
|
|
@ -52,7 +65,7 @@ func TestGenericRender(t *testing.T) {
|
|||
},
|
||||
},
|
||||
"age": {
|
||||
ns: "-",
|
||||
ns: client.ClusterScope,
|
||||
table: makeAgeGeneric(),
|
||||
eID: "c1",
|
||||
eFields: render.Fields{"c1", "c2", "Age"},
|
||||
|
|
@ -64,16 +77,17 @@ func TestGenericRender(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
var re render.Generic
|
||||
for k := range uu {
|
||||
var re render.Generic
|
||||
u := uu[k]
|
||||
t.Run(k, func(t *testing.T) {
|
||||
var r render.Row
|
||||
re.SetTable(u.table)
|
||||
|
||||
assert.Equal(t, u.eHeader, re.Header(u.ns))
|
||||
assert.Nil(t, re.Render(&u.table.Rows[0], u.ns, &r))
|
||||
assert.Equal(t, u.eID, r.ID)
|
||||
assert.Equal(t, u.eFields, r.Fields)
|
||||
assert.Equal(t, u.eHeader, re.Header(u.ns))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -109,35 +123,7 @@ func makeNSGeneric() *metav1beta1.Table {
|
|||
}
|
||||
}
|
||||
|
||||
func makeAllNSGeneric() *metav1beta1.Table {
|
||||
return &metav1beta1.Table{
|
||||
ColumnDefinitions: []metav1beta1.TableColumnDefinition{
|
||||
{Name: "a"},
|
||||
{Name: "b"},
|
||||
{Name: "c"},
|
||||
},
|
||||
Rows: []metav1beta1.TableRow{
|
||||
{
|
||||
Object: runtime.RawExtension{
|
||||
Raw: []byte(`{
|
||||
"kind": "fred",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"namespace": "ns1",
|
||||
"name": "fred"
|
||||
}}`),
|
||||
},
|
||||
Cells: []interface{}{
|
||||
"c1",
|
||||
"c2",
|
||||
"c3",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func makeClusterGeneric() *metav1beta1.Table {
|
||||
func makeNoNSGeneric() *metav1beta1.Table {
|
||||
return &metav1beta1.Table{
|
||||
ColumnDefinitions: []metav1beta1.TableColumnDefinition{
|
||||
{Name: "a"},
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/tview"
|
||||
runewidth "github.com/mattn/go-runewidth"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
|
@ -31,10 +32,6 @@ func asSelector(s *metav1.LabelSelector) string {
|
|||
return sel.String()
|
||||
}
|
||||
|
||||
func isAllNamespace(ns string) bool {
|
||||
return ns == AllNamespaces
|
||||
}
|
||||
|
||||
type metric struct {
|
||||
cpu, mem string
|
||||
}
|
||||
|
|
@ -46,7 +43,7 @@ func noMetric() metric {
|
|||
// MetaFQN returns a fully qualified resource name.
|
||||
func MetaFQN(m metav1.ObjectMeta) string {
|
||||
if m.Namespace == "" {
|
||||
return m.Name
|
||||
return FQN(client.ClusterScope, m.Name)
|
||||
}
|
||||
|
||||
return FQN(m.Namespace, m.Name)
|
||||
|
|
|
|||
|
|
@ -270,7 +270,7 @@ func TestMetaFQN(t *testing.T) {
|
|||
e string
|
||||
}{
|
||||
"full": {metav1.ObjectMeta{Namespace: "fred", Name: "blee"}, "fred/blee"},
|
||||
"nons": {metav1.ObjectMeta{Name: "blee"}, "blee"},
|
||||
"nons": {metav1.ObjectMeta{Name: "blee"}, "-/blee"},
|
||||
}
|
||||
|
||||
for k := range uu {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/tview"
|
||||
autoscalingv1 "k8s.io/api/autoscaling/v1"
|
||||
autoscalingv2beta1 "k8s.io/api/autoscaling/v2beta1"
|
||||
|
|
@ -24,7 +25,7 @@ func (HorizontalPodAutoscaler) ColorerFunc() ColorerFunc {
|
|||
// Header returns a header row.
|
||||
func (HorizontalPodAutoscaler) Header(ns string) HeaderRow {
|
||||
var h HeaderRow
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
h = append(h, Header{Name: "NAMESPACE"})
|
||||
}
|
||||
|
||||
|
|
@ -69,7 +70,7 @@ func (h HorizontalPodAutoscaler) renderV1(raw *unstructured.Unstructured, ns str
|
|||
|
||||
r.ID = MetaFQN(hpa.ObjectMeta)
|
||||
r.Fields = make(Fields, 0, len(h.Header(ns)))
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
r.Fields = append(r.Fields, hpa.Namespace)
|
||||
}
|
||||
r.Fields = append(r.Fields,
|
||||
|
|
@ -94,7 +95,7 @@ func (h HorizontalPodAutoscaler) renderV2b1(raw *unstructured.Unstructured, ns s
|
|||
|
||||
r.ID = MetaFQN(hpa.ObjectMeta)
|
||||
r.Fields = make(Fields, 0, len(h.Header(ns)))
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
r.Fields = append(r.Fields, hpa.Namespace)
|
||||
}
|
||||
|
||||
|
|
@ -120,7 +121,7 @@ func (h HorizontalPodAutoscaler) renderV2b2(raw *unstructured.Unstructured, ns s
|
|||
|
||||
r.ID = MetaFQN(hpa.ObjectMeta)
|
||||
r.Fields = make(Fields, 0, len(h.Header(ns)))
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
r.Fields = append(r.Fields, hpa.Namespace)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/api/extensions/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
|
@ -21,7 +22,7 @@ func (Ingress) ColorerFunc() ColorerFunc {
|
|||
// Header returns a header row.
|
||||
func (Ingress) Header(ns string) HeaderRow {
|
||||
var h HeaderRow
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
h = append(h, Header{Name: "NAMESPACE"})
|
||||
}
|
||||
|
||||
|
|
@ -48,7 +49,7 @@ func (i Ingress) Render(o interface{}, ns string, r *Row) error {
|
|||
|
||||
r.ID = MetaFQN(ing.ObjectMeta)
|
||||
r.Fields = make(Fields, 0, len(i.Header(ns)))
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
r.Fields = append(r.Fields, ing.Namespace)
|
||||
}
|
||||
r.Fields = append(r.Fields,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/rs/zerolog/log"
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
|
|
@ -25,7 +26,7 @@ func (Job) ColorerFunc() ColorerFunc {
|
|||
// Header returns a header row.
|
||||
func (Job) Header(ns string) HeaderRow {
|
||||
var h HeaderRow
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
h = append(h, Header{Name: "NAMESPACE"})
|
||||
}
|
||||
|
||||
|
|
@ -54,7 +55,7 @@ func (j Job) Render(o interface{}, ns string, r *Row) error {
|
|||
|
||||
r.ID = MetaFQN(job.ObjectMeta)
|
||||
r.Fields = make(Fields, 0, len(j.Header(ns)))
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
r.Fields = append(r.Fields, job.Namespace)
|
||||
}
|
||||
cc, ii := toContainers(job.Spec.Template.Spec)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
v1beta1 "k8s.io/api/extensions/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
|
@ -21,7 +22,7 @@ func (NetworkPolicy) ColorerFunc() ColorerFunc {
|
|||
// Header returns a header row.
|
||||
func (NetworkPolicy) Header(ns string) HeaderRow {
|
||||
var h HeaderRow
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
h = append(h, Header{Name: "NAMESPACE"})
|
||||
}
|
||||
|
||||
|
|
@ -54,7 +55,7 @@ func (n NetworkPolicy) Render(o interface{}, ns string, r *Row) error {
|
|||
|
||||
r.ID = MetaFQN(np.ObjectMeta)
|
||||
r.Fields = make(Fields, 0, len(n.Header(ns)))
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
r.Fields = append(r.Fields, np.Namespace)
|
||||
}
|
||||
r.Fields = append(r.Fields,
|
||||
|
|
|
|||
|
|
@ -39,6 +39,6 @@ func TestNamespaceRender(t *testing.T) {
|
|||
r := render.NewRow(3)
|
||||
c.Render(load(t, "ns"), "-", &r)
|
||||
|
||||
assert.Equal(t, "kube-system", r.ID)
|
||||
assert.Equal(t, "-/kube-system", r.ID)
|
||||
assert.Equal(t, render.Fields{"kube-system", "Active"}, r.Fields[:2])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/tview"
|
||||
"github.com/gdamore/tcell"
|
||||
v1beta1 "k8s.io/api/policy/v1beta1"
|
||||
|
|
@ -25,7 +26,7 @@ func (PodDisruptionBudget) ColorerFunc() ColorerFunc {
|
|||
}
|
||||
|
||||
markCol := 5
|
||||
if ns != AllNamespaces {
|
||||
if client.IsNamespaced(ns) {
|
||||
markCol = 4
|
||||
}
|
||||
if strings.TrimSpace(r.Row.Fields[markCol]) != strings.TrimSpace(r.Row.Fields[markCol+1]) {
|
||||
|
|
@ -40,7 +41,7 @@ func (PodDisruptionBudget) ColorerFunc() ColorerFunc {
|
|||
// Header returns a header row.
|
||||
func (PodDisruptionBudget) Header(ns string) HeaderRow {
|
||||
var h HeaderRow
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
h = append(h, Header{Name: "NAMESPACE"})
|
||||
}
|
||||
|
||||
|
|
@ -70,7 +71,7 @@ func (p PodDisruptionBudget) Render(o interface{}, ns string, r *Row) error {
|
|||
|
||||
r.ID = MetaFQN(pdb.ObjectMeta)
|
||||
r.Fields = make(Fields, 0, len(p.Header(ns)))
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
r.Fields = append(r.Fields, pdb.Namespace)
|
||||
}
|
||||
r.Fields = append(r.Fields,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/tview"
|
||||
"github.com/gdamore/tcell"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
|
|
@ -66,7 +67,7 @@ func (Pod) checkReadyCol(readyCol, statusCol string, c tcell.Color) tcell.Color
|
|||
// Header returns a header row.
|
||||
func (Pod) Header(ns string) HeaderRow {
|
||||
var h HeaderRow
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
h = append(h, Header{Name: "NAMESPACE"})
|
||||
}
|
||||
|
||||
|
|
@ -105,7 +106,7 @@ func (p Pod) Render(o interface{}, ns string, r *Row) error {
|
|||
|
||||
r.ID = MetaFQN(po.ObjectMeta)
|
||||
r.Fields = make(Fields, 0, len(p.Header(ns)))
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
r.Fields = append(r.Fields, po.Namespace)
|
||||
}
|
||||
r.Fields = append(r.Fields,
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ type Policies []PolicyRes
|
|||
|
||||
// Upsert adds a new policy.
|
||||
func (pp Policies) Upsert(p PolicyRes) Policies {
|
||||
idx, ok := pp.findPol(p.Resource)
|
||||
idx, ok := pp.find(p.Resource)
|
||||
if !ok {
|
||||
return append(pp, p)
|
||||
}
|
||||
|
|
@ -113,7 +113,7 @@ func (pp Policies) Upsert(p PolicyRes) Policies {
|
|||
}
|
||||
|
||||
// Find locates a row by id. Retturns false is not found.
|
||||
func (pp Policies) findPol(res string) (int, bool) {
|
||||
func (pp Policies) find(res string) (int, bool) {
|
||||
for i, p := range pp {
|
||||
if p.Resource == res {
|
||||
return i, true
|
||||
|
|
|
|||
|
|
@ -12,6 +12,6 @@ func TestPersistentVolumeRender(t *testing.T) {
|
|||
r := render.NewRow(9)
|
||||
c.Render(load(t, "pv"), "-", &r)
|
||||
|
||||
assert.Equal(t, "pvc-07aa4e2c-8726-11e9-a8e8-42010a80015b", r.ID)
|
||||
assert.Equal(t, "-/pvc-07aa4e2c-8726-11e9-a8e8-42010a80015b", r.ID)
|
||||
assert.Equal(t, render.Fields{"pvc-07aa4e2c-8726-11e9-a8e8-42010a80015b", "1Gi", "RWO", "Delete", "Bound", "default/www-nginx-sts-1", "standard"}, r.Fields[:7])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/gdamore/tcell"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
|
@ -22,7 +23,7 @@ func (PersistentVolumeClaim) ColorerFunc() ColorerFunc {
|
|||
}
|
||||
|
||||
markCol := 2
|
||||
if ns != AllNamespaces {
|
||||
if client.IsNamespaced(ns) {
|
||||
markCol = 1
|
||||
}
|
||||
|
||||
|
|
@ -38,7 +39,7 @@ func (PersistentVolumeClaim) ColorerFunc() ColorerFunc {
|
|||
// Header returns a header rbw.
|
||||
func (PersistentVolumeClaim) Header(ns string) HeaderRow {
|
||||
var h HeaderRow
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
h = append(h, Header{Name: "NAMESPACE"})
|
||||
}
|
||||
|
||||
|
|
@ -86,7 +87,7 @@ func (p PersistentVolumeClaim) Render(o interface{}, ns string, r *Row) error {
|
|||
|
||||
r.ID = MetaFQN(pvc.ObjectMeta)
|
||||
r.Fields = make(Fields, 0, len(p.Header(ns)))
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
r.Fields = append(r.Fields, pvc.Namespace)
|
||||
}
|
||||
r.Fields = append(r.Fields,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package render
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
|
@ -19,7 +20,7 @@ func (Role) ColorerFunc() ColorerFunc {
|
|||
// Header returns a header row.
|
||||
func (Role) Header(ns string) HeaderRow {
|
||||
var h HeaderRow
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
h = append(h, Header{Name: "NAMESPACE"})
|
||||
}
|
||||
|
||||
|
|
@ -43,7 +44,7 @@ func (r Role) Render(o interface{}, ns string, row *Row) error {
|
|||
|
||||
row.ID = MetaFQN(ro.ObjectMeta)
|
||||
row.Fields = make(Fields, 0, len(r.Header(ns)))
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
row.Fields = append(row.Fields, ro.Namespace)
|
||||
}
|
||||
row.Fields = append(row.Fields,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
|
@ -20,7 +21,7 @@ func (RoleBinding) ColorerFunc() ColorerFunc {
|
|||
// Header returns a header rbw.
|
||||
func (RoleBinding) Header(ns string) HeaderRow {
|
||||
var h HeaderRow
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
h = append(h, Header{Name: "NAMESPACE"})
|
||||
}
|
||||
|
||||
|
|
@ -49,7 +50,7 @@ func (r RoleBinding) Render(o interface{}, ns string, row *Row) error {
|
|||
|
||||
row.ID = MetaFQN(rb.ObjectMeta)
|
||||
row.Fields = make(Fields, 0, len(r.Header(ns)))
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
row.Fields = append(row.Fields, rb.Namespace)
|
||||
}
|
||||
row.Fields = append(row.Fields,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/tview"
|
||||
"github.com/gdamore/tcell"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
|
|
@ -24,7 +25,7 @@ func (ReplicaSet) ColorerFunc() ColorerFunc {
|
|||
}
|
||||
|
||||
markCol := 2
|
||||
if ns != AllNamespaces {
|
||||
if client.IsNamespaced(ns) {
|
||||
markCol = 1
|
||||
}
|
||||
if strings.TrimSpace(r.Row.Fields[markCol]) != strings.TrimSpace(r.Row.Fields[markCol+1]) {
|
||||
|
|
@ -39,7 +40,7 @@ func (ReplicaSet) ColorerFunc() ColorerFunc {
|
|||
// Header returns a header row.
|
||||
func (ReplicaSet) Header(ns string) HeaderRow {
|
||||
var h HeaderRow
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
h = append(h, Header{Name: "NAMESPACE"})
|
||||
}
|
||||
|
||||
|
|
@ -66,7 +67,7 @@ func (s ReplicaSet) Render(o interface{}, ns string, r *Row) error {
|
|||
|
||||
r.ID = MetaFQN(rs.ObjectMeta)
|
||||
r.Fields = make(Fields, 0, len(s.Header(ns)))
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
r.Fields = append(r.Fields, rs.Namespace)
|
||||
}
|
||||
r.Fields = append(r.Fields,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
|
@ -20,7 +21,7 @@ func (ServiceAccount) ColorerFunc() ColorerFunc {
|
|||
// Header returns a header row.
|
||||
func (ServiceAccount) Header(ns string) HeaderRow {
|
||||
var h HeaderRow
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
h = append(h, Header{Name: "NAMESPACE"})
|
||||
}
|
||||
|
||||
|
|
@ -45,7 +46,7 @@ func (s ServiceAccount) Render(o interface{}, ns string, r *Row) error {
|
|||
|
||||
r.ID = MetaFQN(sa.ObjectMeta)
|
||||
r.Fields = make(Fields, 0, len(s.Header(ns)))
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
r.Fields = append(r.Fields, sa.Namespace)
|
||||
}
|
||||
r.Fields = append(r.Fields,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package render
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
storagev1 "k8s.io/api/storage/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
|
@ -37,7 +38,7 @@ func (StorageClass) Render(o interface{}, ns string, r *Row) error {
|
|||
return err
|
||||
}
|
||||
|
||||
r.ID = FQN(ClusterScope, sc.ObjectMeta.Name)
|
||||
r.ID = FQN(client.ClusterScope, sc.ObjectMeta.Name)
|
||||
r.Fields = Fields{
|
||||
sc.Name,
|
||||
string(sc.Provisioner),
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/tview"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
|
@ -21,7 +22,7 @@ func (Secret) ColorerFunc() ColorerFunc {
|
|||
// Header returns a header row.
|
||||
func (Secret) Header(ns string) HeaderRow {
|
||||
var h HeaderRow
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
h = append(h, Header{Name: "NAMESPACE"})
|
||||
}
|
||||
|
||||
|
|
@ -47,7 +48,7 @@ func (s Secret) Render(o interface{}, ns string, r *Row) error {
|
|||
|
||||
r.ID = MetaFQN(sec.ObjectMeta)
|
||||
r.Fields = make(Fields, 0, len(s.Header(ns)))
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
r.Fields = append(r.Fields, sec.Namespace)
|
||||
}
|
||||
r.Fields = append(r.Fields,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/gdamore/tcell"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
|
@ -23,7 +24,7 @@ func (StatefulSet) ColorerFunc() ColorerFunc {
|
|||
}
|
||||
|
||||
readyCol := 2
|
||||
if ns != AllNamespaces {
|
||||
if client.IsNamespaced(ns) {
|
||||
readyCol--
|
||||
}
|
||||
tokens := strings.Split(strings.TrimSpace(r.Row.Fields[readyCol]), "/")
|
||||
|
|
@ -39,7 +40,7 @@ func (StatefulSet) ColorerFunc() ColorerFunc {
|
|||
// Header returns a header row.
|
||||
func (StatefulSet) Header(ns string) HeaderRow {
|
||||
var h HeaderRow
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
h = append(h, Header{Name: "NAMESPACE"})
|
||||
}
|
||||
|
||||
|
|
@ -66,7 +67,7 @@ func (s StatefulSet) Render(o interface{}, ns string, r *Row) error {
|
|||
|
||||
r.ID = MetaFQN(sts.ObjectMeta)
|
||||
r.Fields = make(Fields, 0, len(s.Header(ns)))
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
r.Fields = append(r.Fields, sts.Namespace)
|
||||
}
|
||||
r.Fields = append(r.Fields,
|
||||
|
|
|
|||
|
|
@ -29,9 +29,9 @@ func (Subject) Header(ns string) HeaderRow {
|
|||
|
||||
// Render renders a K8s resource to screen.
|
||||
func (s Subject) Render(o interface{}, ns string, r *Row) error {
|
||||
res, ok := o.(SubjectRef)
|
||||
res, ok := o.(SubjectRes)
|
||||
if !ok {
|
||||
return fmt.Errorf("Expected SubjectRef, but got %T", s)
|
||||
return fmt.Errorf("Expected SubjectRes, but got %T", s)
|
||||
}
|
||||
|
||||
r.ID = res.Name
|
||||
|
|
@ -48,17 +48,42 @@ func (s Subject) Render(o interface{}, ns string, r *Row) error {
|
|||
// ----------------------------------------------------------------------------
|
||||
// Helpers...
|
||||
|
||||
// SubjectRef represents a subject rule.
|
||||
type SubjectRef struct {
|
||||
// SubjectRes represents a subject rule.
|
||||
type SubjectRes struct {
|
||||
Name, Kind, FirstLocation string
|
||||
}
|
||||
|
||||
// GetObjectKind returns a schema object.
|
||||
func (SubjectRef) GetObjectKind() schema.ObjectKind {
|
||||
func (SubjectRes) GetObjectKind() schema.ObjectKind {
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyObject returns a container copy.
|
||||
func (s SubjectRef) DeepCopyObject() runtime.Object {
|
||||
func (s SubjectRes) DeepCopyObject() runtime.Object {
|
||||
return s
|
||||
}
|
||||
|
||||
// Subjects represents a collection of RBAC policies.
|
||||
type Subjects []SubjectRes
|
||||
|
||||
// Upsert adds a new subject.
|
||||
func (ss Subjects) Upsert(s SubjectRes) Subjects {
|
||||
idx, ok := ss.find(s.Name)
|
||||
if !ok {
|
||||
return append(ss, s)
|
||||
}
|
||||
ss[idx] = s
|
||||
|
||||
return ss
|
||||
}
|
||||
|
||||
// Find locates a row by id. Retturns false is not found.
|
||||
func (ss Subjects) find(res string) (int, bool) {
|
||||
for i, s := range ss {
|
||||
if s.Name == res {
|
||||
return i, true
|
||||
}
|
||||
}
|
||||
|
||||
return 0, false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
|
@ -22,7 +23,7 @@ func (Service) ColorerFunc() ColorerFunc {
|
|||
// Header returns a header row.
|
||||
func (Service) Header(ns string) HeaderRow {
|
||||
var h HeaderRow
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
h = append(h, Header{Name: "NAMESPACE"})
|
||||
}
|
||||
|
||||
|
|
@ -51,7 +52,7 @@ func (s Service) Render(o interface{}, ns string, r *Row) error {
|
|||
|
||||
r.ID = MetaFQN(svc.ObjectMeta)
|
||||
r.Fields = make(Fields, 0, len(s.Header(ns)))
|
||||
if isAllNamespace(ns) {
|
||||
if client.IsAllNamespaces(ns) {
|
||||
r.Fields = append(r.Fields, svc.Namespace)
|
||||
}
|
||||
r.Fields = append(r.Fields,
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@ package render
|
|||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// TableData tracks a K8s resource for tabular display.
|
||||
|
|
@ -81,7 +79,6 @@ func (t *TableData) Delete(newKeys []string) {
|
|||
}
|
||||
|
||||
for _, id := range victims {
|
||||
log.Debug().Msgf("Deleting %s", id)
|
||||
t.RowEvents = t.RowEvents.Delete(id)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,6 @@
|
|||
package render
|
||||
|
||||
const (
|
||||
// AllNamespaces represents all namespaces.
|
||||
AllNamespaces = ""
|
||||
|
||||
// NamespaceAll represent the all namespace.
|
||||
NamespaceAll = "all"
|
||||
|
||||
// ClusterScope represents cluster wide resources.
|
||||
ClusterScope = "-"
|
||||
|
||||
// NonResource represents a custom resource.
|
||||
NonResource = "*"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ func (s *SelectTable) updateSelection(broadcast bool) {
|
|||
}
|
||||
|
||||
func (s *SelectTable) selectionChanged(r, c int) {
|
||||
if r <= 0 {
|
||||
if r < 0 {
|
||||
return
|
||||
}
|
||||
s.selectedRow = r
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
"github.com/derailed/k9s/internal/config"
|
||||
"github.com/derailed/k9s/internal/model"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
|
|
@ -43,9 +44,10 @@ type Table struct {
|
|||
func NewTable(gvr string) *Table {
|
||||
return &Table{
|
||||
SelectTable: &SelectTable{
|
||||
Table: tview.NewTable(),
|
||||
model: model.NewTable(gvr),
|
||||
marks: make(map[string]struct{}),
|
||||
Table: tview.NewTable(),
|
||||
model: model.NewTable(gvr),
|
||||
selectedRow: 1,
|
||||
marks: make(map[string]struct{}),
|
||||
},
|
||||
actions: make(KeyActions),
|
||||
cmdBuff: NewCmdBuff('/', FilterBuff),
|
||||
|
|
@ -107,7 +109,7 @@ func (t *Table) keyboard(evt *tcell.EventKey) *tcell.EventKey {
|
|||
t.SearchBuff().Add(evt.Rune())
|
||||
t.ClearSelection()
|
||||
data := t.GetModel().Peek()
|
||||
t.doUpdate(t.filtered(data), len(data.RowEvents) > 0)
|
||||
t.doUpdate(t.filtered(data))
|
||||
t.UpdateTitle()
|
||||
t.SelectFirstRow()
|
||||
return nil
|
||||
|
|
@ -152,23 +154,18 @@ func (t *Table) Update(data render.TableData) {
|
|||
data.Mutex.RLock()
|
||||
defer data.Mutex.RUnlock()
|
||||
|
||||
var firstRow bool
|
||||
if t.GetRowCount() == 0 {
|
||||
firstRow = true
|
||||
}
|
||||
|
||||
if t.decorateFn != nil {
|
||||
data = t.decorateFn(data)
|
||||
}
|
||||
if !t.cmdBuff.Empty() {
|
||||
data = t.filtered(data)
|
||||
}
|
||||
t.doUpdate(data, firstRow)
|
||||
t.doUpdate(data)
|
||||
t.UpdateTitle()
|
||||
}
|
||||
|
||||
func (t *Table) doUpdate(data render.TableData, firstRow bool) {
|
||||
if data.Namespace == render.AllNamespaces {
|
||||
func (t *Table) doUpdate(data render.TableData) {
|
||||
if client.IsAllNamespaces(data.Namespace) {
|
||||
t.actions[KeyShiftP] = NewKeyAction("Sort Namespace", t.SortColCmd(-2, true), false)
|
||||
} else {
|
||||
t.actions.Delete(KeyShiftP)
|
||||
|
|
@ -191,10 +188,6 @@ func (t *Table) doUpdate(data render.TableData, firstRow bool) {
|
|||
for i, r := range data.RowEvents {
|
||||
t.buildRow(data.Namespace, i+1, r, data.Header, pads)
|
||||
}
|
||||
|
||||
if firstRow {
|
||||
t.SelectFirstRow()
|
||||
}
|
||||
t.updateSelection(true)
|
||||
}
|
||||
|
||||
|
|
@ -348,34 +341,32 @@ func (t *Table) UpdateTitle() {
|
|||
|
||||
// UpdateTitle refreshes the table title.
|
||||
func (t *Table) styleTitle() string {
|
||||
ns := t.GetModel().GetNamespace()
|
||||
if ns == render.AllNamespaces {
|
||||
ns = render.NamespaceAll
|
||||
}
|
||||
rc := t.GetRowCount()
|
||||
if rc > 0 {
|
||||
rc--
|
||||
}
|
||||
|
||||
base, path := strings.Title(t.BaseTitle), t.Path
|
||||
if ns == render.AllNamespaces {
|
||||
ns = render.NamespaceAll
|
||||
base := strings.Title(t.BaseTitle)
|
||||
ns := t.GetModel().GetNamespace()
|
||||
if ns == client.AllNamespaces {
|
||||
ns = client.NamespaceAll
|
||||
}
|
||||
info := ns
|
||||
path := t.Path
|
||||
if path != "" {
|
||||
info = path
|
||||
cns, n := render.Namespaced(path)
|
||||
if cns == render.ClusterScope {
|
||||
info = n
|
||||
cns, n := client.Namespaced(path)
|
||||
if cns == client.ClusterScope {
|
||||
ns = n
|
||||
} else {
|
||||
ns = path
|
||||
}
|
||||
}
|
||||
|
||||
buff := t.SearchBuff().String()
|
||||
var title string
|
||||
if info == "" || info == render.ClusterScope {
|
||||
if ns == client.ClusterScope {
|
||||
title = SkinTitle(fmt.Sprintf(titleFmt, base, rc), t.styles.Frame())
|
||||
} else {
|
||||
title = SkinTitle(fmt.Sprintf(nsTitleFmt, base, info, rc), t.styles.Frame())
|
||||
title = SkinTitle(fmt.Sprintf(nsTitleFmt, base, ns, rc), t.styles.Frame())
|
||||
}
|
||||
if buff == "" {
|
||||
return title
|
||||
|
|
@ -384,5 +375,6 @@ func (t *Table) styleTitle() string {
|
|||
if IsLabelSelector(buff) {
|
||||
buff = TrimLabelSelector(buff)
|
||||
}
|
||||
|
||||
return title + SkinTitle(fmt.Sprintf(SearchFmt, buff), t.styles.Frame())
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue