refactor + added node view and sorters

mine
derailed 2019-03-24 16:05:40 -06:00
parent 6c3c9159de
commit 3de20dcd8b
89 changed files with 2630 additions and 2181 deletions

View File

@ -58,13 +58,12 @@ func run(cmd *cobra.Command, args []string) {
log.Error().Msg(string(debug.Stack())) log.Error().Msg(string(debug.Stack()))
fmt.Printf(printer.Colorize("Boom!! ", printer.ColorRed)) fmt.Printf(printer.Colorize("Boom!! ", printer.ColorRed))
fmt.Println(printer.Colorize(fmt.Sprintf("%v.", err), printer.ColorDarkGray)) fmt.Println(printer.Colorize(fmt.Sprintf("%v.", err), printer.ColorDarkGray))
// debug.PrintStack()
} }
}() }()
zerolog.SetGlobalLevel(parseLevel(logLevel)) zerolog.SetGlobalLevel(parseLevel(logLevel))
loadConfiguration() cfg := loadConfiguration()
app := views.NewApp() app := views.NewApp(cfg)
{ {
defer app.Stop() defer app.Stop()
app.Init(version, refreshRate, k8sFlags) app.Init(version, refreshRate, k8sFlags)
@ -72,52 +71,22 @@ func run(cmd *cobra.Command, args []string) {
} }
} }
func loadConfiguration() { func loadConfiguration() *config.Config {
log.Info().Msg("🐶 K9s starting up...") log.Info().Msg("🐶 K9s starting up...")
// Load K9s config file... // Load K9s config file...
cfg := k8s.NewConfig(k8sFlags) k8sCfg := k8s.NewConfig(k8sFlags)
config.Root = config.NewConfig(cfg) k9sCfg := config.NewConfig(k8sCfg)
if err := config.Root.Load(config.K9sConfigFile); err != nil { if err := k9sCfg.Load(config.K9sConfigFile); err != nil {
log.Warn().Msg("Unable to locate K9s config. Generating new configuration...") log.Warn().Msg("Unable to locate K9s config. Generating new configuration...")
} }
config.Root.K9s.RefreshRate = refreshRate k9sCfg.K9s.RefreshRate = refreshRate
mergeConfigs() k9sCfg.Refine(k8sFlags)
// Init K8s connection... k9sCfg.SetConnection(k8s.InitConnectionOrDie(k8sCfg, log.Logger))
k8s.InitConnectionOrDie(cfg)
log.Info().Msg("✅ Kubernetes connectivity") log.Info().Msg("✅ Kubernetes connectivity")
config.Root.Save() k9sCfg.Save()
}
func mergeConfigs() { return k9sCfg
cfg, err := k8sFlags.ToRawKubeConfigLoader().RawConfig()
if err != nil {
panic("Invalid configuration. Unable to connect to api")
}
if isSet(k8sFlags.Context) {
config.Root.K9s.CurrentContext = *k8sFlags.Context
} else {
config.Root.K9s.CurrentContext = cfg.CurrentContext
}
log.Debug().Msgf("Active Context `%v`", config.Root.K9s.CurrentContext)
if c, ok := cfg.Contexts[config.Root.K9s.CurrentContext]; ok {
config.Root.K9s.CurrentCluster = c.Cluster
if len(c.Namespace) != 0 {
config.Root.SetActiveNamespace(c.Namespace)
}
} else {
log.Panic().Msg(fmt.Sprintf("The specified context `%s does not exists in kubeconfig", config.Root.K9s.CurrentContext))
}
if isSet(k8sFlags.Namespace) {
config.Root.SetActiveNamespace(*k8sFlags.Namespace)
}
if isSet(k8sFlags.ClusterName) {
config.Root.K9s.CurrentCluster = *k8sFlags.ClusterName
}
} }
func parseLevel(level string) zerolog.Level { func parseLevel(level string) zerolog.Level {
@ -251,7 +220,3 @@ func initK8sFlags() {
func clearScreen() { func clearScreen() {
fmt.Print("\033[H\033[2J") fmt.Print("\033[H\033[2J")
} }
func isSet(s *string) bool {
return s != nil && len(*s) > 0
}

7
go.mod
View File

@ -5,10 +5,12 @@ require (
github.com/Azure/go-autorest v11.4.0+incompatible // indirect github.com/Azure/go-autorest v11.4.0+incompatible // indirect
github.com/derailed/tview v0.1.4 github.com/derailed/tview v0.1.4
github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
github.com/docker/distribution v2.7.1+incompatible // indirect
github.com/evanphx/json-patch v4.1.0+incompatible // indirect github.com/evanphx/json-patch v4.1.0+incompatible // indirect
github.com/fatih/camelcase v1.0.0 // indirect github.com/fatih/camelcase v1.0.0 // indirect
github.com/gdamore/tcell v1.1.1 github.com/gdamore/tcell v1.1.1
github.com/gogo/protobuf v1.1.1 // indirect github.com/gogo/protobuf v1.1.1 // indirect
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef // indirect
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c // indirect github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c // indirect
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf // indirect github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf // indirect
github.com/googleapis/gnostic v0.2.0 // indirect github.com/googleapis/gnostic v0.2.0 // indirect
@ -22,8 +24,10 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/onsi/gomega v1.4.3 // indirect github.com/onsi/gomega v1.4.3 // indirect
github.com/opencontainers/go-digest v1.0.0-rc1 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/petergtz/pegomock v0.0.0-20181206220228-b113d17a7e81 github.com/petergtz/pegomock v0.0.0-20181206220228-b113d17a7e81
github.com/robfig/cron v0.0.0-20180505203441-b41be1df6967 // indirect
github.com/rs/zerolog v1.12.0 github.com/rs/zerolog v1.12.0
github.com/sirupsen/logrus v1.4.0 // indirect github.com/sirupsen/logrus v1.4.0 // indirect
github.com/spf13/cobra v0.0.3 github.com/spf13/cobra v0.0.3
@ -35,9 +39,12 @@ require (
gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.2.2 gopkg.in/yaml.v2 v2.2.2
k8s.io/api v0.0.0-20190202010724-74b699b93c15 k8s.io/api v0.0.0-20190202010724-74b699b93c15
k8s.io/apiextensions-apiserver v0.0.0-20190322231200-1c09d17c1352 // indirect
k8s.io/apimachinery v0.0.0-20190207091153-095b9d203467 k8s.io/apimachinery v0.0.0-20190207091153-095b9d203467
k8s.io/apiserver v0.0.0-20190322225753-5eae03fa38e7 // indirect
k8s.io/cli-runtime v0.0.0-20190207094101-a32b78e5dd0a k8s.io/cli-runtime v0.0.0-20190207094101-a32b78e5dd0a
k8s.io/client-go v10.0.0+incompatible k8s.io/client-go v10.0.0+incompatible
k8s.io/component-base v0.0.0-20190313120452-4727f38490bc // indirect
k8s.io/klog v0.1.0 // indirect k8s.io/klog v0.1.0 // indirect
k8s.io/kube-openapi v0.0.0-20190215190454-ea82251f3668 // indirect k8s.io/kube-openapi v0.0.0-20190215190454-ea82251f3668 // indirect
k8s.io/kubernetes v1.13.3 k8s.io/kubernetes v1.13.3

15
go.sum
View File

@ -20,6 +20,8 @@ github.com/derailed/tview v0.1.4 h1:6ZtMtb5+2bbGNH7SldHGcVB8GnSTXKIQwKxWRNb6DxY=
github.com/derailed/tview v0.1.4/go.mod h1:oLBQyhVeXqeUYWDZk7/5NJVbbq/JFXm3W7oEoEtpmSc= github.com/derailed/tview v0.1.4/go.mod h1:oLBQyhVeXqeUYWDZk7/5NJVbbq/JFXm3W7oEoEtpmSc=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= 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/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
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/evanphx/json-patch v4.1.0+incompatible h1:K1MDoo4AZ4wU0GIU/fPmtZg7VpzLjCxu+UwBD1FvwOc= github.com/evanphx/json-patch v4.1.0+incompatible h1:K1MDoo4AZ4wU0GIU/fPmtZg7VpzLjCxu+UwBD1FvwOc=
github.com/evanphx/json-patch v4.1.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.1.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8= github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8=
@ -35,6 +37,8 @@ github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
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/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= 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.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
@ -85,12 +89,15 @@ github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.4.3/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/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
github.com/openzipkin/zipkin-go v0.1.3/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/openzipkin/zipkin-go v0.1.3/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/petergtz/pegomock v0.0.0-20181206220228-b113d17a7e81 h1:MhSbvsIs4KvpPYr4taOvb6j+r9VNbj/08AfjsKi+Ui0= github.com/petergtz/pegomock v0.0.0-20181206220228-b113d17a7e81 h1:MhSbvsIs4KvpPYr4taOvb6j+r9VNbj/08AfjsKi+Ui0=
github.com/petergtz/pegomock v0.0.0-20181206220228-b113d17a7e81/go.mod h1:nuBLWZpVyv/fLo56qTwt/AUau7jgouO1h7bEvZCq82o= github.com/petergtz/pegomock v0.0.0-20181206220228-b113d17a7e81/go.mod h1:nuBLWZpVyv/fLo56qTwt/AUau7jgouO1h7bEvZCq82o=
github.com/petergtz/pegomock v2.1.0+incompatible h1:oqn+Amy6vhpiuQ5PPaGd2PP2B839GC6DcV4AP/BOVCU=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
@ -106,6 +113,8 @@ github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a h1:9a8MnZMP0X2nLJdBg+pBmGgkJlSaKC2KaQmTCk1XDtE= 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-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/rivo/tview v0.0.0-20190213202703-b373355e9db4/go.mod h1:J4W+hErFfITUbyFAEXizpmkuxX7ZN56dopxHB4XQhMw= github.com/rivo/tview v0.0.0-20190213202703-b373355e9db4/go.mod h1:J4W+hErFfITUbyFAEXizpmkuxX7ZN56dopxHB4XQhMw=
github.com/robfig/cron v0.0.0-20180505203441-b41be1df6967 h1:x7xEyJDP7Hv3LVgvWhzioQqbC/KtuUhTigKlH/8ehhE=
github.com/robfig/cron v0.0.0-20180505203441-b41be1df6967/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
github.com/rs/zerolog v1.12.0 h1:aqZ1XRadoS8IBknR5IDFvGzbHly1X9ApIqOroooQF/c= github.com/rs/zerolog v1.12.0 h1:aqZ1XRadoS8IBknR5IDFvGzbHly1X9ApIqOroooQF/c=
github.com/rs/zerolog v1.12.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.12.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
@ -185,12 +194,18 @@ honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.0-20180920025451-e3ad64cb4ed3/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20180920025451-e3ad64cb4ed3/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
k8s.io/api v0.0.0-20190202010724-74b699b93c15 h1:AoUGjnJ3PJMFz+Rkp4lx3X+6mPUnY1MESJhbUSGX+pc= k8s.io/api v0.0.0-20190202010724-74b699b93c15 h1:AoUGjnJ3PJMFz+Rkp4lx3X+6mPUnY1MESJhbUSGX+pc=
k8s.io/api v0.0.0-20190202010724-74b699b93c15/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= k8s.io/api v0.0.0-20190202010724-74b699b93c15/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA=
k8s.io/apiextensions-apiserver v0.0.0-20190322231200-1c09d17c1352 h1:zukcRaXWkBtPh9YLgveTpIvNYzZ+DgAmpQAOxzIKB5c=
k8s.io/apiextensions-apiserver v0.0.0-20190322231200-1c09d17c1352/go.mod h1:IxkesAMoaCRoLrPJdZNZUQp9NfZnzqaVzLhb2VEQzXE=
k8s.io/apimachinery v0.0.0-20190207091153-095b9d203467 h1:zmz9UYvvXrK/B8EDqFuqreJEaXbIWdzEkNgWrN/Cd3o= k8s.io/apimachinery v0.0.0-20190207091153-095b9d203467 h1:zmz9UYvvXrK/B8EDqFuqreJEaXbIWdzEkNgWrN/Cd3o=
k8s.io/apimachinery v0.0.0-20190207091153-095b9d203467/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= k8s.io/apimachinery v0.0.0-20190207091153-095b9d203467/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0=
k8s.io/apiserver v0.0.0-20190322225753-5eae03fa38e7 h1:7ZrRe4kdzs+uEbmIRPaOrpinO3CBtQiY77I1FOv3nrU=
k8s.io/apiserver v0.0.0-20190322225753-5eae03fa38e7/go.mod h1:6bqaTSOSJavUIXUtfaR9Os9JtTCm8ZqH2SUl2S60C4w=
k8s.io/cli-runtime v0.0.0-20190207094101-a32b78e5dd0a h1:MrGQxLLZ09Bl5hYYU9VlKnhY60bpPlYd9yXOPnxkdc0= k8s.io/cli-runtime v0.0.0-20190207094101-a32b78e5dd0a h1:MrGQxLLZ09Bl5hYYU9VlKnhY60bpPlYd9yXOPnxkdc0=
k8s.io/cli-runtime v0.0.0-20190207094101-a32b78e5dd0a/go.mod h1:qWnH3/b8sp/l7EvlDh7ulDU3UWA4P4N1NFbEEP791tM= k8s.io/cli-runtime v0.0.0-20190207094101-a32b78e5dd0a/go.mod h1:qWnH3/b8sp/l7EvlDh7ulDU3UWA4P4N1NFbEEP791tM=
k8s.io/client-go v10.0.0+incompatible h1:F1IqCqw7oMBzDkqlcBymRq1450wD0eNqLE9jzUrIi34= k8s.io/client-go v10.0.0+incompatible h1:F1IqCqw7oMBzDkqlcBymRq1450wD0eNqLE9jzUrIi34=
k8s.io/client-go v10.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= k8s.io/client-go v10.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
k8s.io/component-base v0.0.0-20190313120452-4727f38490bc h1:wECJj/THUnRfyHajZrU4SmU2EIrSAHb3S9d2jTItVmo=
k8s.io/component-base v0.0.0-20190313120452-4727f38490bc/go.mod h1:DMaomcf3j3MM2j1FsvlLVVlc7wA2jPytEur3cP9zRxQ=
k8s.io/klog v0.1.0 h1:I5HMfc/DtuVaGR1KPwUrTc476K8NCqNBldC7H4dYEzk= k8s.io/klog v0.1.0 h1:I5HMfc/DtuVaGR1KPwUrTc476K8NCqNBldC7H4dYEzk=
k8s.io/klog v0.1.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.1.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/kube-openapi v0.0.0-20190215190454-ea82251f3668 h1:M80qeWaBNOX2Uc4plRHcb6k+3YE5VWMaJXKZo+tX9aU= k8s.io/kube-openapi v0.0.0-20190215190454-ea82251f3668 h1:M80qeWaBNOX2Uc4plRHcb6k+3YE5VWMaJXKZo+tX9aU=

View File

@ -1,5 +1,7 @@
package config package config
import "github.com/derailed/k9s/internal/k8s"
// Cluster tracks K9s cluster configuration. // Cluster tracks K9s cluster configuration.
type Cluster struct { type Cluster struct {
Namespace *Namespace `yaml:"namespace"` Namespace *Namespace `yaml:"namespace"`
@ -12,11 +14,11 @@ func NewCluster() *Cluster {
} }
// Validate a cluster config. // Validate a cluster config.
func (c *Cluster) Validate(ks KubeSettings) { func (c *Cluster) Validate(conn k8s.Connection, ks KubeSettings) {
if c.Namespace == nil { if c.Namespace == nil {
c.Namespace = NewNamespace() c.Namespace = NewNamespace()
} }
c.Namespace.Validate(ks) c.Namespace.Validate(conn, ks)
if c.View == nil { if c.View == nil {
c.View = NewView() c.View = NewView()

View File

@ -9,14 +9,15 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"github.com/derailed/k9s/internal/k8s"
"github.com/derailed/k9s/internal/resource" "github.com/derailed/k9s/internal/resource"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
v1 "k8s.io/api/core/v1"
"k8s.io/cli-runtime/pkg/genericclioptions"
) )
var ( var (
// Root K9s configuration.
Root *Config
// K9sHome represent K9s home directory. // K9sHome represent K9s home directory.
K9sHome = filepath.Join(mustK9sHome(), ".k9s") K9sHome = filepath.Join(mustK9sHome(), ".k9s")
// K9sConfigFile represents K9s config file location. // K9sConfigFile represents K9s config file location.
@ -31,12 +32,13 @@ type KubeSettings interface {
CurrentClusterName() (string, error) CurrentClusterName() (string, error)
CurrentNamespaceName() (string, error) CurrentNamespaceName() (string, error)
ClusterNames() ([]string, error) ClusterNames() ([]string, error)
NamespaceNames() ([]string, error) NamespaceNames(nn []v1.Namespace) []string
} }
// Config tracks K9s configuration options. // Config tracks K9s configuration options.
type Config struct { type Config struct {
K9s *K9s `yaml:"k9s"` K9s *K9s `yaml:"k9s"`
client k8s.Connection
settings KubeSettings settings KubeSettings
} }
@ -45,6 +47,42 @@ func NewConfig(ks KubeSettings) *Config {
return &Config{K9s: NewK9s(), settings: ks} return &Config{K9s: NewK9s(), settings: ks}
} }
func isSet(s *string) bool {
return s != nil && len(*s) > 0
}
// Refine the configuration based on cli args.
func (c *Config) Refine(flags *genericclioptions.ConfigFlags) {
cfg, err := flags.ToRawKubeConfigLoader().RawConfig()
if err != nil {
panic("Invalid configuration. Unable to connect to api")
}
if isSet(flags.Context) {
c.K9s.CurrentContext = *flags.Context
} else {
c.K9s.CurrentContext = cfg.CurrentContext
}
log.Debug().Msgf("Active Context `%v`", c.K9s.CurrentContext)
if ctx, ok := cfg.Contexts[c.K9s.CurrentContext]; ok {
c.K9s.CurrentCluster = ctx.Cluster
if len(ctx.Namespace) != 0 {
c.SetActiveNamespace(ctx.Namespace)
}
} else {
log.Panic().Msg(fmt.Sprintf("The specified context `%s does not exists in kubeconfig", c.K9s.CurrentContext))
}
if isSet(flags.Namespace) {
c.SetActiveNamespace(*flags.Namespace)
}
if isSet(flags.ClusterName) {
c.K9s.CurrentCluster = *flags.ClusterName
}
}
// Reset the context to the new current context/cluster. // Reset the context to the new current context/cluster.
// if it does not exist. // if it does not exist.
func (c *Config) Reset() { func (c *Config) Reset() {
@ -96,6 +134,16 @@ func (c *Config) SetActiveView(view string) {
c.K9s.ActiveCluster().View.Active = view c.K9s.ActiveCluster().View.Active = view
} }
// GetConnection return an api server connection.
func (c *Config) GetConnection() k8s.Connection {
return c.client
}
// SetConnection set an api server connection.
func (c *Config) SetConnection(conn k8s.Connection) {
c.client = conn
}
// Load K9s configuration from file // Load K9s configuration from file
func (c *Config) Load(path string) error { func (c *Config) Load(path string) error {
f, err := ioutil.ReadFile(path) f, err := ioutil.ReadFile(path)
@ -134,7 +182,7 @@ func (c *Config) SaveFile(path string) error {
// Validate the configuration. // Validate the configuration.
func (c *Config) Validate() { func (c *Config) Validate() {
c.K9s.Validate(c.settings) c.K9s.Validate(c.client, c.settings)
} }
// Dump debug... // Dump debug...

View File

@ -1,5 +1,7 @@
package config package config
import "github.com/derailed/k9s/internal/k8s"
const ( const (
defaultRefreshRate = 2 defaultRefreshRate = 2
defaultLogRequestSize = 200 defaultLogRequestSize = 200
@ -45,7 +47,7 @@ func (k *K9s) ActiveCluster() *Cluster {
} }
// Validate the current configuration. // Validate the current configuration.
func (k *K9s) Validate(ks KubeSettings) { func (k *K9s) Validate(c k8s.Connection, ks KubeSettings) {
if k.RefreshRate <= 0 { if k.RefreshRate <= 0 {
k.RefreshRate = defaultRefreshRate k.RefreshRate = defaultRefreshRate
} }
@ -87,5 +89,5 @@ func (k *K9s) Validate(ks KubeSettings) {
if _, ok := k.Clusters[k.CurrentCluster]; !ok { if _, ok := k.Clusters[k.CurrentCluster]; !ok {
k.Clusters[k.CurrentCluster] = NewCluster() k.Clusters[k.CurrentCluster] = NewCluster()
} }
k.Clusters[k.CurrentCluster].Validate(ks) k.Clusters[k.CurrentCluster].Validate(c, ks)
} }

View File

@ -1,7 +1,9 @@
package config package config
import ( import (
"github.com/derailed/k9s/internal/k8s"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
) )
const ( const (
@ -26,12 +28,13 @@ func NewNamespace() *Namespace {
} }
// Validate a namespace is setup correctly // Validate a namespace is setup correctly
func (n *Namespace) Validate(ks KubeSettings) { func (n *Namespace) Validate(c k8s.Connection, ks KubeSettings) {
nn, err := ks.NamespaceNames() nns, err := c.DialOrDie().CoreV1().Namespaces().List(metav1.ListOptions{})
if err != nil { if err != nil {
return return
} }
nn := ks.NamespaceNames(nns.Items)
if !n.isAllNamespace() && !InList(nn, n.Active) { if !n.isAllNamespace() && !InList(nn, n.Active) {
log.Debug().Msg("[Config] Validation error active namespace resetting to `default") log.Debug().Msg("[Config] Validation error active namespace resetting to `default")
n.Active = defaultNS n.Active = defaultNS

View File

@ -8,34 +8,50 @@ import (
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/genericclioptions/printers" "k8s.io/cli-runtime/pkg/genericclioptions/printers"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest"
"k8s.io/kubernetes/pkg/kubectl/describe" "k8s.io/kubernetes/pkg/kubectl/describe"
versioned "k8s.io/kubernetes/pkg/kubectl/describe/versioned" versioned "k8s.io/kubernetes/pkg/kubectl/describe/versioned"
v "k8s.io/metrics/pkg/client/clientset/versioned"
) )
type ( type (
// Creator can create a new resources. // Cruder represent a crudable Kubernetes resource.
Creator interface { Cruder interface {
NewInstance(interface{}) Columnar Get(ns string, name string) (interface{}, error)
List(ns string) (k8s.Collection, error)
Delete(ns string, name string) error
} }
// Caller can call Kubernetes verbs on a resource. // Connection represents a Kubenetes apiserver connection.
Caller interface { Connection interface {
k8s.Res Config() *k8s.Config
DialOrDie() kubernetes.Interface
SwitchContextOrDie(ctx string)
NSDialOrDie() dynamic.NamespaceableResourceInterface
RestConfigOrDie() *restclient.Config
MXDial() (*v.Clientset, error)
DynDialOrDie() dynamic.Interface
HasMetrics() bool
IsNamespaced(n string) bool
SupportsResource(group string) bool
} }
// APIFn knows how to call K8s api server. // Factory creates new tabular resources.
APIFn func() k8s.Res Factory interface {
New(interface{}) Columnar
// InstanceFn instantiates a concrete resource. }
InstanceFn func(interface{}) Columnar
// Base resource. // Base resource.
Base struct { Base struct {
path string Factory
caller Caller connection Connection
creator Creator path string
resource Cruder
} }
) )
@ -44,32 +60,39 @@ func (b *Base) Name() string {
return b.path return b.path
} }
// ExtFields returns extended fields in relation to headers.
func (*Base) ExtFields() Properties {
return Properties{}
}
// Get a resource by name // Get a resource by name
func (b *Base) Get(path string) (Columnar, error) { func (b *Base) Get(path string) (Columnar, error) {
ns, n := namespaced(path) ns, n := namespaced(path)
i, err := b.caller.Get(ns, n) i, err := b.resource.Get(ns, n)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return b.creator.NewInstance(i), nil
return b.New(i), nil
} }
// List all resources // List all resources
func (b *Base) List(ns string) (Columnars, error) { func (b *Base) List(ns string) (Columnars, error) {
ii, err := b.caller.List(ns) ii, err := b.resource.List(ns)
if err != nil { if err != nil {
return nil, err return nil, err
} }
cc := make(Columnars, 0, len(ii)) cc := make(Columnars, 0, len(ii))
for i := 0; i < len(ii); i++ { for i := 0; i < len(ii); i++ {
cc = append(cc, b.creator.NewInstance(ii[i])) cc = append(cc, b.New(ii[i]))
} }
return cc, nil return cc, nil
} }
// Describe a given resource. // Describe a given resource.
func (b *Base) Describe(kind, pa string) (string, error) { func (b *Base) Describe(kind, pa string, flags *genericclioptions.ConfigFlags) (string, error) {
ns, n := namespaced(pa) ns, n := namespaced(pa)
mapping, err := k8s.RestMapping.Find(kind) mapping, err := k8s.RestMapping.Find(kind)
@ -77,20 +100,22 @@ func (b *Base) Describe(kind, pa string) (string, error) {
return "", err return "", err
} }
d, err := versioned.Describer(k8s.KubeConfig.Flags(), mapping) d, err := versioned.Describer(flags, mapping)
if err != nil { if err != nil {
return "", err return "", err
} }
opts := describe.DescriberSettings{ opts := describe.DescriberSettings{
ShowEvents: true, ShowEvents: true,
} }
return d.Describe(ns, n, opts) return d.Describe(ns, n, opts)
} }
// Delete a resource by name. // Delete a resource by name.
func (b *Base) Delete(path string) error { func (b *Base) Delete(path string) error {
ns, n := namespaced(path) ns, n := namespaced(path)
return b.caller.Delete(ns, n)
return b.resource.Delete(ns, n)
} }
func (*Base) namespacedName(m metav1.ObjectMeta) string { func (*Base) namespacedName(m metav1.ObjectMeta) string {
@ -107,5 +132,6 @@ func (*Base) marshalObject(o runtime.Object) (string, error) {
log.Error().Msgf("Marshal Error %v", err) log.Error().Msgf("Marshal Error %v", err)
return "", err return "", err
} }
return buff.String(), nil return buff.String(), nil
} }

View File

@ -2,39 +2,52 @@ package resource
import ( import (
"github.com/derailed/k9s/internal/k8s" "github.com/derailed/k9s/internal/k8s"
"github.com/rs/zerolog"
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
mv1beta1 "k8s.io/metrics/pkg/apis/metrics/v1beta1"
) )
type ( type (
// ClusterIfc represents a cluster. // ClusterMeta represents metadata about a Kubernetes cluster.
ClusterIfc interface { ClusterMeta interface {
Connection
Version() (string, error) Version() (string, error)
ContextName() string ContextName() string
ClusterName() string ClusterName() string
UserName() string UserName() string
} }
// MetricsIfc represents a metrics server. // MetricsServer gather metrics information from pods and nodes.
MetricsIfc interface { MetricsServer interface {
NodeMetrics() (k8s.Metric, error) MetricsService
PerNodeMetrics([]v1.Node) (map[string]k8s.Metric, error)
PodMetrics() (map[string]k8s.Metric, error) ClusterLoad([]v1.Node, []mv1beta1.NodeMetrics) k8s.ClusterMetrics
NodesMetrics([]v1.Node, []mv1beta1.NodeMetrics, k8s.NodesMetrics)
PodsMetrics([]mv1beta1.PodMetrics, k8s.PodsMetrics)
}
// MetricsService calls the metrics server for metrics info.
MetricsService interface {
HasMetrics() bool
FetchNodesMetrics() ([]mv1beta1.NodeMetrics, error)
FetchPodsMetrics(ns string) ([]mv1beta1.PodMetrics, error)
} }
// Cluster represents a kubernetes resource. // Cluster represents a kubernetes resource.
Cluster struct { Cluster struct {
api ClusterIfc api ClusterMeta
mx MetricsIfc mx MetricsServer
} }
) )
// NewCluster returns a new cluster info resource. // NewCluster returns a new cluster info resource.
func NewCluster() *Cluster { func NewCluster(c Connection, log *zerolog.Logger) *Cluster {
return NewClusterWithArgs(k8s.NewCluster(), k8s.NewMetricsServer()) return NewClusterWithArgs(k8s.NewCluster(c, log), k8s.NewMetricsServer(c))
} }
// NewClusterWithArgs for tests only! // NewClusterWithArgs for tests only!
func NewClusterWithArgs(ci ClusterIfc, mx MetricsIfc) *Cluster { func NewClusterWithArgs(ci ClusterMeta, mx MetricsServer) *Cluster {
return &Cluster{api: ci, mx: mx} return &Cluster{api: ci, mx: mx}
} }
@ -44,6 +57,7 @@ func (c *Cluster) Version() string {
if err != nil { if err != nil {
return "n/a" return "n/a"
} }
return info return info
} }
@ -63,6 +77,25 @@ func (c *Cluster) UserName() string {
} }
// Metrics gathers node level metrics and compute utilization percentages. // Metrics gathers node level metrics and compute utilization percentages.
func (c *Cluster) Metrics() (k8s.Metric, error) { func (c *Cluster) Metrics(nodes []v1.Node, nmx []mv1beta1.NodeMetrics) k8s.ClusterMetrics {
return c.mx.NodeMetrics() return c.mx.ClusterLoad(nodes, nmx)
}
// GetNodesMetrics fetch all nodes metrics.
func (c *Cluster) GetNodesMetrics() ([]mv1beta1.NodeMetrics, error) {
return c.mx.FetchNodesMetrics()
}
// GetNodes fetch all available nodes.
func (c *Cluster) GetNodes() ([]v1.Node, error) {
nn, err := k8s.NewNode(c.api).List("")
if err != nil {
return nil, err
}
nodes := make([]v1.Node, 0, len(nn))
for _, n := range nn {
nodes = append(nodes, n.(v1.Node))
}
return nodes, nil
} }

View File

@ -8,12 +8,14 @@ import (
"github.com/derailed/k9s/internal/resource" "github.com/derailed/k9s/internal/resource"
m "github.com/petergtz/pegomock" m "github.com/petergtz/pegomock"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
v1 "k8s.io/api/core/v1"
mv1beta1 "k8s.io/metrics/pkg/apis/metrics/v1beta1"
) )
func TestClusterVersion(t *testing.T) { func TestClusterVersion(t *testing.T) {
setup(t) setup(t)
cIfc, mxIfc := NewMockClusterIfc(), NewMockMetricsIfc() cIfc, mxIfc := NewMockClusterMeta(), NewMockMetricsServer()
m.When(cIfc.Version()).ThenReturn("1.2.3", nil) m.When(cIfc.Version()).ThenReturn("1.2.3", nil)
ci := resource.NewClusterWithArgs(cIfc, mxIfc) ci := resource.NewClusterWithArgs(cIfc, mxIfc)
@ -23,7 +25,7 @@ func TestClusterVersion(t *testing.T) {
func TestClusterNoVersion(t *testing.T) { func TestClusterNoVersion(t *testing.T) {
setup(t) setup(t)
cIfc, mxIfc := NewMockClusterIfc(), NewMockMetricsIfc() cIfc, mxIfc := NewMockClusterMeta(), NewMockMetricsServer()
m.When(cIfc.Version()).ThenReturn("bad", fmt.Errorf("No data")) m.When(cIfc.Version()).ThenReturn("bad", fmt.Errorf("No data"))
ci := resource.NewClusterWithArgs(cIfc, mxIfc) ci := resource.NewClusterWithArgs(cIfc, mxIfc)
@ -33,7 +35,7 @@ func TestClusterNoVersion(t *testing.T) {
func TestClusterName(t *testing.T) { func TestClusterName(t *testing.T) {
setup(t) setup(t)
cIfc, mxIfc := NewMockClusterIfc(), NewMockMetricsIfc() cIfc, mxIfc := NewMockClusterMeta(), NewMockMetricsServer()
m.When(cIfc.ClusterName()).ThenReturn("fred") m.When(cIfc.ClusterName()).ThenReturn("fred")
ci := resource.NewClusterWithArgs(cIfc, mxIfc) ci := resource.NewClusterWithArgs(cIfc, mxIfc)
@ -43,13 +45,11 @@ func TestClusterName(t *testing.T) {
func TestClusterMetrics(t *testing.T) { func TestClusterMetrics(t *testing.T) {
setup(t) setup(t)
cIfc, mxIfc := NewMockClusterIfc(), NewMockMetricsIfc() cIfc, mxIfc := NewMockClusterMeta(), NewMockMetricsServer()
m.When(mxIfc.NodeMetrics()).ThenReturn(testMetric(), nil) m.When(mxIfc.ClusterLoad([]v1.Node{}, []mv1beta1.NodeMetrics{})).ThenReturn(clusterMetric())
c := resource.NewClusterWithArgs(cIfc, mxIfc) c := resource.NewClusterWithArgs(cIfc, mxIfc)
m, err := c.Metrics() assert.Equal(t, clusterMetric(), c.Metrics([]v1.Node{}, []mv1beta1.NodeMetrics{}))
assert.Nil(t, err)
assert.Equal(t, testMetric(), m)
} }
// Helpers... // Helpers...
@ -61,11 +61,9 @@ func setup(t *testing.T) {
}) })
} }
func testMetric() k8s.Metric { func clusterMetric() k8s.ClusterMetrics {
return k8s.Metric{ return k8s.ClusterMetrics{
CPU: "100m", PercCPU: 100,
AvailCPU: "1000m", PercMEM: 1000,
Mem: "256Gi",
AvailMem: "512Gi",
} }
} }

View File

@ -15,51 +15,43 @@ type ConfigMap struct {
} }
// NewConfigMapList returns a new resource list. // NewConfigMapList returns a new resource list.
func NewConfigMapList(ns string) List { func NewConfigMapList(c k8s.Connection, ns string) List {
return NewConfigMapListWithArgs(ns, NewConfigMap()) return newList(
} ns,
"cm",
// NewConfigMapListWithArgs returns a new resource list. NewConfigMap(c),
func NewConfigMapListWithArgs(ns string, res Resource) List { AllVerbsAccess|DescribeAccess,
return newList(ns, "cm", res, AllVerbsAccess|DescribeAccess) )
} }
// NewConfigMap instantiates a new ConfigMap. // NewConfigMap instantiates a new ConfigMap.
func NewConfigMap() *ConfigMap { func NewConfigMap(c k8s.Connection) *ConfigMap {
return NewConfigMapWithArgs(k8s.NewConfigMap()) m := &ConfigMap{&Base{connection: c, resource: k8s.NewConfigMap(c)}, nil}
m.Factory = m
return m
} }
// NewConfigMapWithArgs instantiates a new ConfigMap. // New builds a new ConfigMap instance from a k8s resource.
func NewConfigMapWithArgs(r k8s.Res) *ConfigMap { func (r *ConfigMap) New(i interface{}) Columnar {
cm := &ConfigMap{ cm := NewConfigMap(r.connection)
Base: &Base{ switch instance := i.(type) {
caller: r,
},
}
cm.creator = cm
return cm
}
// NewInstance builds a new ConfigMap instance from a k8s resource.
func (*ConfigMap) NewInstance(i interface{}) Columnar {
cm := NewConfigMap()
switch i.(type) {
case *v1.ConfigMap: case *v1.ConfigMap:
cm.instance = i.(*v1.ConfigMap) cm.instance = instance
case v1.ConfigMap: case v1.ConfigMap:
ii := i.(v1.ConfigMap) cm.instance = &instance
cm.instance = &ii
default: default:
log.Fatalf("Unknown %#v", i) log.Fatalf("Unknown %#v", i)
} }
cm.path = cm.namespacedName(cm.instance.ObjectMeta) cm.path = cm.namespacedName(cm.instance.ObjectMeta)
return cm return cm
} }
// Marshal resource to yaml. // Marshal resource to yaml.
func (r *ConfigMap) Marshal(path string) (string, error) { func (r *ConfigMap) Marshal(path string) (string, error) {
ns, n := namespaced(path) ns, n := namespaced(path)
i, err := r.caller.Get(ns, n) i, err := r.resource.Get(ns, n)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -67,6 +59,7 @@ func (r *ConfigMap) Marshal(path string) (string, error) {
cm := i.(*v1.ConfigMap) cm := i.(*v1.ConfigMap)
cm.TypeMeta.APIVersion = "v1" cm.TypeMeta.APIVersion = "v1"
cm.TypeMeta.Kind = "ConfigMap" cm.TypeMeta.Kind = "ConfigMap"
return r.marshalObject(cm) return r.marshalObject(cm)
} }
@ -76,6 +69,7 @@ func (*ConfigMap) Header(ns string) Row {
if ns == AllNamespaces { if ns == AllNamespaces {
hh = append(hh, "NAMESPACE") hh = append(hh, "NAMESPACE")
} }
return append(hh, "NAME", "DATA", "AGE") return append(hh, "NAME", "DATA", "AGE")
} }
@ -93,8 +87,3 @@ func (r *ConfigMap) Fields(ns string) Row {
toAge(i.ObjectMeta.CreationTimestamp), toAge(i.ObjectMeta.CreationTimestamp),
) )
} }
// ExtFields returns extended fields in relation to headers.
func (*ConfigMap) ExtFields() Properties {
return Properties{}
}

View File

@ -41,36 +41,39 @@ func TestCMFields(t *testing.T) {
func TestCMGet(t *testing.T) { func TestCMGet(t *testing.T) {
setup(t) setup(t)
ca := NewMockCaller() conn := NewMockConnection()
ca := NewMockCruder()
m.When(ca.Get("blee", "fred")).ThenReturn(k8sCM(), nil) m.When(ca.Get("blee", "fred")).ThenReturn(k8sCM(), nil)
cm := resource.NewConfigMapWithArgs(ca) cm := resource.NewConfigMap(conn)
ma, err := cm.Get("blee/fred") ma, err := cm.Get("blee/fred")
assert.Nil(t, err) assert.Nil(t, err)
ca.VerifyWasCalledOnce().Get("blee", "fred") ca.VerifyWasCalledOnce().Get("blee", "fred")
assert.Equal(t, cm.NewInstance(k8sCM()), ma) assert.Equal(t, cm.New(k8sCM()), ma)
} }
func TestCMList(t *testing.T) { func TestCMList(t *testing.T) {
setup(t) setup(t)
ca := NewMockCaller() conn := NewMockConnection()
ca := NewMockCruder()
m.When(ca.List("blee")).ThenReturn(k8s.Collection{*k8sCM()}, nil) m.When(ca.List("blee")).ThenReturn(k8s.Collection{*k8sCM()}, nil)
cm := resource.NewConfigMapWithArgs(ca) cm := resource.NewConfigMap(conn)
ma, err := cm.List("blee") ma, err := cm.List("blee")
assert.Nil(t, err) assert.Nil(t, err)
ca.VerifyWasCalledOnce().List("blee") ca.VerifyWasCalledOnce().List("blee")
assert.Equal(t, resource.Columnars{cm.NewInstance(k8sCM())}, ma) assert.Equal(t, resource.Columnars{cm.New(k8sCM())}, ma)
} }
func TestCMDelete(t *testing.T) { func TestCMDelete(t *testing.T) {
setup(t) setup(t)
ca := NewMockCaller() conn := NewMockConnection()
ca := NewMockCruder()
m.When(ca.Delete("blee", "fred")).ThenReturn(nil) m.When(ca.Delete("blee", "fred")).ThenReturn(nil)
cm := resource.NewConfigMapWithArgs(ca) cm := resource.NewConfigMap(conn)
assert.Nil(t, cm.Delete("blee/fred")) assert.Nil(t, cm.Delete("blee/fred"))
ca.VerifyWasCalledOnce().Delete("blee", "fred") ca.VerifyWasCalledOnce().Delete("blee", "fred")
} }
@ -78,10 +81,11 @@ func TestCMDelete(t *testing.T) {
func TestCMMarshal(t *testing.T) { func TestCMMarshal(t *testing.T) {
setup(t) setup(t)
ca := NewMockCaller() conn := NewMockConnection()
ca := NewMockCruder()
m.When(ca.Get("blee", "fred")).ThenReturn(k8sCM(), nil) m.When(ca.Get("blee", "fred")).ThenReturn(k8sCM(), nil)
cm := resource.NewConfigMapWithArgs(ca) cm := resource.NewConfigMap(conn)
ma, err := cm.Marshal("blee/fred") ma, err := cm.Marshal("blee/fred")
ca.VerifyWasCalledOnce().Get("blee", "fred") ca.VerifyWasCalledOnce().Get("blee", "fred")
@ -92,48 +96,38 @@ func TestCMMarshal(t *testing.T) {
func TestCMListHasName(t *testing.T) { func TestCMListHasName(t *testing.T) {
setup(t) setup(t)
ca := NewMockCaller() conn := NewMockConnection()
l := resource.NewConfigMapListWithArgs("blee", resource.NewConfigMapWithArgs(ca)) ca := NewMockCruder()
l := resource.NewConfigMapList(conn, "blee")
assert.Equal(t, "cm", l.GetName()) assert.Equal(t, "cm", l.GetName())
} }
func TestCMListHasNamespace(t *testing.T) { func TestCMListHasNamespace(t *testing.T) {
setup(t) setup(t)
ca := NewMockCaller() conn := NewMockConnection()
l := resource.NewConfigMapListWithArgs("blee", resource.NewConfigMapWithArgs(ca)) ca := NewMockCruder()
l := resource.NewConfigMapList(conn, "blee")
assert.Equal(t, "blee", l.GetNamespace()) assert.Equal(t, "blee", l.GetNamespace())
} }
func TestCMListHasResource(t *testing.T) { func TestCMListHasResource(t *testing.T) {
setup(t) setup(t)
ca := NewMockCaller() conn := NewMockConnection()
l := resource.NewConfigMapListWithArgs("blee", resource.NewConfigMapWithArgs(ca)) ca := NewMockCruder()
l := resource.NewConfigMapList(conn, "blee")
assert.NotNil(t, l.Resource()) assert.NotNil(t, l.Resource())
} }
func TestCMListDescribe(t *testing.T) {
setup(t)
ca := NewMockCaller()
m.When(ca.Get("blee", "fred")).ThenReturn(k8sCM(), nil)
l := resource.NewConfigMapListWithArgs("blee", resource.NewConfigMapWithArgs(ca))
props, err := l.Describe("blee/fred")
ca.VerifyWasCalledOnce().Get("blee", "fred")
assert.Nil(t, err)
assert.Equal(t, 0, len(props))
}
func TestCMListData(t *testing.T) { func TestCMListData(t *testing.T) {
setup(t) setup(t)
ca := NewMockCaller() conn := NewMockConnection()
ca := NewMockCruder()
m.When(ca.List("blee")).ThenReturn(k8s.Collection{*k8sCM()}, nil) m.When(ca.List("blee")).ThenReturn(k8s.Collection{*k8sCM()}, nil)
l := resource.NewConfigMapListWithArgs("blee", resource.NewConfigMapWithArgs(ca)) l := resource.NewConfigMapList(conn, "blee")
// Make sure we can get deltas! // Make sure we can get deltas!
for i := 0; i < 2; i++ { for i := 0; i < 2; i++ {
err := l.Reconcile() err := l.Reconcile()
@ -146,7 +140,6 @@ func TestCMListData(t *testing.T) {
assert.Equal(t, 1, len(td.Rows)) assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, "blee", l.GetNamespace()) assert.Equal(t, "blee", l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"] row := td.Rows["blee/fred"]
assert.Equal(t, 3, len(row.Deltas)) assert.Equal(t, 3, len(row.Deltas))
for _, d := range row.Deltas { for _, d := range row.Deltas {
@ -158,7 +151,8 @@ func TestCMListData(t *testing.T) {
// Helpers... // Helpers...
func newConfigMap() resource.Columnar { func newConfigMap() resource.Columnar {
return resource.NewConfigMap().NewInstance(k8sCM()) conn := NewMockConnection()
return resource.NewConfigMap(conn).New(k8sCM())
} }
func k8sCM() *v1.ConfigMap { func k8sCM() *v1.ConfigMap {

View File

@ -7,6 +7,7 @@ import (
// SwitchableRes represents a resource that can be switched. // SwitchableRes represents a resource that can be switched.
type SwitchableRes interface { type SwitchableRes interface {
k8s.Connection
k8s.ContextRes k8s.ContextRes
} }
@ -17,50 +18,37 @@ type Context struct {
} }
// NewContextList returns a new resource list. // NewContextList returns a new resource list.
func NewContextList(ns string) List { func NewContextList(c k8s.Connection, ns string) List {
return NewContextListWithArgs(ns, NewContext()) return newList(NotNamespaced, "ctx", NewContext(c), SwitchAccess)
}
// NewContextListWithArgs returns a new resource list.
func NewContextListWithArgs(ns string, res Resource) List {
return newList(NotNamespaced, "ctx", res, SwitchAccess)
} }
// NewContext instantiates a new Context. // NewContext instantiates a new Context.
func NewContext() *Context { func NewContext(c k8s.Connection) *Context {
return NewContextWithArgs(k8s.NewContext().(SwitchableRes)) ctx := &Context{&Base{connection: c, resource: k8s.NewContext(c)}, nil}
} ctx.Factory = ctx
// NewContextWithArgs instantiates a new Context.
func NewContextWithArgs(r SwitchableRes) *Context {
ctx := &Context{
Base: &Base{
caller: r,
},
}
ctx.creator = ctx
return ctx return ctx
} }
// NewInstance builds a new Context instance from a k8s resource. // New builds a new Context instance from a k8s resource.
func (r *Context) NewInstance(i interface{}) Columnar { func (r *Context) New(i interface{}) Columnar {
c := NewContext() c := NewContext(r.connection)
switch i.(type) { switch instance := i.(type) {
case *k8s.NamedContext: case *k8s.NamedContext:
c.instance = i.(*k8s.NamedContext) c.instance = instance
case k8s.NamedContext: case k8s.NamedContext:
ii := i.(k8s.NamedContext) c.instance = &instance
c.instance = &ii
default: default:
log.Fatal().Msgf("unknown context type %#v", i) log.Fatal().Msgf("unknown context type %#v", i)
} }
c.path = c.instance.Name c.path = c.instance.Name
return c return c
} }
// Switch out current context. // Switch out current context.
func (r *Context) Switch(c string) error { func (r *Context) Switch(c string) error {
return r.caller.(k8s.ContextRes).Switch(c) return r.resource.(k8s.ContextRes).Switch(c)
} }
// Marshal the resource to yaml. // Marshal the resource to yaml.
@ -90,8 +78,3 @@ func (r *Context) Fields(ns string) Row {
i.Context.Namespace, i.Context.Namespace,
) )
} }
// ExtFields returns extended fields in relation to headers.
func (*Context) ExtFields() Properties {
return Properties{}
}

View File

@ -78,19 +78,6 @@ func TestCTXListHasResource(t *testing.T) {
assert.NotNil(t, l.Resource()) assert.NotNil(t, l.Resource())
} }
func TestCTXListDescribe(t *testing.T) {
setup(t)
ca := NewMockSwitchableRes()
m.When(ca.Get("blee", "fred")).ThenReturn(k8sNamedCTX(), nil)
l := resource.NewContextListWithArgs("blee", resource.NewContextWithArgs(ca))
props, err := l.Describe("blee/fred")
assert.Nil(t, err)
assert.Equal(t, 0, len(props))
ca.VerifyWasCalledOnce().Get("blee", "fred")
}
// Helpers... // Helpers...
func newContext() resource.Columnar { func newContext() resource.Columnar {

View File

@ -13,51 +13,43 @@ type ClusterRole struct {
} }
// NewClusterRoleList returns a new resource list. // NewClusterRoleList returns a new resource list.
func NewClusterRoleList(ns string) List { func NewClusterRoleList(c k8s.Connection, ns string) List {
return NewClusterRoleListWithArgs(ns, NewClusterRole()) return newList(
} NotNamespaced,
"clusterrole",
// NewClusterRoleListWithArgs returns a new resource list. NewClusterRole(c),
func NewClusterRoleListWithArgs(ns string, res Resource) List { CRUDAccess|DescribeAccess,
return newList(NotNamespaced, "clusterrole", res, CRUDAccess|DescribeAccess) )
} }
// NewClusterRole instantiates a new ClusterRole. // NewClusterRole instantiates a new ClusterRole.
func NewClusterRole() *ClusterRole { func NewClusterRole(c k8s.Connection) *ClusterRole {
return NewClusterRoleWithArgs(k8s.NewClusterRole()) cr := &ClusterRole{&Base{connection: c, resource: k8s.NewClusterRole(c)}, nil}
cr.Factory = cr
return cr
} }
// NewClusterRoleWithArgs instantiates a new Context. // New builds a new ClusterRole instance from a k8s resource.
func NewClusterRoleWithArgs(r k8s.Res) *ClusterRole { func (r *ClusterRole) New(i interface{}) Columnar {
ctx := &ClusterRole{ c := NewClusterRole(r.connection)
Base: &Base{ switch instance := i.(type) {
caller: r,
},
}
ctx.creator = ctx
return ctx
}
// NewInstance builds a new Context instance from a k8s resource.
func (r *ClusterRole) NewInstance(i interface{}) Columnar {
c := NewClusterRole()
switch i.(type) {
case *v1.ClusterRole: case *v1.ClusterRole:
c.instance = i.(*v1.ClusterRole) c.instance = instance
case v1.ClusterRole: case v1.ClusterRole:
ii := i.(v1.ClusterRole) c.instance = &instance
c.instance = &ii
default: default:
log.Fatal().Msgf("unknown context type %#v", i) log.Fatal().Msgf("unknown context type %#v", i)
} }
c.path = c.instance.Name c.path = c.instance.Name
return c return c
} }
// Marshal resource to yaml. // Marshal resource to yaml.
func (r *ClusterRole) Marshal(path string) (string, error) { func (r *ClusterRole) Marshal(path string) (string, error) {
ns, n := namespaced(path) ns, n := namespaced(path)
i, err := r.caller.Get(ns, n) i, err := r.resource.Get(ns, n)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -65,6 +57,7 @@ func (r *ClusterRole) Marshal(path string) (string, error) {
cr := i.(*v1.ClusterRole) cr := i.(*v1.ClusterRole)
cr.TypeMeta.APIVersion = "rbac.authorization.k8s.io/v1" cr.TypeMeta.APIVersion = "rbac.authorization.k8s.io/v1"
cr.TypeMeta.Kind = "ClusterRole" cr.TypeMeta.Kind = "ClusterRole"
return r.marshalObject(cr) return r.marshalObject(cr)
} }
@ -83,8 +76,3 @@ func (r *ClusterRole) Fields(ns string) Row {
toAge(i.ObjectMeta.CreationTimestamp), toAge(i.ObjectMeta.CreationTimestamp),
) )
} }
// ExtFields returns extended fields in relation to headers.
func (*ClusterRole) ExtFields() Properties {
return Properties{}
}

View File

@ -13,51 +13,43 @@ type ClusterRoleBinding struct {
} }
// NewClusterRoleBindingList returns a new resource list. // NewClusterRoleBindingList returns a new resource list.
func NewClusterRoleBindingList(ns string) List { func NewClusterRoleBindingList(c k8s.Connection, _ string) List {
return NewClusterRoleBindingListWithArgs(ns, NewClusterRoleBinding()) return newList(
} NotNamespaced,
"ctx",
// NewClusterRoleBindingListWithArgs returns a new resource list. NewClusterRoleBinding(c),
func NewClusterRoleBindingListWithArgs(ns string, res Resource) List { SwitchAccess|ViewAccess|DeleteAccess|DescribeAccess,
return newList(NotNamespaced, "ctx", res, SwitchAccess|ViewAccess|DeleteAccess|DescribeAccess) )
} }
// NewClusterRoleBinding instantiates a new ClusterRoleBinding. // NewClusterRoleBinding instantiates a new ClusterRoleBinding.
func NewClusterRoleBinding() *ClusterRoleBinding { func NewClusterRoleBinding(c k8s.Connection) *ClusterRoleBinding {
return NewClusterRoleBindingWithArgs(k8s.NewClusterRoleBinding()) crb := &ClusterRoleBinding{&Base{connection: c, resource: k8s.NewClusterRoleBinding(c)}, nil}
crb.Factory = crb
return crb
} }
// NewClusterRoleBindingWithArgs instantiates a new Context. // New builds a new tabular instance from a k8s resource.
func NewClusterRoleBindingWithArgs(r k8s.Res) *ClusterRoleBinding { func (r *ClusterRoleBinding) New(i interface{}) Columnar {
ctx := &ClusterRoleBinding{ crb := NewClusterRoleBinding(r.connection)
Base: &Base{ switch instance := i.(type) {
caller: r,
},
}
ctx.creator = ctx
return ctx
}
// NewInstance builds a new Context instance from a k8s resource.
func (r *ClusterRoleBinding) NewInstance(i interface{}) Columnar {
c := NewClusterRoleBinding()
switch i.(type) {
case *v1.ClusterRoleBinding: case *v1.ClusterRoleBinding:
c.instance = i.(*v1.ClusterRoleBinding) crb.instance = instance
case v1.ClusterRoleBinding: case v1.ClusterRoleBinding:
ii := i.(v1.ClusterRoleBinding) crb.instance = &instance
c.instance = &ii
default: default:
log.Fatal().Msgf("unknown context type %#v", i) log.Fatal().Msgf("unknown context type %#v", i)
} }
c.path = c.instance.Name crb.path = crb.instance.Name
return c
return crb
} }
// Marshal resource to yaml. // Marshal resource to yaml.
func (r *ClusterRoleBinding) Marshal(path string) (string, error) { func (r *ClusterRoleBinding) Marshal(path string) (string, error) {
ns, n := namespaced(path) ns, n := namespaced(path)
i, err := r.caller.Get(ns, n) i, err := r.resource.Get(ns, n)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -65,6 +57,7 @@ func (r *ClusterRoleBinding) Marshal(path string) (string, error) {
crb := i.(*v1.ClusterRoleBinding) crb := i.(*v1.ClusterRoleBinding)
crb.TypeMeta.APIVersion = "rbac.authorization.k8s.io/v1" crb.TypeMeta.APIVersion = "rbac.authorization.k8s.io/v1"
crb.TypeMeta.Kind = "ClusterRoleBinding" crb.TypeMeta.Kind = "ClusterRoleBinding"
return r.marshalObject(crb) return r.marshalObject(crb)
} }
@ -76,15 +69,9 @@ func (*ClusterRoleBinding) Header(_ string) Row {
// Fields retrieves displayable fields. // Fields retrieves displayable fields.
func (r *ClusterRoleBinding) Fields(ns string) Row { func (r *ClusterRoleBinding) Fields(ns string) Row {
ff := make(Row, 0, len(r.Header(ns))) ff := make(Row, 0, len(r.Header(ns)))
i := r.instance
return append(ff, return append(ff,
i.Name, r.instance.Name,
toAge(i.ObjectMeta.CreationTimestamp), toAge(r.instance.ObjectMeta.CreationTimestamp),
) )
} }
// ExtFields returns extended fields in relation to headers.
func (*ClusterRoleBinding) ExtFields() Properties {
return Properties{}
}

View File

@ -55,7 +55,6 @@ func TestCRBListData(t *testing.T) {
td := l.Data() td := l.Data()
assert.Equal(t, 1, len(td.Rows)) assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.NotNamespaced, l.GetNamespace()) assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["fred"] row := td.Rows["fred"]
assert.Equal(t, 2, len(row.Deltas)) assert.Equal(t, 2, len(row.Deltas))
for _, d := range row.Deltas { for _, d := range row.Deltas {

View File

@ -74,7 +74,6 @@ func TestCRListData(t *testing.T) {
td := l.Data() td := l.Data()
assert.Equal(t, 1, len(td.Rows)) assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.NotNamespaced, l.GetNamespace()) assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["fred"] row := td.Rows["fred"]
assert.Equal(t, 2, len(row.Deltas)) assert.Equal(t, 2, len(row.Deltas))
for _, d := range row.Deltas { for _, d := range row.Deltas {
@ -83,19 +82,6 @@ func TestCRListData(t *testing.T) {
assert.Equal(t, resource.Row{"fred" + strings.Repeat(" ", 66)}, row.Fields[:1]) assert.Equal(t, resource.Row{"fred" + strings.Repeat(" ", 66)}, row.Fields[:1])
} }
func TestCRListDescribe(t *testing.T) {
setup(t)
ca := NewMockCaller()
m.When(ca.Get("blee", "fred")).ThenReturn(k8sCR(), nil)
l := resource.NewClusterRoleListWithArgs("blee", resource.NewClusterRoleWithArgs(ca))
props, err := l.Describe("blee/fred")
ca.VerifyWasCalledOnce().Get("blee", "fred")
assert.Nil(t, err)
assert.Equal(t, 0, len(props))
}
// Helpers... // Helpers...
func k8sCR() *rbacv1.ClusterRole { func k8sCR() *rbacv1.ClusterRole {

View File

@ -17,42 +17,33 @@ type CRD struct {
} }
// NewCRDList returns a new resource list. // NewCRDList returns a new resource list.
func NewCRDList(ns string) List { func NewCRDList(c k8s.Connection, ns string) List {
return NewCRDListWithArgs(ns, NewCRD()) return newList(
} NotNamespaced,
"crd",
// NewCRDListWithArgs returns a new resource list. NewCRD(c),
func NewCRDListWithArgs(ns string, res Resource) List { CRUDAccess|DescribeAccess,
return newList(NotNamespaced, "crd", res, CRUDAccess|DescribeAccess) )
} }
// NewCRD instantiates a new CRD. // NewCRD instantiates a new CRD.
func NewCRD() *CRD { func NewCRD(c k8s.Connection) *CRD {
return NewCRDWithArgs(k8s.NewCRD()) crd := &CRD{&Base{connection: c, resource: k8s.NewCRD(c)}, nil}
crd.Factory = crd
return crd
} }
// NewCRDWithArgs instantiates a new Context. // New builds a new CRD instance from a k8s resource.
func NewCRDWithArgs(r k8s.Res) *CRD { func (r *CRD) New(i interface{}) Columnar {
ctx := &CRD{ c := NewCRD(r.connection)
Base: &Base{ switch instance := i.(type) {
caller: r,
},
}
ctx.creator = ctx
return ctx
}
// NewInstance builds a new Context instance from a k8s resource.
func (r *CRD) NewInstance(i interface{}) Columnar {
c := NewCRD()
switch i.(type) {
case *unstructured.Unstructured: case *unstructured.Unstructured:
c.instance = i.(*unstructured.Unstructured) c.instance = instance
case unstructured.Unstructured: case unstructured.Unstructured:
ii := i.(unstructured.Unstructured) c.instance = &instance
c.instance = &ii
default: default:
log.Fatal().Msgf("unknown context type %#v", i) log.Fatal().Msgf("unknown CRD type %#v", i)
} }
meta := c.instance.Object["metadata"].(map[string]interface{}) meta := c.instance.Object["metadata"].(map[string]interface{})
c.path = meta["name"].(string) c.path = meta["name"].(string)
@ -63,7 +54,7 @@ func (r *CRD) NewInstance(i interface{}) Columnar {
// Marshal a resource. // Marshal a resource.
func (r *CRD) Marshal(path string) (string, error) { func (r *CRD) Marshal(path string) (string, error) {
ns, n := namespaced(path) ns, n := namespaced(path)
i, err := r.caller.Get(ns, n) i, err := r.resource.Get(ns, n)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -72,9 +63,10 @@ func (r *CRD) Marshal(path string) (string, error) {
if err != nil { if err != nil {
return "", err return "", err
} }
return string(raw), nil
// BOZO!! Need to figure out apiGroup+Version // BOZO!! Need to figure out apiGroup+Version
// return r.marshalObject(i.(*unstructured.Unstructured)) // return r.marshalObject(i.(*unstructured.Unstructured))
return string(raw), nil
} }
// Header return the resource header. // Header return the resource header.
@ -92,6 +84,7 @@ func (r *CRD) Fields(ns string) Row {
if err != nil { if err != nil {
log.Error().Msgf("Fields timestamp %v", err) log.Error().Msgf("Fields timestamp %v", err)
} }
return append(ff, meta["name"].(string), toAge(metav1.Time{t})) return append(ff, meta["name"].(string), toAge(metav1.Time{t}))
} }
@ -112,5 +105,6 @@ func (r *CRD) ExtFields() Properties {
pp["singular"], pp["plural"] = names["singular"], names["plural"] pp["singular"], pp["plural"] = names["singular"], names["plural"]
pp["aliases"] = names["shortNames"] pp["aliases"] = names["shortNames"]
} }
return pp return pp
} }

View File

@ -70,7 +70,6 @@ func TestCRDListData(t *testing.T) {
td := l.Data() td := l.Data()
assert.Equal(t, 1, len(td.Rows)) assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.NotNamespaced, l.GetNamespace()) assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["fred"] row := td.Rows["fred"]
assert.Equal(t, 2, len(row.Deltas)) assert.Equal(t, 2, len(row.Deltas))
for _, d := range row.Deltas { for _, d := range row.Deltas {
@ -79,19 +78,6 @@ func TestCRDListData(t *testing.T) {
assert.Equal(t, resource.Row{"fred"}, row.Fields[:1]) assert.Equal(t, resource.Row{"fred"}, row.Fields[:1])
} }
func TestCRDListDescribe(t *testing.T) {
setup(t)
ca := NewMockCaller()
m.When(ca.Get("blee", "fred")).ThenReturn(k8sCRD(), nil)
l := resource.NewCRDListWithArgs("blee", resource.NewCRDWithArgs(ca))
props, err := l.Describe("blee/fred")
ca.VerifyWasCalledOnce().Get("blee", "fred")
assert.Nil(t, err)
assert.Equal(t, 0, len(props))
}
// Helpers... // Helpers...
func k8sCRD() *unstructured.Unstructured { func k8sCRD() *unstructured.Unstructured {

View File

@ -28,51 +28,43 @@ type (
) )
// NewCronJobList returns a new resource list. // NewCronJobList returns a new resource list.
func NewCronJobList(ns string) List { func NewCronJobList(c k8s.Connection, ns string) List {
return NewCronJobListWithArgs(ns, NewCronJob()) return newList(
} ns,
"cronjob",
// NewCronJobListWithArgs returns a new resource list. NewCronJob(c),
func NewCronJobListWithArgs(ns string, res Resource) List { AllVerbsAccess|DescribeAccess,
return newList(ns, "cronjob", res, AllVerbsAccess|DescribeAccess) )
} }
// NewCronJob instantiates a new CronJob. // NewCronJob instantiates a new CronJob.
func NewCronJob() *CronJob { func NewCronJob(c k8s.Connection) *CronJob {
return NewCronJobWithArgs(k8s.NewCronJob()) cj := &CronJob{&Base{connection: c, resource: k8s.NewCronJob(c)}, nil}
cj.Factory = cj
return cj
} }
// NewCronJobWithArgs instantiates a new CronJob. // New builds a new CronJob instance from a k8s resource.
func NewCronJobWithArgs(r k8s.Res) *CronJob { func (r *CronJob) New(i interface{}) Columnar {
cm := &CronJob{ c := NewCronJob(r.connection)
Base: &Base{ switch instance := i.(type) {
caller: r,
},
}
cm.creator = cm
return cm
}
// NewInstance builds a new CronJob instance from a k8s resource.
func (*CronJob) NewInstance(i interface{}) Columnar {
job := NewCronJob()
switch i.(type) {
case *batchv1beta1.CronJob: case *batchv1beta1.CronJob:
job.instance = i.(*batchv1beta1.CronJob) c.instance = instance
case batchv1beta1.CronJob: case batchv1beta1.CronJob:
ii := i.(batchv1beta1.CronJob) c.instance = &instance
job.instance = &ii
default: default:
log.Fatal().Msgf("Unknown %#v", i) log.Fatal().Msgf("unknown CronJob type %#v", i)
} }
job.path = job.namespacedName(job.instance.ObjectMeta) c.path = c.namespacedName(c.instance.ObjectMeta)
return job
return c
} }
// Marshal resource to yaml. // Marshal resource to yaml.
func (r *CronJob) Marshal(path string) (string, error) { func (r *CronJob) Marshal(path string) (string, error) {
ns, n := namespaced(path) ns, n := namespaced(path)
i, err := r.caller.Get(ns, n) i, err := r.resource.Get(ns, n)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -80,15 +72,17 @@ func (r *CronJob) Marshal(path string) (string, error) {
cj := i.(*batchv1beta1.CronJob) cj := i.(*batchv1beta1.CronJob)
cj.TypeMeta.APIVersion = "extensions/batchv1beta1" cj.TypeMeta.APIVersion = "extensions/batchv1beta1"
cj.TypeMeta.Kind = "CronJob" cj.TypeMeta.Kind = "CronJob"
return r.marshalObject(cj) return r.marshalObject(cj)
} }
// Run a given cronjob. // Run a given cronjob.
func (r *CronJob) Run(pa string) error { func (r *CronJob) Run(pa string) error {
ns, n := namespaced(pa) ns, n := namespaced(pa)
if c, ok := r.caller.(Runnable); ok { if c, ok := r.resource.(Runnable); ok {
return c.Run(ns, n) return c.Run(ns, n)
} }
return fmt.Errorf("unable to run cronjob %s", pa) return fmt.Errorf("unable to run cronjob %s", pa)
} }
@ -98,6 +92,7 @@ func (*CronJob) Header(ns string) Row {
if ns == AllNamespaces { if ns == AllNamespaces {
hh = append(hh, "NAMESPACE") hh = append(hh, "NAMESPACE")
} }
return append(hh, "NAME", "SCHEDULE", "SUSPEND", "ACTIVE", "LAST_SCHEDULE", "AGE") return append(hh, "NAME", "SCHEDULE", "SUSPEND", "ACTIVE", "LAST_SCHEDULE", "AGE")
} }
@ -124,8 +119,3 @@ func (r *CronJob) Fields(ns string) Row {
toAge(i.ObjectMeta.CreationTimestamp), toAge(i.ObjectMeta.CreationTimestamp),
) )
} }
// ExtFields returns extended fields in relation to headers.
func (*CronJob) ExtFields() Properties {
return Properties{}
}

View File

@ -62,7 +62,6 @@ func TestCronJobListData(t *testing.T) {
td := l.Data() td := l.Data()
assert.Equal(t, 1, len(td.Rows)) assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.NotNamespaced, l.GetNamespace()) assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"] row := td.Rows["blee/fred"]
assert.Equal(t, 6, len(row.Deltas)) assert.Equal(t, 6, len(row.Deltas))
for _, d := range row.Deltas { for _, d := range row.Deltas {
@ -71,19 +70,6 @@ func TestCronJobListData(t *testing.T) {
assert.Equal(t, resource.Row{"fred"}, row.Fields[:1]) assert.Equal(t, resource.Row{"fred"}, row.Fields[:1])
} }
func TestCronJobListDescribe(t *testing.T) {
setup(t)
ca := NewMockCaller()
m.When(ca.Get("blee", "fred")).ThenReturn(k8sCronJob(), nil)
l := resource.NewCronJobListWithArgs("blee", resource.NewCronJobWithArgs(ca))
props, err := l.Describe("blee/fred")
ca.VerifyWasCalledOnce().Get("blee", "fred")
assert.Nil(t, err)
assert.Equal(t, 0, len(props))
}
// Helpers... // Helpers...
func k8sCronJob() *batchv1beta1.CronJob { func k8sCronJob() *batchv1beta1.CronJob {

View File

@ -16,49 +16,41 @@ import (
// Custom tracks a kubernetes resource. // Custom tracks a kubernetes resource.
type Custom struct { type Custom struct {
*Base *Base
// instance *unstructured.Unstructured
instance *metav1beta1.TableRow instance *metav1beta1.TableRow
group, version, name string group, version, name string
headers Row headers Row
} }
// NewCustomList returns a new resource list. // NewCustomList returns a new resource list.
func NewCustomList(ns, g, v, n string) List { func NewCustomList(c k8s.Connection, ns, group, version, name string) List {
return NewCustomListWithArgs(ns, n, NewCustom(g, v, n)) if !c.IsNamespaced(name) {
} ns = NotNamespaced
}
// NewCustomListWithArgs returns a new resource list. return newList(
func NewCustomListWithArgs(ns, n string, res Resource) List { ns,
return newList(ns, n, res, AllVerbsAccess) name,
NewCustom(c, group, version, name), AllVerbsAccess,
)
} }
// NewCustom instantiates a new Kubernetes Resource. // NewCustom instantiates a new Kubernetes Resource.
func NewCustom(g, v, n string) *Custom { func NewCustom(c k8s.Connection, group, version, name string) *Custom {
return NewCustomWithArgs(k8s.NewResource(g, v, n)) cr := &Custom{Base: &Base{connection: c, resource: k8s.NewResource(c, group, version, name)}}
} cr.Factory = cr
cr.group, cr.version, cr.name = cr.resource.(*k8s.Resource).GetInfo()
// NewCustomWithArgs instantiates a new Custom.
func NewCustomWithArgs(r k8s.Res) *Custom {
cr := &Custom{
Base: &Base{
caller: r,
},
}
cr.creator = cr
cr.group, cr.version, cr.name = r.(*k8s.Resource).GetInfo()
return cr return cr
} }
// NewInstance builds a new Custom instance from a k8s resource. // New builds a new Custom instance from a k8s resource.
func (*Custom) NewInstance(i interface{}) Columnar { func (r *Custom) New(i interface{}) Columnar {
cr := NewCustom("", "", "") cr := NewCustom(r.connection, "", "", "")
switch i.(type) { switch instance := i.(type) {
case *metav1beta1.TableRow: case *metav1beta1.TableRow:
cr.instance = i.(*metav1beta1.TableRow) cr.instance = instance
case metav1beta1.TableRow: case metav1beta1.TableRow:
t := i.(metav1beta1.TableRow) cr.instance = &instance
cr.instance = &t
default: default:
log.Fatal().Msgf("Unknown %#v", i) log.Fatal().Msgf("Unknown %#v", i)
} }
@ -75,13 +67,14 @@ func (*Custom) NewInstance(i interface{}) Columnar {
name := meta["name"].(string) name := meta["name"].(string)
cr.path = path.Join(ns, name) cr.path = path.Join(ns, name)
cr.group, cr.version, cr.name = obj["kind"].(string), obj["apiVersion"].(string), name cr.group, cr.version, cr.name = obj["kind"].(string), obj["apiVersion"].(string), name
return cr return cr
} }
// Marshal resource to yaml. // Marshal resource to yaml.
func (r *Custom) Marshal(path string) (string, error) { func (r *Custom) Marshal(path string) (string, error) {
ns, n := namespaced(path) ns, n := namespaced(path)
i, err := r.caller.Get(ns, n) i, err := r.resource.Get(ns, n)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -90,12 +83,13 @@ func (r *Custom) Marshal(path string) (string, error) {
if err != nil { if err != nil {
return "", err return "", err
} }
return string(raw), nil return string(raw), nil
} }
// List all resources // List all resources
func (r *Custom) List(ns string) (Columnars, error) { func (r *Custom) List(ns string) (Columnars, error) {
ii, err := r.caller.List(ns) ii, err := r.resource.List(ns)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -112,21 +106,23 @@ func (r *Custom) List(ns string) (Columnars, error) {
rows := table.Rows rows := table.Rows
cc := make(Columnars, 0, len(rows)) cc := make(Columnars, 0, len(rows))
for i := 0; i < len(rows); i++ { for i := 0; i < len(rows); i++ {
cc = append(cc, r.creator.NewInstance(rows[i])) cc = append(cc, r.New(rows[i]))
} }
return cc, nil return cc, nil
} }
// Header return resource header. // Header return resource header.
func (r *Custom) Header(ns string) Row { func (r *Custom) Header(ns string) Row {
hh := make(Row, 0, len(r.headers)+1) hh := make(Row, 0, len(r.headers)+1)
if ns == AllNamespaces { if ns == AllNamespaces {
hh = append(hh, "NAMESPACE") hh = append(hh, "NAMESPACE")
} }
for _, h := range r.headers { for _, h := range r.headers {
hh = append(hh, strings.ToUpper(h)) hh = append(hh, strings.ToUpper(h))
} }
return hh return hh
} }
@ -142,55 +138,17 @@ func (r *Custom) Fields(ns string) Row {
} }
meta := obj["metadata"].(map[string]interface{}) meta := obj["metadata"].(map[string]interface{})
rns, ok := meta["namespace"].(string)
if ns == AllNamespaces { if ns == AllNamespaces {
ff = append(ff, meta["namespace"].(string)) if ok {
ff = append(ff, rns)
}
} }
for _, c := range r.instance.Cells { for _, c := range r.instance.Cells {
ff = append(ff, fmt.Sprintf("%v", c)) ff = append(ff, fmt.Sprintf("%v", c))
} }
return ff return ff
} }
// ExtFields returns extended fields in relation to headers.
func (*Custom) ExtFields() Properties {
return Properties{}
}
func getCRDS() map[string]k8s.APIGroup {
m := map[string]k8s.APIGroup{}
list := NewCRDList("")
ll, _ := list.Resource().List("")
for _, l := range ll {
ff := l.ExtFields()
grp := k8s.APIGroup{
Resource: ff["name"].(string),
Version: ff["version"].(string),
Group: ff["group"].(string),
Kind: ff["kind"].(string),
}
if aa, ok := ff["aliases"].([]interface{}); ok {
if n, ok := ff["plural"].(string); ok {
grp.Plural = n
}
if n, ok := ff["singular"].(string); ok {
grp.Singular = n
}
aliases := make([]string, len(aa))
for i, a := range aa {
aliases[i] = a.(string)
}
grp.Aliases = aliases
} else if s, ok := ff["singular"].(string); ok {
grp.Singular = s
if p, ok := ff["plural"].(string); ok {
grp.Plural = p
}
} else if s, ok := ff["plural"].(string); ok {
grp.Plural = s
}
m[grp.Kind] = grp
}
return m
}

View File

@ -15,51 +15,43 @@ type Deployment struct {
} }
// NewDeploymentList returns a new resource list. // NewDeploymentList returns a new resource list.
func NewDeploymentList(ns string) List { func NewDeploymentList(c k8s.Connection, ns string) List {
return NewDeploymentListWithArgs(ns, NewDeployment()) return newList(
} ns,
"deploy",
// NewDeploymentListWithArgs returns a new resource list. NewDeployment(c),
func NewDeploymentListWithArgs(ns string, res Resource) List { AllVerbsAccess|DescribeAccess,
return newList(ns, "deploy", res, AllVerbsAccess|DescribeAccess) )
} }
// NewDeployment instantiates a new Deployment. // NewDeployment instantiates a new Deployment.
func NewDeployment() *Deployment { func NewDeployment(c k8s.Connection) *Deployment {
return NewDeploymentWithArgs(k8s.NewDeployment()) d := &Deployment{&Base{connection: c, resource: k8s.NewDeployment(c)}, nil}
d.Factory = d
return d
} }
// NewDeploymentWithArgs instantiates a new Deployment. // New builds a new Deployment instance from a k8s resource.
func NewDeploymentWithArgs(r k8s.Res) *Deployment { func (r *Deployment) New(i interface{}) Columnar {
cm := &Deployment{ c := NewDeployment(r.connection)
Base: &Base{ switch instance := i.(type) {
caller: r,
},
}
cm.creator = cm
return cm
}
// NewInstance builds a new Deployment instance from a k8s resource.
func (*Deployment) NewInstance(i interface{}) Columnar {
cm := NewDeployment()
switch i.(type) {
case *v1.Deployment: case *v1.Deployment:
cm.instance = i.(*v1.Deployment) c.instance = instance
case v1.Deployment: case v1.Deployment:
ii := i.(v1.Deployment) c.instance = &instance
cm.instance = &ii
default: default:
log.Fatal().Msgf("Unknown %#v", i) log.Fatal().Msgf("unknown Deployment type %#v", i)
} }
cm.path = cm.namespacedName(cm.instance.ObjectMeta) c.path = c.namespacedName(c.instance.ObjectMeta)
return cm
return c
} }
// Marshal resource to yaml. // Marshal resource to yaml.
func (r *Deployment) Marshal(path string) (string, error) { func (r *Deployment) Marshal(path string) (string, error) {
ns, n := namespaced(path) ns, n := namespaced(path)
i, err := r.caller.Get(ns, n) i, err := r.resource.Get(ns, n)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -67,6 +59,7 @@ func (r *Deployment) Marshal(path string) (string, error) {
dp := i.(*v1.Deployment) dp := i.(*v1.Deployment)
dp.TypeMeta.APIVersion = "apps/v1" dp.TypeMeta.APIVersion = "apps/v1"
dp.TypeMeta.Kind = "Deployment" dp.TypeMeta.Kind = "Deployment"
return r.marshalObject(dp) return r.marshalObject(dp)
} }
@ -76,6 +69,7 @@ func (*Deployment) Header(ns string) Row {
if ns == AllNamespaces { if ns == AllNamespaces {
hh = append(hh, "NAMESPACE") hh = append(hh, "NAMESPACE")
} }
return append(hh, "NAME", "DESIRED", "CURRENT", "UP-TO-DATE", "AVAILABLE", "AGE") return append(hh, "NAME", "DESIRED", "CURRENT", "UP-TO-DATE", "AVAILABLE", "AGE")
} }
@ -87,6 +81,7 @@ func (r *Deployment) Fields(ns string) Row {
if ns == AllNamespaces { if ns == AllNamespaces {
ff = append(ff, i.Namespace) ff = append(ff, i.Namespace)
} }
return append(ff, return append(ff,
i.Name, i.Name,
strconv.Itoa(int(*i.Spec.Replicas)), strconv.Itoa(int(*i.Spec.Replicas)),
@ -96,8 +91,3 @@ func (r *Deployment) Fields(ns string) Row {
toAge(i.ObjectMeta.CreationTimestamp), toAge(i.ObjectMeta.CreationTimestamp),
) )
} }
// ExtFields returns extended fields in relation to headers.
func (*Deployment) ExtFields() Properties {
return Properties{}
}

View File

@ -62,7 +62,6 @@ func TestDeploymentListData(t *testing.T) {
td := l.Data() td := l.Data()
assert.Equal(t, 1, len(td.Rows)) assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.NotNamespaced, l.GetNamespace()) assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"] row := td.Rows["blee/fred"]
assert.Equal(t, 6, len(row.Deltas)) assert.Equal(t, 6, len(row.Deltas))
for _, d := range row.Deltas { for _, d := range row.Deltas {
@ -71,19 +70,6 @@ func TestDeploymentListData(t *testing.T) {
assert.Equal(t, resource.Row{"fred"}, row.Fields[:1]) assert.Equal(t, resource.Row{"fred"}, row.Fields[:1])
} }
func TestDeploymentListDescribe(t *testing.T) {
setup(t)
ca := NewMockCaller()
m.When(ca.Get("blee", "fred")).ThenReturn(k8sDeployment(), nil)
l := resource.NewDeploymentListWithArgs("blee", resource.NewDeploymentWithArgs(ca))
props, err := l.Describe("blee/fred")
ca.VerifyWasCalledOnce().Get("blee", "fred")
assert.Nil(t, err)
assert.Equal(t, 0, len(props))
}
// Helpers... // Helpers...
func k8sDeployment() *appsv1.Deployment { func k8sDeployment() *appsv1.Deployment {

View File

@ -15,51 +15,43 @@ type DaemonSet struct {
} }
// NewDaemonSetList returns a new resource list. // NewDaemonSetList returns a new resource list.
func NewDaemonSetList(ns string) List { func NewDaemonSetList(c k8s.Connection, ns string) List {
return NewDaemonSetListWithArgs(ns, NewDaemonSet()) return newList(
} ns,
"ds",
// NewDaemonSetListWithArgs returns a new resource list. NewDaemonSet(c),
func NewDaemonSetListWithArgs(ns string, res Resource) List { AllVerbsAccess|DescribeAccess,
return newList(ns, "ds", res, AllVerbsAccess|DescribeAccess) )
} }
// NewDaemonSet instantiates a new DaemonSet. // NewDaemonSet instantiates a new DaemonSet.
func NewDaemonSet() *DaemonSet { func NewDaemonSet(c k8s.Connection) *DaemonSet {
return NewDaemonSetWithArgs(k8s.NewDaemonSet()) ds := &DaemonSet{&Base{connection: c, resource: k8s.NewDaemonSet(c)}, nil}
ds.Factory = ds
return ds
} }
// NewDaemonSetWithArgs instantiates a new DaemonSet. // New builds a new DaemonSet instance from a k8s resource.
func NewDaemonSetWithArgs(r k8s.Res) *DaemonSet { func (r *DaemonSet) New(i interface{}) Columnar {
cm := &DaemonSet{ c := NewDaemonSet(r.connection)
Base: &Base{ switch instance := i.(type) {
caller: r,
},
}
cm.creator = cm
return cm
}
// NewInstance builds a new DaemonSet instance from a k8s resource.
func (*DaemonSet) NewInstance(i interface{}) Columnar {
cm := NewDaemonSet()
switch i.(type) {
case *extv1beta1.DaemonSet: case *extv1beta1.DaemonSet:
cm.instance = i.(*extv1beta1.DaemonSet) c.instance = instance
case extv1beta1.DaemonSet: case extv1beta1.DaemonSet:
ii := i.(extv1beta1.DaemonSet) c.instance = &instance
cm.instance = &ii
default: default:
log.Fatal().Msgf("Unknown %#v", i) log.Fatal().Msgf("unknown DaemonSet type %#v", i)
} }
cm.path = cm.namespacedName(cm.instance.ObjectMeta) c.path = c.namespacedName(c.instance.ObjectMeta)
return cm
return c
} }
// Marshal resource to yaml. // Marshal resource to yaml.
func (r *DaemonSet) Marshal(path string) (string, error) { func (r *DaemonSet) Marshal(path string) (string, error) {
ns, n := namespaced(path) ns, n := namespaced(path)
i, err := r.caller.Get(ns, n) i, err := r.resource.Get(ns, n)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -67,6 +59,7 @@ func (r *DaemonSet) Marshal(path string) (string, error) {
ds := i.(*extv1beta1.DaemonSet) ds := i.(*extv1beta1.DaemonSet)
ds.TypeMeta.APIVersion = "extensions/v1beta1" ds.TypeMeta.APIVersion = "extensions/v1beta1"
ds.TypeMeta.Kind = "DaemonSet" ds.TypeMeta.Kind = "DaemonSet"
return r.marshalObject(ds) return r.marshalObject(ds)
} }
@ -78,6 +71,7 @@ func (*DaemonSet) Header(ns string) Row {
} }
hh = append(hh, "NAME", "DESIRED", "CURRENT", "READY", "UP-TO-DATE") hh = append(hh, "NAME", "DESIRED", "CURRENT", "READY", "UP-TO-DATE")
hh = append(hh, "AVAILABLE", "NODE_SELECTOR", "AGE") hh = append(hh, "AVAILABLE", "NODE_SELECTOR", "AGE")
return hh return hh
} }
@ -89,6 +83,7 @@ func (r *DaemonSet) Fields(ns string) Row {
if ns == AllNamespaces { if ns == AllNamespaces {
ff = append(ff, i.Namespace) ff = append(ff, i.Namespace)
} }
return append(ff, return append(ff,
i.Name, i.Name,
strconv.Itoa(int(i.Status.DesiredNumberScheduled)), strconv.Itoa(int(i.Status.DesiredNumberScheduled)),
@ -100,8 +95,3 @@ func (r *DaemonSet) Fields(ns string) Row {
toAge(i.ObjectMeta.CreationTimestamp), toAge(i.ObjectMeta.CreationTimestamp),
) )
} }
// ExtFields returns extended fields in relation to headers.
func (*DaemonSet) ExtFields() Properties {
return Properties{}
}

View File

@ -62,7 +62,6 @@ func TestDSListData(t *testing.T) {
td := l.Data() td := l.Data()
assert.Equal(t, 1, len(td.Rows)) assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.NotNamespaced, l.GetNamespace()) assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"] row := td.Rows["blee/fred"]
assert.Equal(t, 8, len(row.Deltas)) assert.Equal(t, 8, len(row.Deltas))
for _, d := range row.Deltas { for _, d := range row.Deltas {
@ -71,19 +70,6 @@ func TestDSListData(t *testing.T) {
assert.Equal(t, resource.Row{"fred"}, row.Fields[:1]) assert.Equal(t, resource.Row{"fred"}, row.Fields[:1])
} }
func TestDSListDescribe(t *testing.T) {
setup(t)
ca := NewMockCaller()
m.When(ca.Get("blee", "fred")).ThenReturn(k8sDS(), nil)
l := resource.NewDaemonSetListWithArgs("blee", resource.NewDaemonSetWithArgs(ca))
props, err := l.Describe("blee/fred")
ca.VerifyWasCalledOnce().Get("blee", "fred")
assert.Nil(t, err)
assert.Equal(t, 0, len(props))
}
// Helpers... // Helpers...
func k8sDS() *extv1beta1.DaemonSet { func k8sDS() *extv1beta1.DaemonSet {

View File

@ -17,51 +17,43 @@ type Endpoints struct {
} }
// NewEndpointsList returns a new resource list. // NewEndpointsList returns a new resource list.
func NewEndpointsList(ns string) List { func NewEndpointsList(c k8s.Connection, ns string) List {
return NewEndpointsListWithArgs(ns, NewEndpoints()) return newList(
ns,
"ep",
NewEndpoints(c),
AllVerbsAccess|DescribeAccess,
)
} }
// NewEndpointsListWithArgs returns a new resource list. // NewEndpoints instantiates a new Endpoints.
func NewEndpointsListWithArgs(ns string, res Resource) List { func NewEndpoints(c k8s.Connection) *Endpoints {
return newList(ns, "ep", res, AllVerbsAccess|DescribeAccess) ep := &Endpoints{&Base{connection: c, resource: k8s.NewEndpoints(c)}, nil}
} ep.Factory = ep
// NewEndpoints instantiates a new Endpoint.
func NewEndpoints() *Endpoints {
return NewEndpointsWithArgs(k8s.NewEndpoints())
}
// NewEndpointsWithArgs instantiates a new Endpoint.
func NewEndpointsWithArgs(r k8s.Res) *Endpoints {
ep := &Endpoints{
Base: &Base{
caller: r,
},
}
ep.creator = ep
return ep return ep
} }
// NewInstance builds a new Endpoint instance from a k8s resource. // New builds a new Endpoints instance from a k8s resource.
func (*Endpoints) NewInstance(i interface{}) Columnar { func (r *Endpoints) New(i interface{}) Columnar {
cm := NewEndpoints() c := NewEndpoints(r.connection)
switch i.(type) { switch instance := i.(type) {
case *v1.Endpoints: case *v1.Endpoints:
cm.instance = i.(*v1.Endpoints) c.instance = instance
case v1.Endpoints: case v1.Endpoints:
ii := i.(v1.Endpoints) c.instance = &instance
cm.instance = &ii
default: default:
log.Fatal().Msgf("Unknown %#v", i) log.Fatal().Msgf("unknown Endpoints type %#v", i)
} }
cm.path = cm.namespacedName(cm.instance.ObjectMeta) c.path = c.namespacedName(c.instance.ObjectMeta)
return cm
return c
} }
// Marshal resource to yaml. // Marshal resource to yaml.
func (r *Endpoints) Marshal(path string) (string, error) { func (r *Endpoints) Marshal(path string) (string, error) {
ns, n := namespaced(path) ns, n := namespaced(path)
i, err := r.caller.Get(ns, n) i, err := r.resource.Get(ns, n)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -69,6 +61,7 @@ func (r *Endpoints) Marshal(path string) (string, error) {
ep := i.(*v1.Endpoints) ep := i.(*v1.Endpoints)
ep.TypeMeta.APIVersion = "v1" ep.TypeMeta.APIVersion = "v1"
ep.TypeMeta.Kind = "Endpoint" ep.TypeMeta.Kind = "Endpoint"
return r.marshalObject(ep) return r.marshalObject(ep)
} }
@ -78,6 +71,7 @@ func (*Endpoints) Header(ns string) Row {
if ns == AllNamespaces { if ns == AllNamespaces {
hh = append(hh, "NAMESPACE") hh = append(hh, "NAMESPACE")
} }
return append(hh, "NAME", "ENDPOINTS", "AGE") return append(hh, "NAME", "ENDPOINTS", "AGE")
} }
@ -96,10 +90,8 @@ func (r *Endpoints) Fields(ns string) Row {
) )
} }
// ExtFields returns extended fields in relation to headers. // ----------------------------------------------------------------------------
func (*Endpoints) ExtFields() Properties { // Helpers...
return Properties{}
}
func (r *Endpoints) toEPs(ss []v1.EndpointSubset) string { func (r *Endpoints) toEPs(ss []v1.EndpointSubset) string {
aa := make([]string, 0, len(ss)) aa := make([]string, 0, len(ss))
@ -124,5 +116,6 @@ func (r *Endpoints) toEPs(ss []v1.EndpointSubset) string {
} }
} }
} }
return strings.Join(aa, ",") return strings.Join(aa, ",")
} }

View File

@ -62,7 +62,6 @@ func TestEndpointsListData(t *testing.T) {
td := l.Data() td := l.Data()
assert.Equal(t, 1, len(td.Rows)) assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.NotNamespaced, l.GetNamespace()) assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"] row := td.Rows["blee/fred"]
assert.Equal(t, 3, len(row.Deltas)) assert.Equal(t, 3, len(row.Deltas))
for _, d := range row.Deltas { for _, d := range row.Deltas {
@ -71,19 +70,6 @@ func TestEndpointsListData(t *testing.T) {
assert.Equal(t, resource.Row{"fred"}, row.Fields[:1]) assert.Equal(t, resource.Row{"fred"}, row.Fields[:1])
} }
func TestEndpointsListDescribe(t *testing.T) {
setup(t)
ca := NewMockCaller()
m.When(ca.Get("blee", "fred")).ThenReturn(k8sEndpoints(), nil)
l := resource.NewEndpointsListWithArgs("blee", resource.NewEndpointsWithArgs(ca))
props, err := l.Describe("blee/fred")
ca.VerifyWasCalledOnce().Get("blee", "fred")
assert.Nil(t, err)
assert.Equal(t, 0, len(props))
}
// Helpers... // Helpers...
func k8sEndpoints() *v1.Endpoints { func k8sEndpoints() *v1.Endpoints {

View File

@ -16,51 +16,43 @@ type Event struct {
} }
// NewEventList returns a new resource list. // NewEventList returns a new resource list.
func NewEventList(ns string) List { func NewEventList(c k8s.Connection, ns string) List {
return NewEventListWithArgs(ns, NewEvent()) return newList(
ns,
"ev",
NewEvent(c),
ListAccess+NamespaceAccess,
)
} }
// NewEventListWithArgs returns a new resource list. // NewEvent instantiates a new Event.
func NewEventListWithArgs(ns string, res Resource) List { func NewEvent(c k8s.Connection) *Event {
return newList(ns, "event", res, ListAccess+NamespaceAccess) ev := &Event{&Base{connection: c, resource: k8s.NewEvent(c)}, nil}
ev.Factory = ev
return ev
} }
// NewEvent instantiates a new Endpoint. // New builds a new Event instance from a k8s resource.
func NewEvent() *Event { func (r *Event) New(i interface{}) Columnar {
return NewEventWithArgs(k8s.NewEvent()) c := NewEvent(r.connection)
} switch instance := i.(type) {
// NewEventWithArgs instantiates a new Endpoint.
func NewEventWithArgs(r k8s.Res) *Event {
ep := &Event{
Base: &Base{
caller: r,
},
}
ep.creator = ep
return ep
}
// NewInstance builds a new Endpoint instance from a k8s resource.
func (*Event) NewInstance(i interface{}) Columnar {
cm := NewEvent()
switch i.(type) {
case *v1.Event: case *v1.Event:
cm.instance = i.(*v1.Event) c.instance = instance
case v1.Event: case v1.Event:
ii := i.(v1.Event) c.instance = &instance
cm.instance = &ii
default: default:
log.Fatal().Msgf("Unknown %#v", i) log.Fatal().Msgf("unknown Event type %#v", i)
} }
cm.path = cm.namespacedName(cm.instance.ObjectMeta) c.path = c.namespacedName(c.instance.ObjectMeta)
return cm
return c
} }
// Marshal resource to yaml. // Marshal resource to yaml.
func (r *Event) Marshal(path string) (string, error) { func (r *Event) Marshal(path string) (string, error) {
ns, n := namespaced(path) ns, n := namespaced(path)
i, err := r.caller.Get(ns, n) i, err := r.resource.Get(ns, n)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -68,19 +60,10 @@ func (r *Event) Marshal(path string) (string, error) {
ev := i.(*v1.Event) ev := i.(*v1.Event)
ev.TypeMeta.APIVersion = "v1" ev.TypeMeta.APIVersion = "v1"
ev.TypeMeta.Kind = "Event" ev.TypeMeta.Kind = "Event"
return r.marshalObject(ev) return r.marshalObject(ev)
} }
// // Get resource given a namespaced name.
// func (r *Event) Get(path string) (Columnar, error) {
// ns, n := namespaced(path)
// i, err := r.caller.Get(ns, n)
// if err != nil {
// return nil, err
// }
// return r.NewInstance(i), nil
// }
// Delete a resource by name. // Delete a resource by name.
func (r *Event) Delete(path string) error { func (r *Event) Delete(path string) error {
return nil return nil
@ -92,6 +75,7 @@ func (*Event) Header(ns string) Row {
if ns == AllNamespaces { if ns == AllNamespaces {
ff = append(ff, "NAMESPACE") ff = append(ff, "NAMESPACE")
} }
return append(ff, "NAME", "REASON", "SOURCE", "COUNT", "MESSAGE", "AGE") return append(ff, "NAME", "REASON", "SOURCE", "COUNT", "MESSAGE", "AGE")
} }
@ -116,11 +100,7 @@ func (r *Event) Fields(ns string) Row {
) )
} }
// ExtFields returns extended fields in relation to headers. // ----------------------------------------------------------------------------
func (*Event) ExtFields() Properties {
return Properties{}
}
// Helpers... // Helpers...
func (*Event) toEmoji(t, r string) string { func (*Event) toEmoji(t, r string) string {

View File

@ -62,7 +62,6 @@ func TestEventListData(t *testing.T) {
td := l.Data() td := l.Data()
assert.Equal(t, 1, len(td.Rows)) assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.NotNamespaced, l.GetNamespace()) assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"] row := td.Rows["blee/fred"]
assert.Equal(t, 6, len(row.Deltas)) assert.Equal(t, 6, len(row.Deltas))
for _, d := range row.Deltas { for _, d := range row.Deltas {
@ -71,19 +70,6 @@ func TestEventListData(t *testing.T) {
assert.Equal(t, resource.Row{"fred"}, row.Fields[:1]) assert.Equal(t, resource.Row{"fred"}, row.Fields[:1])
} }
func TestEventListDescribe(t *testing.T) {
setup(t)
ca := NewMockCaller()
m.When(ca.Get("blee", "fred")).ThenReturn(k8sEvent(), nil)
l := resource.NewEventListWithArgs("blee", resource.NewEventWithArgs(ca))
props, err := l.Describe("blee/fred")
ca.VerifyWasCalledOnce().Get("blee", "fred")
assert.Nil(t, err)
assert.Equal(t, 0, len(props))
}
// Helpers... // Helpers...
func k8sEvent() *v1.Event { func k8sEvent() *v1.Event {

View File

@ -38,6 +38,7 @@ const (
func namespaced(n string) (string, string) { func namespaced(n string) (string, string) {
ns, po := path.Split(n) ns, po := path.Split(n)
return strings.Trim(ns, "/"), po return strings.Trim(ns, "/"), po
} }
@ -53,6 +54,7 @@ func check(s, sub string) string {
if len(s) == 0 { if len(s) == 0 {
return sub return sub
} }
return s return s
} }
@ -73,12 +75,14 @@ func toAge(timestamp metav1.Time) string {
if timestamp.IsZero() { if timestamp.IsZero() {
return "<unknown>" return "<unknown>"
} }
return duration.HumanDuration(time.Since(timestamp.Time)) return duration.HumanDuration(time.Since(timestamp.Time))
} }
// Pad a string up to the given length. // Pad a string up to the given length.
func Pad(s string, l int) string { func Pad(s string, l int) string {
fmat := "%-" + strconv.Itoa(l) + "s" fmat := "%-" + strconv.Itoa(l) + "s"
return fmt.Sprintf(fmat, s) return fmt.Sprintf(fmat, s)
} }
@ -104,5 +108,16 @@ func mapToStr(m map[string]string) (s string) {
s += "," s += ","
} }
} }
return return
} }
// ToMillicore shows cpu reading for human.
func ToMillicore(v int64) string {
return strconv.Itoa(int(v)) + "m"
}
// ToMi shows mem reading for human.
func ToMi(v float64) string {
return strconv.Itoa(int(v)) + "Mi"
}

View File

@ -117,3 +117,33 @@ func BenchmarkMapToStr(b *testing.B) {
mapToStr(ll) mapToStr(ll)
} }
} }
func TestToMillicore(t *testing.T) {
uu := []struct {
v int64
e string
}{
{0, "0m"},
{2, "2m"},
{1000, "1000m"},
}
for _, u := range uu {
assert.Equal(t, u.e, ToMillicore(u.v))
}
}
func TestToMi(t *testing.T) {
uu := []struct {
v float64
e string
}{
{0, "0Mi"},
{2, "2Mi"},
{1000, "1000Mi"},
}
for _, u := range uu {
assert.Equal(t, u.e, ToMi(u.v))
}
}

View File

@ -17,51 +17,43 @@ type HPA struct {
} }
// NewHPAList returns a new resource list. // NewHPAList returns a new resource list.
func NewHPAList(ns string) List { func NewHPAList(c k8s.Connection, ns string) List {
return NewHPAListWithArgs(ns, NewHPA()) return newList(
ns,
"hpa",
NewHPA(c),
AllVerbsAccess|DescribeAccess,
)
} }
// NewHPAListWithArgs returns a new resource list. // NewHPA instantiates a new HPA.
func NewHPAListWithArgs(ns string, res Resource) List { func NewHPA(c k8s.Connection) *HPA {
return newList(ns, "hpa", res, AllVerbsAccess|DescribeAccess) hpa := &HPA{&Base{connection: c, resource: k8s.NewHPA(c)}, nil}
hpa.Factory = hpa
return hpa
} }
// NewHPA instantiates a new Endpoint. // New builds a new HPA instance from a k8s resource.
func NewHPA() *HPA { func (r *HPA) New(i interface{}) Columnar {
return NewHPAWithArgs(k8s.NewHPA()) c := NewHPA(r.connection)
} switch instance := i.(type) {
// NewHPAWithArgs instantiates a new Endpoint.
func NewHPAWithArgs(r k8s.Res) *HPA {
ep := &HPA{
Base: &Base{
caller: r,
},
}
ep.creator = ep
return ep
}
// NewInstance builds a new Endpoint instance from a k8s resource.
func (*HPA) NewInstance(i interface{}) Columnar {
cm := NewHPA()
switch i.(type) {
case *autoscalingv2beta2.HorizontalPodAutoscaler: case *autoscalingv2beta2.HorizontalPodAutoscaler:
cm.instance = i.(*autoscalingv2beta2.HorizontalPodAutoscaler) c.instance = instance
case autoscalingv2beta2.HorizontalPodAutoscaler: case autoscalingv2beta2.HorizontalPodAutoscaler:
ii := i.(autoscalingv2beta2.HorizontalPodAutoscaler) c.instance = &instance
cm.instance = &ii
default: default:
log.Fatal().Msgf("Unknown %#v", i) log.Fatal().Msgf("unknown HPA type %#v", i)
} }
cm.path = cm.namespacedName(cm.instance.ObjectMeta) c.path = c.namespacedName(c.instance.ObjectMeta)
return cm
return c
} }
// Marshal resource to yaml. // Marshal resource to yaml.
func (r *HPA) Marshal(path string) (string, error) { func (r *HPA) Marshal(path string) (string, error) {
ns, n := namespaced(path) ns, n := namespaced(path)
i, err := r.caller.Get(ns, n) i, err := r.resource.Get(ns, n)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -69,6 +61,7 @@ func (r *HPA) Marshal(path string) (string, error) {
hpa := i.(*autoscalingv2beta2.HorizontalPodAutoscaler) hpa := i.(*autoscalingv2beta2.HorizontalPodAutoscaler)
hpa.TypeMeta.APIVersion = "autoscaling/v2beta2" hpa.TypeMeta.APIVersion = "autoscaling/v2beta2"
hpa.TypeMeta.Kind = "HorizontalPodAutoscaler" hpa.TypeMeta.Kind = "HorizontalPodAutoscaler"
return r.marshalObject(hpa) return r.marshalObject(hpa)
} }
@ -78,6 +71,7 @@ func (*HPA) Header(ns string) Row {
if ns == AllNamespaces { if ns == AllNamespaces {
hh = append(hh, "NAMESPACE") hh = append(hh, "NAMESPACE")
} }
return append(hh, return append(hh,
"NAME", "NAME",
"REFERENCE", "REFERENCE",
@ -108,60 +102,33 @@ func (r *HPA) Fields(ns string) Row {
) )
} }
// ExtFields returns extended fields in relation to headers. // ----------------------------------------------------------------------------
func (*HPA) ExtFields() Properties { // Helpers...
return Properties{}
}
func toMetrics(specs []autoscalingv2beta2.MetricSpec, statuses []autoscalingv2beta2.MetricStatus) string { func toMetrics(specs []autoscalingv2beta2.MetricSpec, statuses []autoscalingv2beta2.MetricStatus) string {
if len(specs) == 0 { if len(specs) == 0 {
return "<none>" return "<none>"
} }
list, max, more, count := []string{}, 2, false, 0 list, max, more, count := []string{}, 2, false, 0
for i, spec := range specs { for i, spec := range specs {
current := "<unknown>"
switch spec.Type { switch spec.Type {
case autoscalingv2beta2.ExternalMetricSourceType: case autoscalingv2beta2.ExternalMetricSourceType:
current := "<unknown>" list = append(list, externalMetrics(i, spec, statuses))
if spec.External.Target.AverageValue != nil {
if len(statuses) > i && statuses[i].External != nil && &statuses[i].External.Current.AverageValue != nil {
current = statuses[i].External.Current.AverageValue.String()
}
list = append(list, fmt.Sprintf("%s/%s (avg)", current, spec.External.Target.AverageValue.String()))
} else {
if len(statuses) > i && statuses[i].External != nil {
current = statuses[i].External.Current.Value.String()
}
list = append(list, fmt.Sprintf("%s/%s", current, spec.External.Target.Value.String()))
}
case autoscalingv2beta2.PodsMetricSourceType: case autoscalingv2beta2.PodsMetricSourceType:
current := "<unknown>"
if len(statuses) > i && statuses[i].Pods != nil { if len(statuses) > i && statuses[i].Pods != nil {
current = statuses[i].Pods.Current.AverageValue.String() current = statuses[i].Pods.Current.AverageValue.String()
} }
list = append(list, fmt.Sprintf("%s/%s", current, spec.Pods.Target.AverageValue.String())) list = append(list, fmt.Sprintf("%s/%s", current, spec.Pods.Target.AverageValue.String()))
case autoscalingv2beta2.ObjectMetricSourceType: case autoscalingv2beta2.ObjectMetricSourceType:
current := "<unknown>"
if len(statuses) > i && statuses[i].Object != nil { if len(statuses) > i && statuses[i].Object != nil {
current = statuses[i].Object.Current.Value.String() current = statuses[i].Object.Current.Value.String()
} }
list = append(list, fmt.Sprintf("%s/%s", current, spec.Object.Target.Value.String())) list = append(list, fmt.Sprintf("%s/%s", current, spec.Object.Target.Value.String()))
case autoscalingv2beta2.ResourceMetricSourceType: case autoscalingv2beta2.ResourceMetricSourceType:
current := "<unknown>" list = append(list, resourceMetrics(i, spec, statuses))
if spec.Resource.Target.AverageValue != nil {
if len(statuses) > i && statuses[i].Resource != nil {
current = statuses[i].Resource.Current.AverageValue.String()
}
list = append(list, fmt.Sprintf("%s/%s", current, spec.Resource.Target.AverageValue.String()))
} else {
if len(statuses) > i && statuses[i].Resource != nil && statuses[i].Resource.Current.AverageUtilization != nil {
current = fmt.Sprintf("%d%%", *statuses[i].Resource.Current.AverageUtilization)
}
target := "<auto>"
if spec.Resource.Target.AverageUtilization != nil {
target = fmt.Sprintf("%d%%", *spec.Resource.Target.AverageUtilization)
}
list = append(list, fmt.Sprintf("%s/%s", current, target))
}
default: default:
list = append(list, "<unknown type>") list = append(list, "<unknown type>")
} }
@ -169,13 +136,50 @@ func toMetrics(specs []autoscalingv2beta2.MetricSpec, statuses []autoscalingv2be
} }
if count > max { if count > max {
list = list[:max] list, more = list[:max], true
more = true
} }
ret := strings.Join(list, ", ") ret := strings.Join(list, ", ")
if more { if more {
return fmt.Sprintf("%s + %d more...", ret, count-max) return fmt.Sprintf("%s + %d more...", ret, count-max)
} }
return ret return ret
} }
func externalMetrics(i int, spec autoscalingv2beta2.MetricSpec, statuses []autoscalingv2beta2.MetricStatus) string {
current := "<unknown>"
if spec.External.Target.AverageValue != nil {
if len(statuses) > i && statuses[i].External != nil && &statuses[i].External.Current.AverageValue != nil {
current = statuses[i].External.Current.AverageValue.String()
}
return fmt.Sprintf("%s/%s (avg)", current, spec.External.Target.AverageValue.String())
}
if len(statuses) > i && statuses[i].External != nil {
current = statuses[i].External.Current.Value.String()
}
return fmt.Sprintf("%s/%s", current, spec.External.Target.Value.String())
}
func resourceMetrics(i int, spec autoscalingv2beta2.MetricSpec, statuses []autoscalingv2beta2.MetricStatus) string {
current := "<unknown>"
if spec.Resource.Target.AverageValue != nil {
if len(statuses) > i && statuses[i].Resource != nil {
current = statuses[i].Resource.Current.AverageValue.String()
}
return fmt.Sprintf("%s/%s", current, spec.Resource.Target.AverageValue.String())
}
if len(statuses) > i && statuses[i].Resource != nil && statuses[i].Resource.Current.AverageUtilization != nil {
current = fmt.Sprintf("%d%%", *statuses[i].Resource.Current.AverageUtilization)
}
target := "<auto>"
if spec.Resource.Target.AverageUtilization != nil {
target = fmt.Sprintf("%d%%", *spec.Resource.Target.AverageUtilization)
}
return fmt.Sprintf("%s/%s", current, target)
}

View File

@ -65,7 +65,6 @@ func TestHPAListData(t *testing.T) {
td := l.Data() td := l.Data()
assert.Equal(t, 1, len(td.Rows)) assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.NotNamespaced, l.GetNamespace()) assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"] row := td.Rows["blee/fred"]
assert.Equal(t, 7, len(row.Deltas)) assert.Equal(t, 7, len(row.Deltas))
for _, d := range row.Deltas { for _, d := range row.Deltas {
@ -74,19 +73,6 @@ func TestHPAListData(t *testing.T) {
assert.Equal(t, resource.Row{"fred"}, row.Fields[:1]) assert.Equal(t, resource.Row{"fred"}, row.Fields[:1])
} }
func TestHPAListDescribe(t *testing.T) {
setup(t)
ca := NewMockCaller()
m.When(ca.Get("blee", "fred")).ThenReturn(k8sHPA(), nil)
l := resource.NewHPAListWithArgs("blee", resource.NewHPAWithArgs(ca))
props, err := l.Describe("blee/fred")
ca.VerifyWasCalledOnce().Get("blee", "fred")
assert.Nil(t, err)
assert.Equal(t, 0, len(props))
}
// Helpers... // Helpers...
func k8sHPA() *autoscalingv2beta2.HorizontalPodAutoscaler { func k8sHPA() *autoscalingv2beta2.HorizontalPodAutoscaler {

View File

@ -16,51 +16,43 @@ type Ingress struct {
} }
// NewIngressList returns a new resource list. // NewIngressList returns a new resource list.
func NewIngressList(ns string) List { func NewIngressList(c k8s.Connection, ns string) List {
return NewIngressListWithArgs(ns, NewIngress()) return newList(
ns,
"ing",
NewIngress(c),
AllVerbsAccess|DescribeAccess,
)
} }
// NewIngressListWithArgs returns a new resource list. // NewIngress instantiates a new Ingress.
func NewIngressListWithArgs(ns string, res Resource) List { func NewIngress(c k8s.Connection) *Ingress {
return newList(ns, "ing", res, AllVerbsAccess|DescribeAccess) ing := &Ingress{&Base{connection: c, resource: k8s.NewIngress(c)}, nil}
ing.Factory = ing
return ing
} }
// NewIngress instantiates a new Endpoint. // New builds a new Ingress instance from a k8s resource.
func NewIngress() *Ingress { func (r *Ingress) New(i interface{}) Columnar {
return NewIngressWithArgs(k8s.NewIngress()) c := NewIngress(r.connection)
} switch instance := i.(type) {
// NewIngressWithArgs instantiates a new Endpoint.
func NewIngressWithArgs(r k8s.Res) *Ingress {
ep := &Ingress{
Base: &Base{
caller: r,
},
}
ep.creator = ep
return ep
}
// NewInstance builds a new Endpoint instance from a k8s resource.
func (*Ingress) NewInstance(i interface{}) Columnar {
cm := NewIngress()
switch i.(type) {
case *v1beta1.Ingress: case *v1beta1.Ingress:
cm.instance = i.(*v1beta1.Ingress) c.instance = instance
case v1beta1.Ingress: case v1beta1.Ingress:
ii := i.(v1beta1.Ingress) c.instance = &instance
cm.instance = &ii
default: default:
log.Fatal().Msgf("Unknown %#v", i) log.Fatal().Msgf("unknown Ingress type %#v", i)
} }
cm.path = cm.namespacedName(cm.instance.ObjectMeta) c.path = c.namespacedName(c.instance.ObjectMeta)
return cm
return c
} }
// Marshal resource to yaml. // Marshal resource to yaml.
func (r *Ingress) Marshal(path string) (string, error) { func (r *Ingress) Marshal(path string) (string, error) {
ns, n := namespaced(path) ns, n := namespaced(path)
i, err := r.caller.Get(ns, n) i, err := r.resource.Get(ns, n)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -68,6 +60,7 @@ func (r *Ingress) Marshal(path string) (string, error) {
ing := i.(*v1beta1.Ingress) ing := i.(*v1beta1.Ingress)
ing.TypeMeta.APIVersion = "extensions/v1beta1" ing.TypeMeta.APIVersion = "extensions/v1beta1"
ing.TypeMeta.Kind = "Ingress" ing.TypeMeta.Kind = "Ingress"
return r.marshalObject(ing) return r.marshalObject(ing)
} }
@ -77,6 +70,7 @@ func (*Ingress) Header(ns string) Row {
if ns == AllNamespaces { if ns == AllNamespaces {
hh = append(hh, "NAMESPACE") hh = append(hh, "NAMESPACE")
} }
return append(hh, "NAME", "HOSTS", "ADDRESS", "PORT", "AGE") return append(hh, "NAME", "HOSTS", "ADDRESS", "PORT", "AGE")
} }
@ -98,11 +92,7 @@ func (r *Ingress) Fields(ns string) Row {
) )
} }
// ExtFields returns extended fields in relation to headers. // ----------------------------------------------------------------------------
func (*Ingress) ExtFields() Properties {
return Properties{}
}
// Helpers... // Helpers...
func (*Ingress) toAddress(lbs v1.LoadBalancerStatus) string { func (*Ingress) toAddress(lbs v1.LoadBalancerStatus) string {
@ -115,6 +105,7 @@ func (*Ingress) toAddress(lbs v1.LoadBalancerStatus) string {
res = append(res, lb.Hostname) res = append(res, lb.Hostname)
} }
} }
return strings.Join(res, ",") return strings.Join(res, ",")
} }
@ -122,6 +113,7 @@ func (*Ingress) toPorts(tls []v1beta1.IngressTLS) string {
if len(tls) != 0 { if len(tls) != 0 {
return "80, 443" return "80, 443"
} }
return "80" return "80"
} }
@ -135,5 +127,6 @@ func (*Ingress) toHosts(rr []v1beta1.IngressRule) string {
} }
i++ i++
} }
return s return s
} }

View File

@ -62,7 +62,6 @@ func TestIngressListData(t *testing.T) {
td := l.Data() td := l.Data()
assert.Equal(t, 1, len(td.Rows)) assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.NotNamespaced, l.GetNamespace()) assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"] row := td.Rows["blee/fred"]
assert.Equal(t, 5, len(row.Deltas)) assert.Equal(t, 5, len(row.Deltas))
for _, d := range row.Deltas { for _, d := range row.Deltas {
@ -71,19 +70,6 @@ func TestIngressListData(t *testing.T) {
assert.Equal(t, resource.Row{"fred"}, row.Fields[:1]) assert.Equal(t, resource.Row{"fred"}, row.Fields[:1])
} }
func TestIngressListDescribe(t *testing.T) {
setup(t)
ca := NewMockCaller()
m.When(ca.Get("blee", "fred")).ThenReturn(k8sIngress(), nil)
l := resource.NewIngressListWithArgs("blee", resource.NewIngressWithArgs(ca))
props, err := l.Describe("blee/fred")
ca.VerifyWasCalledOnce().Get("blee", "fred")
assert.Nil(t, err)
assert.Equal(t, 0, len(props))
}
// Helpers... // Helpers...
func k8sIngress() *v1beta1.Ingress { func k8sIngress() *v1beta1.Ingress {

View File

@ -19,51 +19,43 @@ type Job struct {
} }
// NewJobList returns a new resource list. // NewJobList returns a new resource list.
func NewJobList(ns string) List { func NewJobList(c k8s.Connection, ns string) List {
return NewJobListWithArgs(ns, NewJob()) return newList(
} ns,
"job",
// NewJobListWithArgs returns a new resource list. NewJob(c),
func NewJobListWithArgs(ns string, res Resource) List { AllVerbsAccess|DescribeAccess,
return newList(ns, "job", res, AllVerbsAccess|DescribeAccess) )
} }
// NewJob instantiates a new Job. // NewJob instantiates a new Job.
func NewJob() *Job { func NewJob(c k8s.Connection) *Job {
return NewJobWithArgs(k8s.NewJob()) j := &Job{&Base{connection: c, resource: k8s.NewJob(c)}, nil}
j.Factory = j
return j
} }
// NewJobWithArgs instantiates a new Job. // New builds a new Job instance from a k8s resource.
func NewJobWithArgs(r k8s.Res) *Job { func (r *Job) New(i interface{}) Columnar {
cm := &Job{ c := NewJob(r.connection)
Base: &Base{ switch instance := i.(type) {
caller: r,
},
}
cm.creator = cm
return cm
}
// NewInstance builds a new Job instance from a k8s resource.
func (*Job) NewInstance(i interface{}) Columnar {
job := NewJob()
switch i.(type) {
case *v1.Job: case *v1.Job:
job.instance = i.(*v1.Job) c.instance = instance
case v1.Job: case v1.Job:
ii := i.(v1.Job) c.instance = &instance
job.instance = &ii
default: default:
log.Fatal().Msgf("Unknown %#v", i) log.Fatal().Msgf("unknown Job type %#v", i)
} }
job.path = job.namespacedName(job.instance.ObjectMeta) c.path = c.namespacedName(c.instance.ObjectMeta)
return job
return c
} }
// Marshal resource to yaml. // Marshal resource to yaml.
func (r *Job) Marshal(path string) (string, error) { func (r *Job) Marshal(path string) (string, error) {
ns, n := namespaced(path) ns, n := namespaced(path)
i, err := r.caller.Get(ns, n) i, err := r.resource.Get(ns, n)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -71,18 +63,20 @@ func (r *Job) Marshal(path string) (string, error) {
jo := i.(*v1.Job) jo := i.(*v1.Job)
jo.TypeMeta.APIVersion = "extensions/v1beta1" jo.TypeMeta.APIVersion = "extensions/v1beta1"
jo.TypeMeta.Kind = "Job" jo.TypeMeta.Kind = "Job"
return r.marshalObject(jo) return r.marshalObject(jo)
} }
// Containers fetch all the containers on this job, may include init containers. // Containers fetch all the containers on this job, may include init containers.
func (r *Job) Containers(path string, includeInit bool) ([]string, error) { func (r *Job) Containers(path string, includeInit bool) ([]string, error) {
ns, n := namespaced(path) ns, n := namespaced(path)
return r.caller.(k8s.Loggable).Containers(ns, n, includeInit)
return r.resource.(k8s.Loggable).Containers(ns, n, includeInit)
} }
// Logs retrieves logs for a given container. // Logs retrieves logs for a given container.
func (r *Job) Logs(c chan<- string, ns, n, co string, lines int64, prev bool) (context.CancelFunc, error) { func (r *Job) Logs(c chan<- string, ns, n, co string, lines int64, prev bool) (context.CancelFunc, error) {
req := r.caller.(k8s.Loggable).Logs(ns, n, co, lines, prev) req := r.resource.(k8s.Loggable).Logs(ns, n, co, lines, prev)
ctx, cancel := context.WithCancel(context.TODO()) ctx, cancel := context.WithCancel(context.TODO())
req.Context(ctx) req.Context(ctx)
@ -116,6 +110,7 @@ func (r *Job) Logs(c chan<- string, ns, n, co string, lines int64, prev bool) (c
c <- scanner.Text() c <- scanner.Text()
} }
}() }()
return cancel, nil return cancel, nil
} }
@ -125,6 +120,7 @@ func (*Job) Header(ns string) Row {
if ns == AllNamespaces { if ns == AllNamespaces {
hh = append(hh, "NAMESPACE") hh = append(hh, "NAMESPACE")
} }
return append(hh, "NAME", "COMPLETIONS", "DURATION", "AGE") return append(hh, "NAME", "COMPLETIONS", "DURATION", "AGE")
} }
@ -136,6 +132,7 @@ func (r *Job) Fields(ns string) Row {
if ns == AllNamespaces { if ns == AllNamespaces {
ff = append(ff, i.Namespace) ff = append(ff, i.Namespace)
} }
return append(ff, return append(ff,
i.Name, i.Name,
r.toCompletion(i.Spec, i.Status), r.toCompletion(i.Spec, i.Status),
@ -144,11 +141,7 @@ func (r *Job) Fields(ns string) Row {
) )
} }
// ExtFields returns extended fields in relation to headers. // ----------------------------------------------------------------------------
func (*Job) ExtFields() Properties {
return Properties{}
}
// Helpers... // Helpers...
func (*Job) toCompletion(spec v1.JobSpec, status v1.JobStatus) (s string) { func (*Job) toCompletion(spec v1.JobSpec, status v1.JobStatus) (s string) {
@ -162,6 +155,7 @@ func (*Job) toCompletion(spec v1.JobSpec, status v1.JobStatus) (s string) {
if parallelism > 1 { if parallelism > 1 {
return fmt.Sprintf("%d/1 of %d", status.Succeeded, parallelism) return fmt.Sprintf("%d/1 of %d", status.Succeeded, parallelism)
} }
return fmt.Sprintf("%d/1", status.Succeeded) return fmt.Sprintf("%d/1", status.Succeeded)
} }
@ -171,5 +165,6 @@ func (*Job) toDuration(status v1.JobStatus) string {
case status.CompletionTime == nil: case status.CompletionTime == nil:
return duration.HumanDuration(time.Since(status.StartTime.Time)) return duration.HumanDuration(time.Since(status.StartTime.Time))
} }
return duration.HumanDuration(status.CompletionTime.Sub(status.StartTime.Time)) return duration.HumanDuration(status.CompletionTime.Sub(status.StartTime.Time))
} }

View File

@ -62,7 +62,6 @@ func TestJobListData(t *testing.T) {
td := l.Data() td := l.Data()
assert.Equal(t, 1, len(td.Rows)) assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.NotNamespaced, l.GetNamespace()) assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"] row := td.Rows["blee/fred"]
assert.Equal(t, 4, len(row.Deltas)) assert.Equal(t, 4, len(row.Deltas))
for _, d := range row.Deltas { for _, d := range row.Deltas {
@ -71,19 +70,6 @@ func TestJobListData(t *testing.T) {
assert.Equal(t, resource.Row{"fred"}, row.Fields[:1]) assert.Equal(t, resource.Row{"fred"}, row.Fields[:1])
} }
func TestJobListDescribe(t *testing.T) {
setup(t)
ca := NewMockCaller()
m.When(ca.Get("blee", "fred")).ThenReturn(k8sJob(), nil)
l := resource.NewJobListWithArgs("blee", resource.NewJobWithArgs(ca))
props, err := l.Describe("blee/fred")
ca.VerifyWasCalledOnce().Get("blee", "fred")
assert.Nil(t, err)
assert.Equal(t, 0, len(props))
}
// Helpers... // Helpers...
func k8sJob() *v1.Job { func k8sJob() *v1.Job {

View File

@ -3,8 +3,8 @@ package resource
import ( import (
"reflect" "reflect"
"github.com/derailed/k9s/internal/k8s"
"k8s.io/apimachinery/pkg/watch" "k8s.io/apimachinery/pkg/watch"
"k8s.io/cli-runtime/pkg/genericclioptions"
) )
const ( const (
@ -63,10 +63,8 @@ type (
GetNamespace() string GetNamespace() string
SetNamespace(string) SetNamespace(string)
Reconcile() error Reconcile() error
Describe(pa string) (Properties, error)
GetName() string GetName() string
Access(flag int) bool Access(flag int) bool
HasXRay() bool
} }
// Columnar tracks resources that can be diplayed in a tabular fashion. // Columnar tracks resources that can be diplayed in a tabular fashion.
@ -86,20 +84,13 @@ type (
// Columnars a collection of columnars. // Columnars a collection of columnars.
Columnars []Columnar Columnars []Columnar
// MxColumnar tracks resource metrics.
MxColumnar interface {
Columnar
Metrics() k8s.Metric
SetMetrics(k8s.Metric)
}
// Resource tracks generic Kubernetes resources. // Resource tracks generic Kubernetes resources.
Resource interface { Resource interface {
NewInstance(interface{}) Columnar New(interface{}) Columnar
Get(path string) (Columnar, error) Get(path string) (Columnar, error)
List(ns string) (Columnars, error) List(ns string) (Columnars, error)
Delete(path string) error Delete(path string) error
Describe(kind, pa string) (string, error) Describe(kind, pa string, flags *genericclioptions.ConfigFlags) (string, error)
Marshal(pa string) (string, error) Marshal(pa string) (string, error)
Header(ns string) Row Header(ns string) Row
} }
@ -107,8 +98,7 @@ type (
list struct { list struct {
namespace, name string namespace, name string
verbs int verbs int
xray bool resource Resource
api Resource
cache RowEvents cache RowEvents
} }
) )
@ -117,20 +107,16 @@ func newRowEvent(a watch.EventType, f, d Row) *RowEvent {
return &RowEvent{Action: a, Fields: f, Deltas: d} return &RowEvent{Action: a, Fields: f, Deltas: d}
} }
func newList(ns, name string, api Resource, v int) *list { func newList(ns, name string, res Resource, verbs int) *list {
return &list{ return &list{
namespace: ns, namespace: ns,
name: name, name: name,
verbs: v, verbs: verbs,
api: api, resource: res,
cache: RowEvents{}, cache: RowEvents{},
} }
} }
func (l *list) HasXRay() bool {
return l.xray
}
// Access check access control on a given resource. // Access check access control on a given resource.
func (l *list) Access(f int) bool { func (l *list) Access(f int) bool {
return l.verbs&f == f return l.verbs&f == f
@ -151,6 +137,7 @@ func (l *list) GetNamespace() string {
if !l.Access(NamespaceAccess) { if !l.Access(NamespaceAccess) {
l.namespace = NotNamespaced l.namespace = NotNamespaced
} }
return l.namespace return l.namespace
} }
@ -179,28 +166,18 @@ func (l *list) GetName() string {
// Resource returns a resource api connection. // Resource returns a resource api connection.
func (l *list) Resource() Resource { func (l *list) Resource() Resource {
return l.api return l.resource
} }
// Cache tracks previous resource state. // Cache tracks previous resource state.
func (l *list) Data() TableData { func (l *list) Data() TableData {
return TableData{ return TableData{
Header: l.api.Header(l.namespace), Header: l.resource.Header(l.namespace),
Rows: l.cache, Rows: l.cache,
Namespace: l.namespace, Namespace: l.namespace,
} }
} }
func (l *list) Describe(pa string) (Properties, error) {
var p Properties
i, err := l.api.Get(pa)
if err != nil {
return p, err
}
return i.ExtFields(), nil
}
// Reconcile previous vs current state and emits delta events. // Reconcile previous vs current state and emits delta events.
func (l *list) Reconcile() error { func (l *list) Reconcile() error {
var ( var (
@ -208,7 +185,7 @@ func (l *list) Reconcile() error {
err error err error
) )
if items, err = l.api.List(l.namespace); err != nil { if items, err = l.resource.List(l.namespace); err != nil {
return err return err
} }
@ -254,5 +231,6 @@ func (l *list) Reconcile() error {
delete(l.cache, k) delete(l.cache, k)
} }
} }
return nil return nil
} }

View File

@ -1,187 +0,0 @@
// Code generated by pegomock. DO NOT EDIT.
// Source: github.com/derailed/k9s/internal/resource (interfaces: ClusterIfc)
package resource_test
import (
pegomock "github.com/petergtz/pegomock"
"reflect"
"time"
)
type MockClusterIfc struct {
fail func(message string, callerSkip ...int)
}
func NewMockClusterIfc() *MockClusterIfc {
return &MockClusterIfc{fail: pegomock.GlobalFailHandler}
}
func (mock *MockClusterIfc) ClusterName() string {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClusterIfc().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("ClusterName", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem()})
var ret0 string
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(string)
}
}
return ret0
}
func (mock *MockClusterIfc) ContextName() string {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClusterIfc().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("ContextName", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem()})
var ret0 string
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(string)
}
}
return ret0
}
func (mock *MockClusterIfc) UserName() string {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClusterIfc().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("UserName", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem()})
var ret0 string
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(string)
}
}
return ret0
}
func (mock *MockClusterIfc) Version() (string, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClusterIfc().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("Version", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 string
var ret1 error
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(string)
}
if result[1] != nil {
ret1 = result[1].(error)
}
}
return ret0, ret1
}
func (mock *MockClusterIfc) VerifyWasCalledOnce() *VerifierClusterIfc {
return &VerifierClusterIfc{
mock: mock,
invocationCountMatcher: pegomock.Times(1),
}
}
func (mock *MockClusterIfc) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierClusterIfc {
return &VerifierClusterIfc{
mock: mock,
invocationCountMatcher: invocationCountMatcher,
}
}
func (mock *MockClusterIfc) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierClusterIfc {
return &VerifierClusterIfc{
mock: mock,
invocationCountMatcher: invocationCountMatcher,
inOrderContext: inOrderContext,
}
}
func (mock *MockClusterIfc) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierClusterIfc {
return &VerifierClusterIfc{
mock: mock,
invocationCountMatcher: invocationCountMatcher,
timeout: timeout,
}
}
type VerifierClusterIfc struct {
mock *MockClusterIfc
invocationCountMatcher pegomock.Matcher
inOrderContext *pegomock.InOrderContext
timeout time.Duration
}
func (verifier *VerifierClusterIfc) ClusterName() *ClusterIfc_ClusterName_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ClusterName", params, verifier.timeout)
return &ClusterIfc_ClusterName_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type ClusterIfc_ClusterName_OngoingVerification struct {
mock *MockClusterIfc
methodInvocations []pegomock.MethodInvocation
}
func (c *ClusterIfc_ClusterName_OngoingVerification) GetCapturedArguments() {
}
func (c *ClusterIfc_ClusterName_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierClusterIfc) ContextName() *ClusterIfc_ContextName_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ContextName", params, verifier.timeout)
return &ClusterIfc_ContextName_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type ClusterIfc_ContextName_OngoingVerification struct {
mock *MockClusterIfc
methodInvocations []pegomock.MethodInvocation
}
func (c *ClusterIfc_ContextName_OngoingVerification) GetCapturedArguments() {
}
func (c *ClusterIfc_ContextName_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierClusterIfc) UserName() *ClusterIfc_UserName_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UserName", params, verifier.timeout)
return &ClusterIfc_UserName_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type ClusterIfc_UserName_OngoingVerification struct {
mock *MockClusterIfc
methodInvocations []pegomock.MethodInvocation
}
func (c *ClusterIfc_UserName_OngoingVerification) GetCapturedArguments() {
}
func (c *ClusterIfc_UserName_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierClusterIfc) Version() *ClusterIfc_Version_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Version", params, verifier.timeout)
return &ClusterIfc_Version_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type ClusterIfc_Version_OngoingVerification struct {
mock *MockClusterIfc
methodInvocations []pegomock.MethodInvocation
}
func (c *ClusterIfc_Version_OngoingVerification) GetCapturedArguments() {
}
func (c *ClusterIfc_Version_OngoingVerification) GetAllCapturedArguments() {
}

View File

@ -0,0 +1,455 @@
// Code generated by pegomock. DO NOT EDIT.
// Source: github.com/derailed/k9s/internal/resource (interfaces: ClusterMeta)
package resource_test
import (
k8s "github.com/derailed/k9s/internal/k8s"
pegomock "github.com/petergtz/pegomock"
dynamic "k8s.io/client-go/dynamic"
kubernetes "k8s.io/client-go/kubernetes"
rest "k8s.io/client-go/rest"
versioned "k8s.io/metrics/pkg/client/clientset/versioned"
"reflect"
"time"
)
type MockClusterMeta struct {
fail func(message string, callerSkip ...int)
}
func NewMockClusterMeta() *MockClusterMeta {
return &MockClusterMeta{fail: pegomock.GlobalFailHandler}
}
func (mock *MockClusterMeta) ClusterName() string {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClusterMeta().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("ClusterName", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem()})
var ret0 string
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(string)
}
}
return ret0
}
func (mock *MockClusterMeta) Config() *k8s.Config {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClusterMeta().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("Config", params, []reflect.Type{reflect.TypeOf((**k8s.Config)(nil)).Elem()})
var ret0 *k8s.Config
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(*k8s.Config)
}
}
return ret0
}
func (mock *MockClusterMeta) ContextName() string {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClusterMeta().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("ContextName", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem()})
var ret0 string
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(string)
}
}
return ret0
}
func (mock *MockClusterMeta) DialOrDie() kubernetes.Interface {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClusterMeta().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("DialOrDie", params, []reflect.Type{reflect.TypeOf((*kubernetes.Interface)(nil)).Elem()})
var ret0 kubernetes.Interface
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(kubernetes.Interface)
}
}
return ret0
}
func (mock *MockClusterMeta) DynDialOrDie() dynamic.Interface {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClusterMeta().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("DynDialOrDie", params, []reflect.Type{reflect.TypeOf((*dynamic.Interface)(nil)).Elem()})
var ret0 dynamic.Interface
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(dynamic.Interface)
}
}
return ret0
}
func (mock *MockClusterMeta) HasMetrics() bool {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClusterMeta().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("HasMetrics", params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem()})
var ret0 bool
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(bool)
}
}
return ret0
}
func (mock *MockClusterMeta) MXDial() (*versioned.Clientset, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClusterMeta().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("MXDial", params, []reflect.Type{reflect.TypeOf((**versioned.Clientset)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 *versioned.Clientset
var ret1 error
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(*versioned.Clientset)
}
if result[1] != nil {
ret1 = result[1].(error)
}
}
return ret0, ret1
}
func (mock *MockClusterMeta) NSDialOrDie() dynamic.NamespaceableResourceInterface {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClusterMeta().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("NSDialOrDie", params, []reflect.Type{reflect.TypeOf((*dynamic.NamespaceableResourceInterface)(nil)).Elem()})
var ret0 dynamic.NamespaceableResourceInterface
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(dynamic.NamespaceableResourceInterface)
}
}
return ret0
}
func (mock *MockClusterMeta) RestConfigOrDie() *rest.Config {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClusterMeta().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("RestConfigOrDie", params, []reflect.Type{reflect.TypeOf((**rest.Config)(nil)).Elem()})
var ret0 *rest.Config
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(*rest.Config)
}
}
return ret0
}
func (mock *MockClusterMeta) SwitchContextOrDie(_param0 string) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClusterMeta().")
}
params := []pegomock.Param{_param0}
pegomock.GetGenericMockFrom(mock).Invoke("SwitchContextOrDie", params, []reflect.Type{})
}
func (mock *MockClusterMeta) UserName() string {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClusterMeta().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("UserName", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem()})
var ret0 string
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(string)
}
}
return ret0
}
func (mock *MockClusterMeta) Version() (string, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClusterMeta().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("Version", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 string
var ret1 error
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(string)
}
if result[1] != nil {
ret1 = result[1].(error)
}
}
return ret0, ret1
}
func (mock *MockClusterMeta) VerifyWasCalledOnce() *VerifierClusterMeta {
return &VerifierClusterMeta{
mock: mock,
invocationCountMatcher: pegomock.Times(1),
}
}
func (mock *MockClusterMeta) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierClusterMeta {
return &VerifierClusterMeta{
mock: mock,
invocationCountMatcher: invocationCountMatcher,
}
}
func (mock *MockClusterMeta) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierClusterMeta {
return &VerifierClusterMeta{
mock: mock,
invocationCountMatcher: invocationCountMatcher,
inOrderContext: inOrderContext,
}
}
func (mock *MockClusterMeta) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierClusterMeta {
return &VerifierClusterMeta{
mock: mock,
invocationCountMatcher: invocationCountMatcher,
timeout: timeout,
}
}
type VerifierClusterMeta struct {
mock *MockClusterMeta
invocationCountMatcher pegomock.Matcher
inOrderContext *pegomock.InOrderContext
timeout time.Duration
}
func (verifier *VerifierClusterMeta) ClusterName() *ClusterMeta_ClusterName_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ClusterName", params, verifier.timeout)
return &ClusterMeta_ClusterName_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type ClusterMeta_ClusterName_OngoingVerification struct {
mock *MockClusterMeta
methodInvocations []pegomock.MethodInvocation
}
func (c *ClusterMeta_ClusterName_OngoingVerification) GetCapturedArguments() {
}
func (c *ClusterMeta_ClusterName_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierClusterMeta) Config() *ClusterMeta_Config_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Config", params, verifier.timeout)
return &ClusterMeta_Config_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type ClusterMeta_Config_OngoingVerification struct {
mock *MockClusterMeta
methodInvocations []pegomock.MethodInvocation
}
func (c *ClusterMeta_Config_OngoingVerification) GetCapturedArguments() {
}
func (c *ClusterMeta_Config_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierClusterMeta) ContextName() *ClusterMeta_ContextName_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ContextName", params, verifier.timeout)
return &ClusterMeta_ContextName_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type ClusterMeta_ContextName_OngoingVerification struct {
mock *MockClusterMeta
methodInvocations []pegomock.MethodInvocation
}
func (c *ClusterMeta_ContextName_OngoingVerification) GetCapturedArguments() {
}
func (c *ClusterMeta_ContextName_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierClusterMeta) DialOrDie() *ClusterMeta_DialOrDie_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "DialOrDie", params, verifier.timeout)
return &ClusterMeta_DialOrDie_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type ClusterMeta_DialOrDie_OngoingVerification struct {
mock *MockClusterMeta
methodInvocations []pegomock.MethodInvocation
}
func (c *ClusterMeta_DialOrDie_OngoingVerification) GetCapturedArguments() {
}
func (c *ClusterMeta_DialOrDie_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierClusterMeta) DynDialOrDie() *ClusterMeta_DynDialOrDie_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "DynDialOrDie", params, verifier.timeout)
return &ClusterMeta_DynDialOrDie_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type ClusterMeta_DynDialOrDie_OngoingVerification struct {
mock *MockClusterMeta
methodInvocations []pegomock.MethodInvocation
}
func (c *ClusterMeta_DynDialOrDie_OngoingVerification) GetCapturedArguments() {
}
func (c *ClusterMeta_DynDialOrDie_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierClusterMeta) HasMetrics() *ClusterMeta_HasMetrics_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "HasMetrics", params, verifier.timeout)
return &ClusterMeta_HasMetrics_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type ClusterMeta_HasMetrics_OngoingVerification struct {
mock *MockClusterMeta
methodInvocations []pegomock.MethodInvocation
}
func (c *ClusterMeta_HasMetrics_OngoingVerification) GetCapturedArguments() {
}
func (c *ClusterMeta_HasMetrics_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierClusterMeta) MXDial() *ClusterMeta_MXDial_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "MXDial", params, verifier.timeout)
return &ClusterMeta_MXDial_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type ClusterMeta_MXDial_OngoingVerification struct {
mock *MockClusterMeta
methodInvocations []pegomock.MethodInvocation
}
func (c *ClusterMeta_MXDial_OngoingVerification) GetCapturedArguments() {
}
func (c *ClusterMeta_MXDial_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierClusterMeta) NSDialOrDie() *ClusterMeta_NSDialOrDie_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "NSDialOrDie", params, verifier.timeout)
return &ClusterMeta_NSDialOrDie_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type ClusterMeta_NSDialOrDie_OngoingVerification struct {
mock *MockClusterMeta
methodInvocations []pegomock.MethodInvocation
}
func (c *ClusterMeta_NSDialOrDie_OngoingVerification) GetCapturedArguments() {
}
func (c *ClusterMeta_NSDialOrDie_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierClusterMeta) RestConfigOrDie() *ClusterMeta_RestConfigOrDie_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "RestConfigOrDie", params, verifier.timeout)
return &ClusterMeta_RestConfigOrDie_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type ClusterMeta_RestConfigOrDie_OngoingVerification struct {
mock *MockClusterMeta
methodInvocations []pegomock.MethodInvocation
}
func (c *ClusterMeta_RestConfigOrDie_OngoingVerification) GetCapturedArguments() {
}
func (c *ClusterMeta_RestConfigOrDie_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierClusterMeta) SwitchContextOrDie(_param0 string) *ClusterMeta_SwitchContextOrDie_OngoingVerification {
params := []pegomock.Param{_param0}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "SwitchContextOrDie", params, verifier.timeout)
return &ClusterMeta_SwitchContextOrDie_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type ClusterMeta_SwitchContextOrDie_OngoingVerification struct {
mock *MockClusterMeta
methodInvocations []pegomock.MethodInvocation
}
func (c *ClusterMeta_SwitchContextOrDie_OngoingVerification) GetCapturedArguments() string {
_param0 := c.GetAllCapturedArguments()
return _param0[len(_param0)-1]
}
func (c *ClusterMeta_SwitchContextOrDie_OngoingVerification) GetAllCapturedArguments() (_param0 []string) {
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(params) > 0 {
_param0 = make([]string, len(params[0]))
for u, param := range params[0] {
_param0[u] = param.(string)
}
}
return
}
func (verifier *VerifierClusterMeta) UserName() *ClusterMeta_UserName_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "UserName", params, verifier.timeout)
return &ClusterMeta_UserName_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type ClusterMeta_UserName_OngoingVerification struct {
mock *MockClusterMeta
methodInvocations []pegomock.MethodInvocation
}
func (c *ClusterMeta_UserName_OngoingVerification) GetCapturedArguments() {
}
func (c *ClusterMeta_UserName_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierClusterMeta) Version() *ClusterMeta_Version_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Version", params, verifier.timeout)
return &ClusterMeta_Version_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type ClusterMeta_Version_OngoingVerification struct {
mock *MockClusterMeta
methodInvocations []pegomock.MethodInvocation
}
func (c *ClusterMeta_Version_OngoingVerification) GetCapturedArguments() {
}
func (c *ClusterMeta_Version_OngoingVerification) GetAllCapturedArguments() {
}

View File

@ -0,0 +1,323 @@
// Code generated by pegomock. DO NOT EDIT.
// Source: github.com/derailed/k9s/internal/resource (interfaces: Connection)
package resource_test
import (
k8s "github.com/derailed/k9s/internal/k8s"
pegomock "github.com/petergtz/pegomock"
dynamic "k8s.io/client-go/dynamic"
kubernetes "k8s.io/client-go/kubernetes"
rest "k8s.io/client-go/rest"
versioned "k8s.io/metrics/pkg/client/clientset/versioned"
"reflect"
"time"
)
type MockConnection struct {
fail func(message string, callerSkip ...int)
}
func NewMockConnection() *MockConnection {
return &MockConnection{fail: pegomock.GlobalFailHandler}
}
func (mock *MockConnection) Config() *k8s.Config {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockConnection().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("Config", params, []reflect.Type{reflect.TypeOf((**k8s.Config)(nil)).Elem()})
var ret0 *k8s.Config
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(*k8s.Config)
}
}
return ret0
}
func (mock *MockConnection) DialOrDie() kubernetes.Interface {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockConnection().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("DialOrDie", params, []reflect.Type{reflect.TypeOf((*kubernetes.Interface)(nil)).Elem()})
var ret0 kubernetes.Interface
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(kubernetes.Interface)
}
}
return ret0
}
func (mock *MockConnection) DynDialOrDie() dynamic.Interface {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockConnection().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("DynDialOrDie", params, []reflect.Type{reflect.TypeOf((*dynamic.Interface)(nil)).Elem()})
var ret0 dynamic.Interface
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(dynamic.Interface)
}
}
return ret0
}
func (mock *MockConnection) HasMetrics() bool {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockConnection().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("HasMetrics", params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem()})
var ret0 bool
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(bool)
}
}
return ret0
}
func (mock *MockConnection) MXDial() (*versioned.Clientset, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockConnection().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("MXDial", params, []reflect.Type{reflect.TypeOf((**versioned.Clientset)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 *versioned.Clientset
var ret1 error
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(*versioned.Clientset)
}
if result[1] != nil {
ret1 = result[1].(error)
}
}
return ret0, ret1
}
func (mock *MockConnection) NSDialOrDie() dynamic.NamespaceableResourceInterface {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockConnection().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("NSDialOrDie", params, []reflect.Type{reflect.TypeOf((*dynamic.NamespaceableResourceInterface)(nil)).Elem()})
var ret0 dynamic.NamespaceableResourceInterface
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(dynamic.NamespaceableResourceInterface)
}
}
return ret0
}
func (mock *MockConnection) RestConfigOrDie() *rest.Config {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockConnection().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("RestConfigOrDie", params, []reflect.Type{reflect.TypeOf((**rest.Config)(nil)).Elem()})
var ret0 *rest.Config
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(*rest.Config)
}
}
return ret0
}
func (mock *MockConnection) SwitchContextOrDie(_param0 string) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockConnection().")
}
params := []pegomock.Param{_param0}
pegomock.GetGenericMockFrom(mock).Invoke("SwitchContextOrDie", params, []reflect.Type{})
}
func (mock *MockConnection) VerifyWasCalledOnce() *VerifierConnection {
return &VerifierConnection{
mock: mock,
invocationCountMatcher: pegomock.Times(1),
}
}
func (mock *MockConnection) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierConnection {
return &VerifierConnection{
mock: mock,
invocationCountMatcher: invocationCountMatcher,
}
}
func (mock *MockConnection) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierConnection {
return &VerifierConnection{
mock: mock,
invocationCountMatcher: invocationCountMatcher,
inOrderContext: inOrderContext,
}
}
func (mock *MockConnection) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierConnection {
return &VerifierConnection{
mock: mock,
invocationCountMatcher: invocationCountMatcher,
timeout: timeout,
}
}
type VerifierConnection struct {
mock *MockConnection
invocationCountMatcher pegomock.Matcher
inOrderContext *pegomock.InOrderContext
timeout time.Duration
}
func (verifier *VerifierConnection) Config() *Connection_Config_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Config", params, verifier.timeout)
return &Connection_Config_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type Connection_Config_OngoingVerification struct {
mock *MockConnection
methodInvocations []pegomock.MethodInvocation
}
func (c *Connection_Config_OngoingVerification) GetCapturedArguments() {
}
func (c *Connection_Config_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierConnection) DialOrDie() *Connection_DialOrDie_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "DialOrDie", params, verifier.timeout)
return &Connection_DialOrDie_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type Connection_DialOrDie_OngoingVerification struct {
mock *MockConnection
methodInvocations []pegomock.MethodInvocation
}
func (c *Connection_DialOrDie_OngoingVerification) GetCapturedArguments() {
}
func (c *Connection_DialOrDie_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierConnection) DynDialOrDie() *Connection_DynDialOrDie_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "DynDialOrDie", params, verifier.timeout)
return &Connection_DynDialOrDie_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type Connection_DynDialOrDie_OngoingVerification struct {
mock *MockConnection
methodInvocations []pegomock.MethodInvocation
}
func (c *Connection_DynDialOrDie_OngoingVerification) GetCapturedArguments() {
}
func (c *Connection_DynDialOrDie_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierConnection) HasMetrics() *Connection_HasMetrics_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "HasMetrics", params, verifier.timeout)
return &Connection_HasMetrics_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type Connection_HasMetrics_OngoingVerification struct {
mock *MockConnection
methodInvocations []pegomock.MethodInvocation
}
func (c *Connection_HasMetrics_OngoingVerification) GetCapturedArguments() {
}
func (c *Connection_HasMetrics_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierConnection) MXDial() *Connection_MXDial_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "MXDial", params, verifier.timeout)
return &Connection_MXDial_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type Connection_MXDial_OngoingVerification struct {
mock *MockConnection
methodInvocations []pegomock.MethodInvocation
}
func (c *Connection_MXDial_OngoingVerification) GetCapturedArguments() {
}
func (c *Connection_MXDial_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierConnection) NSDialOrDie() *Connection_NSDialOrDie_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "NSDialOrDie", params, verifier.timeout)
return &Connection_NSDialOrDie_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type Connection_NSDialOrDie_OngoingVerification struct {
mock *MockConnection
methodInvocations []pegomock.MethodInvocation
}
func (c *Connection_NSDialOrDie_OngoingVerification) GetCapturedArguments() {
}
func (c *Connection_NSDialOrDie_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierConnection) RestConfigOrDie() *Connection_RestConfigOrDie_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "RestConfigOrDie", params, verifier.timeout)
return &Connection_RestConfigOrDie_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type Connection_RestConfigOrDie_OngoingVerification struct {
mock *MockConnection
methodInvocations []pegomock.MethodInvocation
}
func (c *Connection_RestConfigOrDie_OngoingVerification) GetCapturedArguments() {
}
func (c *Connection_RestConfigOrDie_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierConnection) SwitchContextOrDie(_param0 string) *Connection_SwitchContextOrDie_OngoingVerification {
params := []pegomock.Param{_param0}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "SwitchContextOrDie", params, verifier.timeout)
return &Connection_SwitchContextOrDie_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type Connection_SwitchContextOrDie_OngoingVerification struct {
mock *MockConnection
methodInvocations []pegomock.MethodInvocation
}
func (c *Connection_SwitchContextOrDie_OngoingVerification) GetCapturedArguments() string {
_param0 := c.GetAllCapturedArguments()
return _param0[len(_param0)-1]
}
func (c *Connection_SwitchContextOrDie_OngoingVerification) GetAllCapturedArguments() (_param0 []string) {
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(params) > 0 {
_param0 = make([]string, len(params[0]))
for u, param := range params[0] {
_param0[u] = param.(string)
}
}
return
}

View File

@ -1,5 +1,5 @@
// Code generated by pegomock. DO NOT EDIT. // Code generated by pegomock. DO NOT EDIT.
// Source: github.com/derailed/k9s/internal/resource (interfaces: Caller) // Source: github.com/derailed/k9s/internal/resource (interfaces: Cruder)
package resource_test package resource_test
@ -10,17 +10,17 @@ import (
"time" "time"
) )
type MockCaller struct { type MockCruder struct {
fail func(message string, callerSkip ...int) fail func(message string, callerSkip ...int)
} }
func NewMockCaller() *MockCaller { func NewMockCruder() *MockCruder {
return &MockCaller{fail: pegomock.GlobalFailHandler} return &MockCruder{fail: pegomock.GlobalFailHandler}
} }
func (mock *MockCaller) Delete(_param0 string, _param1 string) error { func (mock *MockCruder) Delete(_param0 string, _param1 string) error {
if mock == nil { if mock == nil {
panic("mock must not be nil. Use myMock := NewMockCaller().") panic("mock must not be nil. Use myMock := NewMockCruder().")
} }
params := []pegomock.Param{_param0, _param1} params := []pegomock.Param{_param0, _param1}
result := pegomock.GetGenericMockFrom(mock).Invoke("Delete", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()}) result := pegomock.GetGenericMockFrom(mock).Invoke("Delete", params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()})
@ -33,9 +33,9 @@ func (mock *MockCaller) Delete(_param0 string, _param1 string) error {
return ret0 return ret0
} }
func (mock *MockCaller) Get(_param0 string, _param1 string) (interface{}, error) { func (mock *MockCruder) Get(_param0 string, _param1 string) (interface{}, error) {
if mock == nil { if mock == nil {
panic("mock must not be nil. Use myMock := NewMockCaller().") panic("mock must not be nil. Use myMock := NewMockCruder().")
} }
params := []pegomock.Param{_param0, _param1} params := []pegomock.Param{_param0, _param1}
result := pegomock.GetGenericMockFrom(mock).Invoke("Get", params, []reflect.Type{reflect.TypeOf((*interface{})(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) result := pegomock.GetGenericMockFrom(mock).Invoke("Get", params, []reflect.Type{reflect.TypeOf((*interface{})(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
@ -52,9 +52,9 @@ func (mock *MockCaller) Get(_param0 string, _param1 string) (interface{}, error)
return ret0, ret1 return ret0, ret1
} }
func (mock *MockCaller) List(_param0 string) (k8s.Collection, error) { func (mock *MockCruder) List(_param0 string) (k8s.Collection, error) {
if mock == nil { if mock == nil {
panic("mock must not be nil. Use myMock := NewMockCaller().") panic("mock must not be nil. Use myMock := NewMockCruder().")
} }
params := []pegomock.Param{_param0} params := []pegomock.Param{_param0}
result := pegomock.GetGenericMockFrom(mock).Invoke("List", params, []reflect.Type{reflect.TypeOf((*k8s.Collection)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()}) result := pegomock.GetGenericMockFrom(mock).Invoke("List", params, []reflect.Type{reflect.TypeOf((*k8s.Collection)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
@ -71,60 +71,60 @@ func (mock *MockCaller) List(_param0 string) (k8s.Collection, error) {
return ret0, ret1 return ret0, ret1
} }
func (mock *MockCaller) VerifyWasCalledOnce() *VerifierCaller { func (mock *MockCruder) VerifyWasCalledOnce() *VerifierCruder {
return &VerifierCaller{ return &VerifierCruder{
mock: mock, mock: mock,
invocationCountMatcher: pegomock.Times(1), invocationCountMatcher: pegomock.Times(1),
} }
} }
func (mock *MockCaller) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierCaller { func (mock *MockCruder) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierCruder {
return &VerifierCaller{ return &VerifierCruder{
mock: mock, mock: mock,
invocationCountMatcher: invocationCountMatcher, invocationCountMatcher: invocationCountMatcher,
} }
} }
func (mock *MockCaller) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierCaller { func (mock *MockCruder) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierCruder {
return &VerifierCaller{ return &VerifierCruder{
mock: mock, mock: mock,
invocationCountMatcher: invocationCountMatcher, invocationCountMatcher: invocationCountMatcher,
inOrderContext: inOrderContext, inOrderContext: inOrderContext,
} }
} }
func (mock *MockCaller) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierCaller { func (mock *MockCruder) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierCruder {
return &VerifierCaller{ return &VerifierCruder{
mock: mock, mock: mock,
invocationCountMatcher: invocationCountMatcher, invocationCountMatcher: invocationCountMatcher,
timeout: timeout, timeout: timeout,
} }
} }
type VerifierCaller struct { type VerifierCruder struct {
mock *MockCaller mock *MockCruder
invocationCountMatcher pegomock.Matcher invocationCountMatcher pegomock.Matcher
inOrderContext *pegomock.InOrderContext inOrderContext *pegomock.InOrderContext
timeout time.Duration timeout time.Duration
} }
func (verifier *VerifierCaller) Delete(_param0 string, _param1 string) *Caller_Delete_OngoingVerification { func (verifier *VerifierCruder) Delete(_param0 string, _param1 string) *Cruder_Delete_OngoingVerification {
params := []pegomock.Param{_param0, _param1} params := []pegomock.Param{_param0, _param1}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Delete", params, verifier.timeout) methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Delete", params, verifier.timeout)
return &Caller_Delete_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} return &Cruder_Delete_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
} }
type Caller_Delete_OngoingVerification struct { type Cruder_Delete_OngoingVerification struct {
mock *MockCaller mock *MockCruder
methodInvocations []pegomock.MethodInvocation methodInvocations []pegomock.MethodInvocation
} }
func (c *Caller_Delete_OngoingVerification) GetCapturedArguments() (string, string) { func (c *Cruder_Delete_OngoingVerification) GetCapturedArguments() (string, string) {
_param0, _param1 := c.GetAllCapturedArguments() _param0, _param1 := c.GetAllCapturedArguments()
return _param0[len(_param0)-1], _param1[len(_param1)-1] return _param0[len(_param0)-1], _param1[len(_param1)-1]
} }
func (c *Caller_Delete_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []string) { func (c *Cruder_Delete_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []string) {
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(params) > 0 { if len(params) > 0 {
_param0 = make([]string, len(params[0])) _param0 = make([]string, len(params[0]))
@ -139,23 +139,23 @@ func (c *Caller_Delete_OngoingVerification) GetAllCapturedArguments() (_param0 [
return return
} }
func (verifier *VerifierCaller) Get(_param0 string, _param1 string) *Caller_Get_OngoingVerification { func (verifier *VerifierCruder) Get(_param0 string, _param1 string) *Cruder_Get_OngoingVerification {
params := []pegomock.Param{_param0, _param1} params := []pegomock.Param{_param0, _param1}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Get", params, verifier.timeout) methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Get", params, verifier.timeout)
return &Caller_Get_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} return &Cruder_Get_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
} }
type Caller_Get_OngoingVerification struct { type Cruder_Get_OngoingVerification struct {
mock *MockCaller mock *MockCruder
methodInvocations []pegomock.MethodInvocation methodInvocations []pegomock.MethodInvocation
} }
func (c *Caller_Get_OngoingVerification) GetCapturedArguments() (string, string) { func (c *Cruder_Get_OngoingVerification) GetCapturedArguments() (string, string) {
_param0, _param1 := c.GetAllCapturedArguments() _param0, _param1 := c.GetAllCapturedArguments()
return _param0[len(_param0)-1], _param1[len(_param1)-1] return _param0[len(_param0)-1], _param1[len(_param1)-1]
} }
func (c *Caller_Get_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []string) { func (c *Cruder_Get_OngoingVerification) GetAllCapturedArguments() (_param0 []string, _param1 []string) {
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(params) > 0 { if len(params) > 0 {
_param0 = make([]string, len(params[0])) _param0 = make([]string, len(params[0]))
@ -170,23 +170,23 @@ func (c *Caller_Get_OngoingVerification) GetAllCapturedArguments() (_param0 []st
return return
} }
func (verifier *VerifierCaller) List(_param0 string) *Caller_List_OngoingVerification { func (verifier *VerifierCruder) List(_param0 string) *Cruder_List_OngoingVerification {
params := []pegomock.Param{_param0} params := []pegomock.Param{_param0}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "List", params, verifier.timeout) methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "List", params, verifier.timeout)
return &Caller_List_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations} return &Cruder_List_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
} }
type Caller_List_OngoingVerification struct { type Cruder_List_OngoingVerification struct {
mock *MockCaller mock *MockCruder
methodInvocations []pegomock.MethodInvocation methodInvocations []pegomock.MethodInvocation
} }
func (c *Caller_List_OngoingVerification) GetCapturedArguments() string { func (c *Cruder_List_OngoingVerification) GetCapturedArguments() string {
_param0 := c.GetAllCapturedArguments() _param0 := c.GetAllCapturedArguments()
return _param0[len(_param0)-1] return _param0[len(_param0)-1]
} }
func (c *Caller_List_OngoingVerification) GetAllCapturedArguments() (_param0 []string) { func (c *Cruder_List_OngoingVerification) GetAllCapturedArguments() (_param0 []string) {
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations) params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(params) > 0 { if len(params) > 0 {
_param0 = make([]string, len(params[0])) _param0 = make([]string, len(params[0]))

View File

@ -1,175 +0,0 @@
// Code generated by pegomock. DO NOT EDIT.
// Source: github.com/derailed/k9s/internal/resource (interfaces: MetricsIfc)
package resource_test
import (
k8s "github.com/derailed/k9s/internal/k8s"
pegomock "github.com/petergtz/pegomock"
v1 "k8s.io/api/core/v1"
"reflect"
"time"
)
type MockMetricsIfc struct {
fail func(message string, callerSkip ...int)
}
func NewMockMetricsIfc() *MockMetricsIfc {
return &MockMetricsIfc{fail: pegomock.GlobalFailHandler}
}
func (mock *MockMetricsIfc) NodeMetrics() (k8s.Metric, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockMetricsIfc().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("NodeMetrics", params, []reflect.Type{reflect.TypeOf((*k8s.Metric)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 k8s.Metric
var ret1 error
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(k8s.Metric)
}
if result[1] != nil {
ret1 = result[1].(error)
}
}
return ret0, ret1
}
func (mock *MockMetricsIfc) PerNodeMetrics(_param0 []v1.Node) (map[string]k8s.Metric, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockMetricsIfc().")
}
params := []pegomock.Param{_param0}
result := pegomock.GetGenericMockFrom(mock).Invoke("PerNodeMetrics", params, []reflect.Type{reflect.TypeOf((*map[string]k8s.Metric)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 map[string]k8s.Metric
var ret1 error
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(map[string]k8s.Metric)
}
if result[1] != nil {
ret1 = result[1].(error)
}
}
return ret0, ret1
}
func (mock *MockMetricsIfc) PodMetrics() (map[string]k8s.Metric, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockMetricsIfc().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("PodMetrics", params, []reflect.Type{reflect.TypeOf((*map[string]k8s.Metric)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 map[string]k8s.Metric
var ret1 error
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(map[string]k8s.Metric)
}
if result[1] != nil {
ret1 = result[1].(error)
}
}
return ret0, ret1
}
func (mock *MockMetricsIfc) VerifyWasCalledOnce() *VerifierMetricsIfc {
return &VerifierMetricsIfc{
mock: mock,
invocationCountMatcher: pegomock.Times(1),
}
}
func (mock *MockMetricsIfc) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMetricsIfc {
return &VerifierMetricsIfc{
mock: mock,
invocationCountMatcher: invocationCountMatcher,
}
}
func (mock *MockMetricsIfc) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMetricsIfc {
return &VerifierMetricsIfc{
mock: mock,
invocationCountMatcher: invocationCountMatcher,
inOrderContext: inOrderContext,
}
}
func (mock *MockMetricsIfc) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMetricsIfc {
return &VerifierMetricsIfc{
mock: mock,
invocationCountMatcher: invocationCountMatcher,
timeout: timeout,
}
}
type VerifierMetricsIfc struct {
mock *MockMetricsIfc
invocationCountMatcher pegomock.Matcher
inOrderContext *pegomock.InOrderContext
timeout time.Duration
}
func (verifier *VerifierMetricsIfc) NodeMetrics() *MetricsIfc_NodeMetrics_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "NodeMetrics", params, verifier.timeout)
return &MetricsIfc_NodeMetrics_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type MetricsIfc_NodeMetrics_OngoingVerification struct {
mock *MockMetricsIfc
methodInvocations []pegomock.MethodInvocation
}
func (c *MetricsIfc_NodeMetrics_OngoingVerification) GetCapturedArguments() {
}
func (c *MetricsIfc_NodeMetrics_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierMetricsIfc) PerNodeMetrics(_param0 []v1.Node) *MetricsIfc_PerNodeMetrics_OngoingVerification {
params := []pegomock.Param{_param0}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "PerNodeMetrics", params, verifier.timeout)
return &MetricsIfc_PerNodeMetrics_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type MetricsIfc_PerNodeMetrics_OngoingVerification struct {
mock *MockMetricsIfc
methodInvocations []pegomock.MethodInvocation
}
func (c *MetricsIfc_PerNodeMetrics_OngoingVerification) GetCapturedArguments() []v1.Node {
_param0 := c.GetAllCapturedArguments()
return _param0[len(_param0)-1]
}
func (c *MetricsIfc_PerNodeMetrics_OngoingVerification) GetAllCapturedArguments() (_param0 [][]v1.Node) {
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(params) > 0 {
_param0 = make([][]v1.Node, len(params[0]))
for u, param := range params[0] {
_param0[u] = param.([]v1.Node)
}
}
return
}
func (verifier *VerifierMetricsIfc) PodMetrics() *MetricsIfc_PodMetrics_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "PodMetrics", params, verifier.timeout)
return &MetricsIfc_PodMetrics_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type MetricsIfc_PodMetrics_OngoingVerification struct {
mock *MockMetricsIfc
methodInvocations []pegomock.MethodInvocation
}
func (c *MetricsIfc_PodMetrics_OngoingVerification) GetCapturedArguments() {
}
func (c *MetricsIfc_PodMetrics_OngoingVerification) GetAllCapturedArguments() {
}

View File

@ -0,0 +1,300 @@
// Code generated by pegomock. DO NOT EDIT.
// Source: github.com/derailed/k9s/internal/resource (interfaces: MetricsServer)
package resource_test
import (
k8s "github.com/derailed/k9s/internal/k8s"
pegomock "github.com/petergtz/pegomock"
v1 "k8s.io/api/core/v1"
v1beta1 "k8s.io/metrics/pkg/apis/metrics/v1beta1"
"reflect"
"time"
)
type MockMetricsServer struct {
fail func(message string, callerSkip ...int)
}
func NewMockMetricsServer() *MockMetricsServer {
return &MockMetricsServer{fail: pegomock.GlobalFailHandler}
}
func (mock *MockMetricsServer) ClusterLoad(_param0 []v1.Node, _param1 []v1beta1.NodeMetrics) k8s.ClusterMetrics {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockMetricsServer().")
}
params := []pegomock.Param{_param0, _param1}
result := pegomock.GetGenericMockFrom(mock).Invoke("ClusterLoad", params, []reflect.Type{reflect.TypeOf((*k8s.ClusterMetrics)(nil)).Elem()})
var ret0 k8s.ClusterMetrics
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(k8s.ClusterMetrics)
}
}
return ret0
}
func (mock *MockMetricsServer) FetchNodesMetrics() ([]v1beta1.NodeMetrics, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockMetricsServer().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("FetchNodesMetrics", params, []reflect.Type{reflect.TypeOf((*[]v1beta1.NodeMetrics)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 []v1beta1.NodeMetrics
var ret1 error
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].([]v1beta1.NodeMetrics)
}
if result[1] != nil {
ret1 = result[1].(error)
}
}
return ret0, ret1
}
func (mock *MockMetricsServer) FetchPodsMetrics(_param0 string) ([]v1beta1.PodMetrics, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockMetricsServer().")
}
params := []pegomock.Param{_param0}
result := pegomock.GetGenericMockFrom(mock).Invoke("FetchPodsMetrics", params, []reflect.Type{reflect.TypeOf((*[]v1beta1.PodMetrics)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 []v1beta1.PodMetrics
var ret1 error
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].([]v1beta1.PodMetrics)
}
if result[1] != nil {
ret1 = result[1].(error)
}
}
return ret0, ret1
}
func (mock *MockMetricsServer) HasMetrics() bool {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockMetricsServer().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("HasMetrics", params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem()})
var ret0 bool
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(bool)
}
}
return ret0
}
func (mock *MockMetricsServer) NodesMetrics(_param0 []v1.Node, _param1 []v1beta1.NodeMetrics, _param2 k8s.NodesMetrics) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockMetricsServer().")
}
params := []pegomock.Param{_param0, _param1, _param2}
pegomock.GetGenericMockFrom(mock).Invoke("NodesMetrics", params, []reflect.Type{})
}
func (mock *MockMetricsServer) PodsMetrics(_param0 []v1beta1.PodMetrics, _param1 k8s.PodsMetrics) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockMetricsServer().")
}
params := []pegomock.Param{_param0, _param1}
pegomock.GetGenericMockFrom(mock).Invoke("PodsMetrics", params, []reflect.Type{})
}
func (mock *MockMetricsServer) VerifyWasCalledOnce() *VerifierMetricsServer {
return &VerifierMetricsServer{
mock: mock,
invocationCountMatcher: pegomock.Times(1),
}
}
func (mock *MockMetricsServer) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMetricsServer {
return &VerifierMetricsServer{
mock: mock,
invocationCountMatcher: invocationCountMatcher,
}
}
func (mock *MockMetricsServer) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMetricsServer {
return &VerifierMetricsServer{
mock: mock,
invocationCountMatcher: invocationCountMatcher,
inOrderContext: inOrderContext,
}
}
func (mock *MockMetricsServer) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMetricsServer {
return &VerifierMetricsServer{
mock: mock,
invocationCountMatcher: invocationCountMatcher,
timeout: timeout,
}
}
type VerifierMetricsServer struct {
mock *MockMetricsServer
invocationCountMatcher pegomock.Matcher
inOrderContext *pegomock.InOrderContext
timeout time.Duration
}
func (verifier *VerifierMetricsServer) ClusterLoad(_param0 []v1.Node, _param1 []v1beta1.NodeMetrics) *MetricsServer_ClusterLoad_OngoingVerification {
params := []pegomock.Param{_param0, _param1}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "ClusterLoad", params, verifier.timeout)
return &MetricsServer_ClusterLoad_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type MetricsServer_ClusterLoad_OngoingVerification struct {
mock *MockMetricsServer
methodInvocations []pegomock.MethodInvocation
}
func (c *MetricsServer_ClusterLoad_OngoingVerification) GetCapturedArguments() ([]v1.Node, []v1beta1.NodeMetrics) {
_param0, _param1 := c.GetAllCapturedArguments()
return _param0[len(_param0)-1], _param1[len(_param1)-1]
}
func (c *MetricsServer_ClusterLoad_OngoingVerification) GetAllCapturedArguments() (_param0 [][]v1.Node, _param1 [][]v1beta1.NodeMetrics) {
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(params) > 0 {
_param0 = make([][]v1.Node, len(params[0]))
for u, param := range params[0] {
_param0[u] = param.([]v1.Node)
}
_param1 = make([][]v1beta1.NodeMetrics, len(params[1]))
for u, param := range params[1] {
_param1[u] = param.([]v1beta1.NodeMetrics)
}
}
return
}
func (verifier *VerifierMetricsServer) FetchNodesMetrics() *MetricsServer_FetchNodesMetrics_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "FetchNodesMetrics", params, verifier.timeout)
return &MetricsServer_FetchNodesMetrics_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type MetricsServer_FetchNodesMetrics_OngoingVerification struct {
mock *MockMetricsServer
methodInvocations []pegomock.MethodInvocation
}
func (c *MetricsServer_FetchNodesMetrics_OngoingVerification) GetCapturedArguments() {
}
func (c *MetricsServer_FetchNodesMetrics_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierMetricsServer) FetchPodsMetrics(_param0 string) *MetricsServer_FetchPodsMetrics_OngoingVerification {
params := []pegomock.Param{_param0}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "FetchPodsMetrics", params, verifier.timeout)
return &MetricsServer_FetchPodsMetrics_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type MetricsServer_FetchPodsMetrics_OngoingVerification struct {
mock *MockMetricsServer
methodInvocations []pegomock.MethodInvocation
}
func (c *MetricsServer_FetchPodsMetrics_OngoingVerification) GetCapturedArguments() string {
_param0 := c.GetAllCapturedArguments()
return _param0[len(_param0)-1]
}
func (c *MetricsServer_FetchPodsMetrics_OngoingVerification) GetAllCapturedArguments() (_param0 []string) {
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(params) > 0 {
_param0 = make([]string, len(params[0]))
for u, param := range params[0] {
_param0[u] = param.(string)
}
}
return
}
func (verifier *VerifierMetricsServer) HasMetrics() *MetricsServer_HasMetrics_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "HasMetrics", params, verifier.timeout)
return &MetricsServer_HasMetrics_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type MetricsServer_HasMetrics_OngoingVerification struct {
mock *MockMetricsServer
methodInvocations []pegomock.MethodInvocation
}
func (c *MetricsServer_HasMetrics_OngoingVerification) GetCapturedArguments() {
}
func (c *MetricsServer_HasMetrics_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierMetricsServer) NodesMetrics(_param0 []v1.Node, _param1 []v1beta1.NodeMetrics, _param2 k8s.NodesMetrics) *MetricsServer_NodesMetrics_OngoingVerification {
params := []pegomock.Param{_param0, _param1, _param2}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "NodesMetrics", params, verifier.timeout)
return &MetricsServer_NodesMetrics_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type MetricsServer_NodesMetrics_OngoingVerification struct {
mock *MockMetricsServer
methodInvocations []pegomock.MethodInvocation
}
func (c *MetricsServer_NodesMetrics_OngoingVerification) GetCapturedArguments() ([]v1.Node, []v1beta1.NodeMetrics, k8s.NodesMetrics) {
_param0, _param1, _param2 := c.GetAllCapturedArguments()
return _param0[len(_param0)-1], _param1[len(_param1)-1], _param2[len(_param2)-1]
}
func (c *MetricsServer_NodesMetrics_OngoingVerification) GetAllCapturedArguments() (_param0 [][]v1.Node, _param1 [][]v1beta1.NodeMetrics, _param2 []k8s.NodesMetrics) {
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(params) > 0 {
_param0 = make([][]v1.Node, len(params[0]))
for u, param := range params[0] {
_param0[u] = param.([]v1.Node)
}
_param1 = make([][]v1beta1.NodeMetrics, len(params[1]))
for u, param := range params[1] {
_param1[u] = param.([]v1beta1.NodeMetrics)
}
_param2 = make([]k8s.NodesMetrics, len(params[2]))
for u, param := range params[2] {
_param2[u] = param.(k8s.NodesMetrics)
}
}
return
}
func (verifier *VerifierMetricsServer) PodsMetrics(_param0 []v1beta1.PodMetrics, _param1 k8s.PodsMetrics) *MetricsServer_PodsMetrics_OngoingVerification {
params := []pegomock.Param{_param0, _param1}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "PodsMetrics", params, verifier.timeout)
return &MetricsServer_PodsMetrics_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type MetricsServer_PodsMetrics_OngoingVerification struct {
mock *MockMetricsServer
methodInvocations []pegomock.MethodInvocation
}
func (c *MetricsServer_PodsMetrics_OngoingVerification) GetCapturedArguments() ([]v1beta1.PodMetrics, k8s.PodsMetrics) {
_param0, _param1 := c.GetAllCapturedArguments()
return _param0[len(_param0)-1], _param1[len(_param1)-1]
}
func (c *MetricsServer_PodsMetrics_OngoingVerification) GetAllCapturedArguments() (_param0 [][]v1beta1.PodMetrics, _param1 []k8s.PodsMetrics) {
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(params) > 0 {
_param0 = make([][]v1beta1.PodMetrics, len(params[0]))
for u, param := range params[0] {
_param0[u] = param.([]v1beta1.PodMetrics)
}
_param1 = make([]k8s.PodsMetrics, len(params[1]))
for u, param := range params[1] {
_param1[u] = param.(k8s.PodsMetrics)
}
}
return
}

View File

@ -0,0 +1,170 @@
// Code generated by pegomock. DO NOT EDIT.
// Source: github.com/derailed/k9s/internal/resource (interfaces: MetricsService)
package resource_test
import (
pegomock "github.com/petergtz/pegomock"
v1beta1 "k8s.io/metrics/pkg/apis/metrics/v1beta1"
"reflect"
"time"
)
type MockMetricsService struct {
fail func(message string, callerSkip ...int)
}
func NewMockMetricsService() *MockMetricsService {
return &MockMetricsService{fail: pegomock.GlobalFailHandler}
}
func (mock *MockMetricsService) FetchNodesMetrics() ([]v1beta1.NodeMetrics, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockMetricsService().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("FetchNodesMetrics", params, []reflect.Type{reflect.TypeOf((*[]v1beta1.NodeMetrics)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 []v1beta1.NodeMetrics
var ret1 error
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].([]v1beta1.NodeMetrics)
}
if result[1] != nil {
ret1 = result[1].(error)
}
}
return ret0, ret1
}
func (mock *MockMetricsService) FetchPodsMetrics(_param0 string) ([]v1beta1.PodMetrics, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockMetricsService().")
}
params := []pegomock.Param{_param0}
result := pegomock.GetGenericMockFrom(mock).Invoke("FetchPodsMetrics", params, []reflect.Type{reflect.TypeOf((*[]v1beta1.PodMetrics)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 []v1beta1.PodMetrics
var ret1 error
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].([]v1beta1.PodMetrics)
}
if result[1] != nil {
ret1 = result[1].(error)
}
}
return ret0, ret1
}
func (mock *MockMetricsService) HasMetrics() bool {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockMetricsService().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("HasMetrics", params, []reflect.Type{reflect.TypeOf((*bool)(nil)).Elem()})
var ret0 bool
if len(result) != 0 {
if result[0] != nil {
ret0 = result[0].(bool)
}
}
return ret0
}
func (mock *MockMetricsService) VerifyWasCalledOnce() *VerifierMetricsService {
return &VerifierMetricsService{
mock: mock,
invocationCountMatcher: pegomock.Times(1),
}
}
func (mock *MockMetricsService) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierMetricsService {
return &VerifierMetricsService{
mock: mock,
invocationCountMatcher: invocationCountMatcher,
}
}
func (mock *MockMetricsService) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierMetricsService {
return &VerifierMetricsService{
mock: mock,
invocationCountMatcher: invocationCountMatcher,
inOrderContext: inOrderContext,
}
}
func (mock *MockMetricsService) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierMetricsService {
return &VerifierMetricsService{
mock: mock,
invocationCountMatcher: invocationCountMatcher,
timeout: timeout,
}
}
type VerifierMetricsService struct {
mock *MockMetricsService
invocationCountMatcher pegomock.Matcher
inOrderContext *pegomock.InOrderContext
timeout time.Duration
}
func (verifier *VerifierMetricsService) FetchNodesMetrics() *MetricsService_FetchNodesMetrics_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "FetchNodesMetrics", params, verifier.timeout)
return &MetricsService_FetchNodesMetrics_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type MetricsService_FetchNodesMetrics_OngoingVerification struct {
mock *MockMetricsService
methodInvocations []pegomock.MethodInvocation
}
func (c *MetricsService_FetchNodesMetrics_OngoingVerification) GetCapturedArguments() {
}
func (c *MetricsService_FetchNodesMetrics_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierMetricsService) FetchPodsMetrics(_param0 string) *MetricsService_FetchPodsMetrics_OngoingVerification {
params := []pegomock.Param{_param0}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "FetchPodsMetrics", params, verifier.timeout)
return &MetricsService_FetchPodsMetrics_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type MetricsService_FetchPodsMetrics_OngoingVerification struct {
mock *MockMetricsService
methodInvocations []pegomock.MethodInvocation
}
func (c *MetricsService_FetchPodsMetrics_OngoingVerification) GetCapturedArguments() string {
_param0 := c.GetAllCapturedArguments()
return _param0[len(_param0)-1]
}
func (c *MetricsService_FetchPodsMetrics_OngoingVerification) GetAllCapturedArguments() (_param0 []string) {
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(params) > 0 {
_param0 = make([]string, len(params[0]))
for u, param := range params[0] {
_param0[u] = param.(string)
}
}
return
}
func (verifier *VerifierMetricsService) HasMetrics() *MetricsService_HasMetrics_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "HasMetrics", params, verifier.timeout)
return &MetricsService_HasMetrics_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type MetricsService_HasMetrics_OngoingVerification struct {
mock *MockMetricsService
methodInvocations []pegomock.MethodInvocation
}
func (c *MetricsService_HasMetrics_OngoingVerification) GetCapturedArguments() {
}
func (c *MetricsService_HasMetrics_OngoingVerification) GetAllCapturedArguments() {
}

View File

@ -18,86 +18,77 @@ const (
// Node tracks a kubernetes resource. // Node tracks a kubernetes resource.
type Node struct { type Node struct {
*Base *Base
instance *v1.Node instance *v1.Node
metricSvc MetricsIfc metricsServer MetricsServer
metrics k8s.Metric metrics k8s.NodeMetrics
} }
// NewNodeList returns a new resource list. // NewNodeList returns a new resource list.
func NewNodeList(ns string) List { func NewNodeList(c k8s.Connection, ns string) List {
return NewNodeListWithArgs(ns, NewNode()) return newList(
NotNamespaced,
"no",
NewNode(c),
ViewAccess|DescribeAccess,
)
} }
// NewNodeListWithArgs returns a new resource list. // NewNode instantiates a new Node.
func NewNodeListWithArgs(ns string, res Resource) List { func NewNode(c k8s.Connection) *Node {
return newList(NotNamespaced, "no", res, ViewAccess|DescribeAccess) n := &Node{&Base{connection: c, resource: k8s.NewNode(c)}, nil, k8s.NewMetricsServer(c), k8s.NodeMetrics{}}
n.Factory = n
return n
} }
// NewNode instantiates a new Endpoint. // New builds a new Node instance from a k8s resource.
func NewNode() *Node { func (r *Node) New(i interface{}) Columnar {
return NewNodeWithArgs(k8s.NewNode(), k8s.NewMetricsServer()) c := NewNode(r.connection)
} switch instance := i.(type) {
// NewNodeWithArgs instantiates a new Endpoint.
func NewNodeWithArgs(r k8s.Res, mx MetricsIfc) *Node {
ep := &Node{
metricSvc: mx,
Base: &Base{
caller: r,
},
}
ep.creator = ep
return ep
}
// NewInstance builds a new Endpoint instance from a k8s resource.
func (*Node) NewInstance(i interface{}) Columnar {
cm := NewNode()
switch i.(type) {
case *v1.Node: case *v1.Node:
cm.instance = i.(*v1.Node) c.instance = instance
case v1.Node: case v1.Node:
ii := i.(v1.Node) c.instance = &instance
cm.instance = &ii
default: default:
log.Fatal().Msgf("Unknown %#v", i) log.Fatal().Msgf("unknown Node type %#v", i)
} }
cm.path = cm.namespacedName(cm.instance.ObjectMeta) c.path = c.namespacedName(c.instance.ObjectMeta)
return cm
return c
} }
// List all resources for a given namespace. // List all resources for a given namespace.
func (r *Node) List(ns string) (Columnars, error) { func (r *Node) List(ns string) (Columnars, error) {
ii, err := r.caller.List(AllNamespaces) nn, err := r.resource.List(ns)
if err != nil { if err != nil {
return nil, err return nil, err
} }
nn := make([]v1.Node, len(ii)) nodes := make([]v1.Node, 0, len(nn))
for k, i := range ii { for _, n := range nn {
nn[k] = i.(v1.Node) nodes = append(nodes, n.(v1.Node))
} }
cc := make(Columnars, 0, len(nn)) mx := make(k8s.NodesMetrics, len(nodes))
mx, err := r.metricSvc.PerNodeMetrics(nn) if r.metricsServer.HasMetrics() {
if err != nil { nmx, _ := r.metricsServer.FetchNodesMetrics()
log.Warn().Msgf("No metrics: %#v", err) r.metricsServer.NodesMetrics(nodes, nmx, mx)
} }
for i := 0; i < len(nn); i++ { cc := make(Columnars, 0, len(nodes))
n := r.NewInstance(&nn[i]).(*Node) for i := range nodes {
if err == nil { no := r.New(&nodes[i]).(*Node)
n.metrics = mx[nn[i].Name] no.metrics = mx[nodes[i].Name]
} cc = append(cc, no)
cc = append(cc, n)
} }
return cc, nil return cc, nil
} }
// Marshal a resource to yaml. // Marshal a resource to yaml.
func (r *Node) Marshal(path string) (string, error) { func (r *Node) Marshal(path string) (string, error) {
ns, n := namespaced(path) ns, n := namespaced(path)
i, err := r.caller.Get(ns, n) i, err := r.resource.Get(ns, n)
if err != nil { if err != nil {
log.Error().Err(err) log.Error().Err(err)
return "", err return "", err
@ -106,6 +97,7 @@ func (r *Node) Marshal(path string) (string, error) {
no := i.(*v1.Node) no := i.(*v1.Node)
no.TypeMeta.APIVersion = "v1" no.TypeMeta.APIVersion = "v1"
no.TypeMeta.Kind = "Node" no.TypeMeta.Kind = "Node"
return r.marshalObject(no) return r.marshalObject(no)
} }
@ -116,12 +108,15 @@ func (*Node) Header(ns string) Row {
"STATUS", "STATUS",
"ROLES", "ROLES",
"VERSION", "VERSION",
"KERNEL",
"INTERNAL-IP", "INTERNAL-IP",
"EXTERNAL-IP", "EXTERNAL-IP",
"CPU", "CPU",
"MEM", "MEM",
"AVAILABLE_CPU", "AVA CPU",
"AVAILABLE_MEM", "AVA MEM",
"CAP CPU",
"CAP MEM",
"AGE", "AGE",
} }
} }
@ -131,33 +126,28 @@ func (r *Node) Fields(ns string) Row {
ff := make(Row, 0, len(r.Header(ns))) ff := make(Row, 0, len(r.Header(ns)))
i := r.instance i := r.instance
status := r.status(i)
iIP, eIP := r.getIPs(i.Status.Addresses) iIP, eIP := r.getIPs(i.Status.Addresses)
iIP, eIP = missing(iIP), missing(eIP) iIP, eIP = missing(iIP), missing(eIP)
roles := missing(strings.Join(findNodeRoles(i), ","))
cpu, mem, acpu, amem := na(r.metrics.CPU), na(r.metrics.Mem), na(r.metrics.AvailCPU), na(r.metrics.AvailMem)
return append(ff, return append(ff,
i.Name, i.Name,
status, r.status(i),
roles, missing(strings.Join(findNodeRoles(i), ",")),
i.Status.NodeInfo.KubeletVersion,
i.Status.NodeInfo.KernelVersion, i.Status.NodeInfo.KernelVersion,
iIP, iIP,
eIP, eIP,
cpu, ToMillicore(r.metrics.CurrentCPU),
mem, ToMi(r.metrics.CurrentMEM),
acpu, ToMillicore(r.metrics.AvailCPU),
amem, ToMi(r.metrics.AvailMEM),
ToMillicore(r.metrics.TotalCPU),
ToMi(r.metrics.TotalMEM),
toAge(i.ObjectMeta.CreationTimestamp), toAge(i.ObjectMeta.CreationTimestamp),
) )
} }
// ExtFields returns extended fields in relation to headers. // ----------------------------------------------------------------------------
func (*Node) ExtFields() Properties {
return Properties{}
}
// Helpers... // Helpers...
func (*Node) getIPs(addrs []v1.NodeAddress) (iIP, eIP string) { func (*Node) getIPs(addrs []v1.NodeAddress) (iIP, eIP string) {
@ -169,6 +159,7 @@ func (*Node) getIPs(addrs []v1.NodeAddress) (iIP, eIP string) {
iIP = a.Address iIP = a.Address
} }
} }
return return
} }
@ -195,6 +186,7 @@ func (r *Node) status(i *v1.Node) string {
if i.Spec.Unschedulable { if i.Spec.Unschedulable {
status = append(status, "SchedulingDisabled") status = append(status, "SchedulingDisabled")
} }
return strings.Join(status, ",") return strings.Join(status, ",")
} }
@ -210,5 +202,6 @@ func findNodeRoles(i *v1.Node) []string {
roles.Insert(v) roles.Insert(v)
} }
} }
return roles.List() return roles.List()
} }

View File

@ -8,7 +8,10 @@ import (
m "github.com/petergtz/pegomock" m "github.com/petergtz/pegomock"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
res "k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
mv1beta1 "k8s.io/metrics/pkg/apis/metrics/v1beta1"
v1beta1 "k8s.io/metrics/pkg/apis/metrics/v1beta1"
) )
func TestNodeListAccess(t *testing.T) { func TestNodeListAccess(t *testing.T) {
@ -31,9 +34,9 @@ func TestNodeFields(t *testing.T) {
func TestNodeMarshal(t *testing.T) { func TestNodeMarshal(t *testing.T) {
setup(t) setup(t)
mx := NewMockMetricsIfc() mx := NewMockMetricsServer()
m.When(mx.PerNodeMetrics([]v1.Node{*k8sNode()})). // m.When(mx.NodesMetrics([]v1.Node{*k8sNode()})).
ThenReturn(map[string]k8s.Metric{"fred": {}}, nil) // ThenReturn(map[string]k8s.RawMetric{"fred": {}}, nil)
ca := NewMockCaller() ca := NewMockCaller()
m.When(ca.Get("blee", "fred")).ThenReturn(k8sNode(), nil) m.When(ca.Get("blee", "fred")).ThenReturn(k8sNode(), nil)
@ -47,48 +50,34 @@ func TestNodeMarshal(t *testing.T) {
func TestNodeListData(t *testing.T) { func TestNodeListData(t *testing.T) {
setup(t) setup(t)
mx := NewMockMetricsIfc() mockServer := NewMockMetricsServer()
m.When(mx.PerNodeMetrics([]v1.Node{*k8sNode()})). m.When(mockServer.HasMetrics()).ThenReturn(true)
ThenReturn(map[string]k8s.Metric{"fred": {}}, nil) m.When(mockServer.FetchNodesMetrics()).
ca := NewMockCaller() ThenReturn([]mv1beta1.NodeMetrics{makeMxNode("fred", "100m", "100Mi")}, nil)
m.When(ca.List("")).ThenReturn(k8s.Collection{*k8sNode()}, nil)
l := resource.NewNodeListWithArgs("", resource.NewNodeWithArgs(ca, mx)) ca := NewMockCaller()
m.When(ca.List("-")).ThenReturn(k8s.Collection{*k8sNode()}, nil)
l := resource.NewNodeListWithArgs("", resource.NewNodeWithArgs(ca, mockServer))
// Make sure we can get deltas! // Make sure we can get deltas!
for i := 0; i < 2; i++ { for i := 0; i < 2; i++ {
err := l.Reconcile() err := l.Reconcile()
assert.Nil(t, err) assert.Nil(t, err)
} }
ca.VerifyWasCalled(m.Times(2)).List("") ca.VerifyWasCalled(m.Times(2)).List("-")
td := l.Data() td := l.Data()
assert.Equal(t, 1, len(td.Rows)) assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.NotNamespaced, l.GetNamespace()) assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
assert.False(t, l.HasXRay()) row, ok := td.Rows["fred"]
row := td.Rows["fred"] assert.True(t, ok)
assert.Equal(t, 11, len(row.Deltas)) assert.Equal(t, 12, len(row.Deltas))
for _, d := range row.Deltas { for _, d := range row.Deltas {
assert.Equal(t, "", d) assert.Equal(t, "", d)
} }
assert.Equal(t, resource.Row{"fred"}, row.Fields[:1]) assert.Equal(t, resource.Row{"fred"}, row.Fields[:1])
} }
func TestNodeListDescribe(t *testing.T) {
setup(t)
mx := NewMockMetricsIfc()
m.When(mx.PerNodeMetrics([]v1.Node{*k8sNode()})).
ThenReturn(map[string]k8s.Metric{"fred": {}}, nil)
ca := NewMockCaller()
m.When(ca.Get("blee", "fred")).ThenReturn(k8sNode(), nil)
l := resource.NewNodeListWithArgs("blee", resource.NewNodeWithArgs(ca, mx))
props, err := l.Describe("blee/fred")
ca.VerifyWasCalledOnce().Get("blee", "fred")
assert.Nil(t, err)
assert.Equal(t, 0, len(props))
}
// Helpers... // Helpers...
func k8sNode() *v1.Node { func k8sNode() *v1.Node {
@ -106,6 +95,25 @@ func k8sNode() *v1.Node {
} }
} }
func makeMxNode(name, cpu, mem string) mv1beta1.NodeMetrics {
return v1beta1.NodeMetrics{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
Usage: makeRes(cpu, mem),
}
}
func makeRes(c, m string) v1.ResourceList {
cpu, _ := res.ParseQuantity(c)
mem, _ := res.ParseQuantity(m)
return v1.ResourceList{
v1.ResourceCPU: cpu,
v1.ResourceMemory: mem,
}
}
func newNode() resource.Columnar { func newNode() resource.Columnar {
return resource.NewNode().NewInstance(k8sNode()) return resource.NewNode().NewInstance(k8sNode())
} }

View File

@ -13,51 +13,43 @@ type Namespace struct {
} }
// NewNamespaceList returns a new resource list. // NewNamespaceList returns a new resource list.
func NewNamespaceList(ns string) List { func NewNamespaceList(c k8s.Connection, ns string) List {
return NewNamespaceListWithArgs(ns, NewNamespace()) return newList(
NotNamespaced,
"ns",
NewNamespace(c),
CRUDAccess|DescribeAccess,
)
} }
// NewNamespaceListWithArgs returns a new resource list. // NewNamespace instantiates a new Namespace.
func NewNamespaceListWithArgs(ns string, res Resource) List { func NewNamespace(c k8s.Connection) *Namespace {
return newList(NotNamespaced, "ns", res, CRUDAccess|DescribeAccess) n := &Namespace{&Base{connection: c, resource: k8s.NewNamespace(c)}, nil}
n.Factory = n
return n
} }
// NewNamespace instantiates a new Endpoint. // New builds a new Namespace instance from a k8s resource.
func NewNamespace() *Namespace { func (r *Namespace) New(i interface{}) Columnar {
return NewNamespaceWithArgs(k8s.NewNamespace()) c := NewNamespace(r.connection)
} switch instance := i.(type) {
// NewNamespaceWithArgs instantiates a new Endpoint.
func NewNamespaceWithArgs(r k8s.Res) *Namespace {
ep := &Namespace{
Base: &Base{
caller: r,
},
}
ep.creator = ep
return ep
}
// NewInstance builds a new Endpoint instance from a k8s resource.
func (*Namespace) NewInstance(i interface{}) Columnar {
cm := NewNamespace()
switch i.(type) {
case *v1.Namespace: case *v1.Namespace:
cm.instance = i.(*v1.Namespace) c.instance = instance
case v1.Namespace: case v1.Namespace:
ii := i.(v1.Namespace) c.instance = &instance
cm.instance = &ii
default: default:
log.Fatal().Msgf("Unknown %#v", i) log.Fatal().Msgf("unknown Namespace type %#v", i)
} }
cm.path = cm.namespacedName(cm.instance.ObjectMeta) c.path = c.namespacedName(c.instance.ObjectMeta)
return cm
return c
} }
// Marshal a resource to yaml. // Marshal a resource to yaml.
func (r *Namespace) Marshal(path string) (string, error) { func (r *Namespace) Marshal(path string) (string, error) {
ns, n := namespaced(path) ns, n := namespaced(path)
i, err := r.caller.Get(ns, n) i, err := r.resource.Get(ns, n)
if err != nil { if err != nil {
log.Error().Err(err) log.Error().Err(err)
return "", err return "", err
@ -66,6 +58,7 @@ func (r *Namespace) Marshal(path string) (string, error) {
nss := i.(*v1.Namespace) nss := i.(*v1.Namespace)
nss.TypeMeta.APIVersion = "v1" nss.TypeMeta.APIVersion = "v1"
nss.TypeMeta.Kind = "Namespace" nss.TypeMeta.Kind = "Namespace"
return r.marshalObject(nss) return r.marshalObject(nss)
} }
@ -78,14 +71,10 @@ func (*Namespace) Header(ns string) Row {
func (r *Namespace) Fields(ns string) Row { func (r *Namespace) Fields(ns string) Row {
ff := make(Row, 0, len(r.Header(ns))) ff := make(Row, 0, len(r.Header(ns)))
i := r.instance i := r.instance
return append(ff, return append(ff,
i.Name, i.Name,
string(i.Status.Phase), string(i.Status.Phase),
toAge(i.ObjectMeta.CreationTimestamp), toAge(i.ObjectMeta.CreationTimestamp),
) )
} }
// ExtFields returns extended fields in relation to headers.
func (*Namespace) ExtFields() Properties {
return Properties{}
}

View File

@ -62,7 +62,6 @@ func TestNamespaceListData(t *testing.T) {
td := l.Data() td := l.Data()
assert.Equal(t, 1, len(td.Rows)) assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.NotNamespaced, l.GetNamespace()) assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"] row := td.Rows["blee/fred"]
assert.Equal(t, 3, len(row.Deltas)) assert.Equal(t, 3, len(row.Deltas))
for _, d := range row.Deltas { for _, d := range row.Deltas {
@ -71,19 +70,6 @@ func TestNamespaceListData(t *testing.T) {
assert.Equal(t, resource.Row{"fred"}, row.Fields[:1]) assert.Equal(t, resource.Row{"fred"}, row.Fields[:1])
} }
func TestNamespaceListDescribe(t *testing.T) {
setup(t)
ca := NewMockCaller()
m.When(ca.Get("blee", "fred")).ThenReturn(k8sNamespace(), nil)
l := resource.NewNamespaceListWithArgs("blee", resource.NewNamespaceWithArgs(ca))
props, err := l.Describe("blee/fred")
ca.VerifyWasCalledOnce().Get("blee", "fred")
assert.Nil(t, err)
assert.Equal(t, 0, len(props))
}
// Helpers... // Helpers...
func k8sNamespace() *v1.Namespace { func k8sNamespace() *v1.Namespace {

View File

@ -11,59 +11,52 @@ import (
// PodDisruptionBudget that can be displayed in a table and interacted with. // PodDisruptionBudget that can be displayed in a table and interacted with.
type PodDisruptionBudget struct { type PodDisruptionBudget struct {
*Base *Base
instance *v1beta1.PodDisruptionBudget instance *v1beta1.PodDisruptionBudget
} }
// NewPDBList returns a new resource list. // NewPDBList returns a new resource list.
func NewPDBList(ns string) List { func NewPDBList(c k8s.Connection, ns string) List {
return NewPDBListWithArgs(ns, NewPDB()) return newList(
ns,
"pdb",
NewPDB(c),
AllVerbsAccess|DescribeAccess,
)
} }
// NewPDBListWithArgs returns a new resource list. // NewPDB instantiates a new PDB.
func NewPDBListWithArgs(ns string, res Resource) List { func NewPDB(c k8s.Connection) *PodDisruptionBudget {
return newList(ns, "pdb", res, AllVerbsAccess|DescribeAccess) p := &PodDisruptionBudget{&Base{connection: c, resource: k8s.NewPodDisruptionBudget(c)}, nil}
} p.Factory = p
// NewPDB returns a new PodDisruptionBudget instance.
func NewPDB() *PodDisruptionBudget {
return NewPDBWithArgs(k8s.NewPodDisruptionBudget())
}
// NewPDBWithArgs returns a new Pod instance.
func NewPDBWithArgs(r k8s.Res) *PodDisruptionBudget {
p := &PodDisruptionBudget{
Base: &Base{
caller: r,
},
}
p.creator = p
return p return p
} }
// NewInstance builds a new PodDisruptionBudget instance from a k8s resource. // New builds a new PDB instance from a k8s resource.
func (r *PodDisruptionBudget) NewInstance(i interface{}) Columnar { func (r *PodDisruptionBudget) New(i interface{}) Columnar {
pdb := NewPDB() c := NewPDB(r.connection)
switch i.(type) { switch instance := i.(type) {
case *v1beta1.PodDisruptionBudget: case *v1beta1.PodDisruptionBudget:
pdb.instance = i.(*v1beta1.PodDisruptionBudget) c.instance = instance
case v1beta1.PodDisruptionBudget: case v1beta1.PodDisruptionBudget:
ii := i.(v1beta1.PodDisruptionBudget) c.instance = &instance
pdb.instance = &ii
case *interface{}: case *interface{}:
ptr := *i.(*interface{}) ptr := *i.(*interface{})
pdbi := ptr.(v1beta1.PodDisruptionBudget) pdbi := ptr.(v1beta1.PodDisruptionBudget)
pdb.instance = &pdbi c.instance = &pdbi
default: default:
log.Fatal().Msgf("Unknown %#v", i) log.Fatal().Msgf("unknown PDB type %#v", i)
} }
pdb.path = r.namespacedName(pdb.instance.ObjectMeta) c.path = c.namespacedName(c.instance.ObjectMeta)
return pdb
return c
} }
// Marshal resource to yaml. // Marshal resource to yaml.
func (r *PodDisruptionBudget) Marshal(path string) (string, error) { func (r *PodDisruptionBudget) Marshal(path string) (string, error) {
ns, n := namespaced(path) ns, n := namespaced(path)
i, err := r.caller.Get(ns, n) i, err := r.resource.Get(ns, n)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -71,6 +64,7 @@ func (r *PodDisruptionBudget) Marshal(path string) (string, error) {
pdb := i.(*v1beta1.PodDisruptionBudget) pdb := i.(*v1beta1.PodDisruptionBudget)
pdb.TypeMeta.APIVersion = "v1beta1" pdb.TypeMeta.APIVersion = "v1beta1"
pdb.TypeMeta.Kind = "PodDisruptionBudget" pdb.TypeMeta.Kind = "PodDisruptionBudget"
return r.marshalObject(pdb) return r.marshalObject(pdb)
} }
@ -80,6 +74,7 @@ func (*PodDisruptionBudget) Header(ns string) Row {
if ns == AllNamespaces { if ns == AllNamespaces {
hh = append(hh, "NAMESPACE") hh = append(hh, "NAMESPACE")
} }
return append(hh, return append(hh,
"NAME", "NAME",
"MIN AVAILABLE", "MIN AVAILABLE",
@ -122,8 +117,3 @@ func (r *PodDisruptionBudget) Fields(ns string) Row {
toAge(i.ObjectMeta.CreationTimestamp), toAge(i.ObjectMeta.CreationTimestamp),
) )
} }
// ExtFields returns extra info about the resource.
func (r *PodDisruptionBudget) ExtFields() Properties {
return nil
}

View File

@ -72,7 +72,6 @@ func TestPDBListData(t *testing.T) {
td := l.Data() td := l.Data()
assert.Equal(t, 1, len(td.Rows)) assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.NotNamespaced, l.GetNamespace()) assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"] row := td.Rows["blee/fred"]
assert.Equal(t, 8, len(row.Deltas)) assert.Equal(t, 8, len(row.Deltas))
for _, d := range row.Deltas { for _, d := range row.Deltas {
@ -81,19 +80,6 @@ func TestPDBListData(t *testing.T) {
assert.Equal(t, resource.Row{"fred"}, row.Fields[:1]) assert.Equal(t, resource.Row{"fred"}, row.Fields[:1])
} }
func TestPDBListDescribe(t *testing.T) {
setup(t)
ca := NewMockCaller()
m.When(ca.Get("blee", "fred")).ThenReturn(k8sPDB(), nil)
l := resource.NewPDBListWithArgs("blee", resource.NewPDBWithArgs(ca))
props, err := l.Describe("blee/fred")
ca.VerifyWasCalledOnce().Get("blee", "fred")
assert.Nil(t, err)
assert.Equal(t, 0, len(props))
}
// Helpers... // Helpers...
func k8sPDB() *v1beta1.PodDisruptionBudget { func k8sPDB() *v1beta1.PodDisruptionBudget {

View File

@ -37,75 +37,64 @@ type (
// Pod that can be displayed in a table and interacted with. // Pod that can be displayed in a table and interacted with.
Pod struct { Pod struct {
*Base *Base
instance *v1.Pod instance *v1.Pod
metricSvc MetricsIfc metricServer MetricsServer
metrics k8s.Metric metrics k8s.PodMetrics
} }
) )
// NewPodList returns a new resource list. // NewPodList returns a new resource list.
func NewPodList(ns string) List { func NewPodList(c k8s.Connection, ns string) List {
return NewPodListWithArgs(ns, NewPod()) return newList(
ns,
"po",
NewPod(c),
AllVerbsAccess|DescribeAccess,
)
} }
// NewPodListWithArgs returns a new resource list. // NewPod instantiates a new Pod.
func NewPodListWithArgs(ns string, res Resource) List { func NewPod(c k8s.Connection) *Pod {
l := newList(ns, "po", res, AllVerbsAccess|DescribeAccess) p := &Pod{&Base{connection: c, resource: k8s.NewPod(c)}, nil, k8s.NewMetricsServer(c), k8s.PodMetrics{}}
l.xray = true p.Factory = p
return l
}
// NewPod returns a new Pod instance.
func NewPod() *Pod {
return NewPodWithArgs(k8s.NewPod(), k8s.NewMetricsServer())
}
// NewPodWithArgs returns a new Pod instance.
func NewPodWithArgs(r k8s.Res, mx MetricsIfc) *Pod {
p := &Pod{
metricSvc: mx,
Base: &Base{
caller: r,
},
}
p.creator = p
return p return p
} }
// NewInstance builds a new Pod instance from a k8s resource. // New builds a new Pod instance from a k8s resource.
func (r *Pod) NewInstance(i interface{}) Columnar { func (r *Pod) New(i interface{}) Columnar {
pod := NewPod() c := NewPod(r.connection)
switch i.(type) { switch instance := i.(type) {
case *v1.Pod: case *v1.Pod:
pod.instance = i.(*v1.Pod) c.instance = instance
case v1.Pod: case v1.Pod:
ii := i.(v1.Pod) c.instance = &instance
pod.instance = &ii
case *interface{}: case *interface{}:
ptr := *i.(*interface{}) ptr := *instance
po := ptr.(v1.Pod) po := ptr.(v1.Pod)
pod.instance = &po c.instance = &po
default: default:
log.Fatal().Msgf("Unknown %#v", i) log.Fatal().Msgf("unknown Pod type %#v", i)
} }
pod.path = r.namespacedName(pod.instance.ObjectMeta) c.path = c.namespacedName(c.instance.ObjectMeta)
return pod
return c
} }
// Metrics retrieves cpu/mem resource consumption on a pod. // Metrics retrieves cpu/mem resource consumption on a pod.
func (r *Pod) Metrics() k8s.Metric { func (r *Pod) Metrics() k8s.PodMetrics {
return r.metrics return r.metrics
} }
// SetMetrics set the current k8s resource metrics on a given pod. // SetMetrics set the current k8s resource metrics on a given pod.
func (r *Pod) SetMetrics(m k8s.Metric) { func (r *Pod) SetMetrics(m k8s.PodMetrics) {
r.metrics = m r.metrics = m
} }
// Marshal resource to yaml. // Marshal resource to yaml.
func (r *Pod) Marshal(path string) (string, error) { func (r *Pod) Marshal(path string) (string, error) {
ns, n := namespaced(path) ns, n := namespaced(path)
i, err := r.caller.Get(ns, n) i, err := r.resource.Get(ns, n)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -113,18 +102,20 @@ func (r *Pod) Marshal(path string) (string, error) {
po := i.(*v1.Pod) po := i.(*v1.Pod)
po.TypeMeta.APIVersion = "v1" po.TypeMeta.APIVersion = "v1"
po.TypeMeta.Kind = "Pod" po.TypeMeta.Kind = "Pod"
return r.marshalObject(po) return r.marshalObject(po)
} }
// Containers lists out all the docker contrainers name contained in a pod. // Containers lists out all the docker contrainers name contained in a pod.
func (r *Pod) Containers(path string, includeInit bool) ([]string, error) { func (r *Pod) Containers(path string, includeInit bool) ([]string, error) {
ns, po := namespaced(path) ns, po := namespaced(path)
return r.caller.(k8s.Loggable).Containers(ns, po, includeInit)
return r.resource.(k8s.Loggable).Containers(ns, po, includeInit)
} }
// Logs tails a given container logs // Logs tails a given container logs
func (r *Pod) Logs(c chan<- string, ns, n, co string, lines int64, prev bool) (context.CancelFunc, error) { func (r *Pod) Logs(c chan<- string, ns, n, co string, lines int64, prev bool) (context.CancelFunc, error) {
req := r.caller.(k8s.Loggable).Logs(ns, n, co, lines, prev) req := r.resource.(k8s.Loggable).Logs(ns, n, co, lines, prev)
ctx, cancel := context.WithCancel(context.TODO()) ctx, cancel := context.WithCancel(context.TODO())
req.Context(ctx) req.Context(ctx)
@ -158,29 +149,32 @@ func (r *Pod) Logs(c chan<- string, ns, n, co string, lines int64, prev bool) (c
c <- scanner.Text() c <- scanner.Text()
} }
}() }()
return cancel, nil return cancel, nil
} }
// List resources for a given namespace. // List resources for a given namespace.
func (r *Pod) List(ns string) (Columnars, error) { func (r *Pod) List(ns string) (Columnars, error) {
ii, err := r.caller.List(ns) pods, err := r.resource.List(ns)
if err != nil { if err != nil {
return nil, err return nil, err
} }
metrics, err := r.metricSvc.PodMetrics() mx := make(k8s.PodsMetrics, len(pods))
if err != nil { if r.metricServer.HasMetrics() {
log.Error().Err(err) pmx, _ := r.metricServer.FetchPodsMetrics(ns)
r.metricServer.PodsMetrics(pmx, mx)
} }
cc := make(Columnars, 0, len(ii)) cc := make(Columnars, 0, len(pods))
for i := 0; i < len(ii); i++ { for i := range pods {
po := r.NewInstance(&ii[i]).(MxColumnar) po := r.New(&pods[i]).(*Pod)
if err == nil { if err == nil {
po.SetMetrics(metrics[po.Name()]) po.metrics = mx[po.Name()]
} }
cc = append(cc, po) cc = append(cc, po)
} }
return cc, nil return cc, nil
} }
@ -214,13 +208,14 @@ func (r *Pod) Fields(ns string) Row {
} }
cr, _, rc, cc := r.statuses() cr, _, rc, cc := r.statuses()
return append(ff, return append(ff,
Pad(i.ObjectMeta.Name, podNameSize), Pad(i.ObjectMeta.Name, podNameSize),
strconv.Itoa(cr)+"/"+strconv.Itoa(len(cc)), strconv.Itoa(cr)+"/"+strconv.Itoa(len(cc)),
r.phase(i.Status), r.phase(i.Status),
strconv.Itoa(rc), strconv.Itoa(rc),
r.metrics.CPU, ToMillicore(r.metrics.CurrentCPU),
r.metrics.Mem, ToMi(r.metrics.CurrentMEM),
i.Status.PodIP, i.Status.PodIP,
i.Spec.NodeName, i.Spec.NodeName,
string(i.Status.QOSClass), string(i.Status.QOSClass),
@ -228,27 +223,15 @@ func (r *Pod) Fields(ns string) Row {
) )
} }
// ExtFields returns extra info about the resource. // ----------------------------------------------------------------------------
func (r *Pod) ExtFields() Properties { // Helpers...
i := r.instance
return Properties{
"Priority": strconv.Itoa(int(*i.Spec.Priority)),
"Priority Class": missing(i.Spec.PriorityClassName),
"Labels": mapToStr(i.Labels),
"Annotations": mapToStr(i.ObjectMeta.Annotations),
"Containers": r.toContainers(i.Spec.Containers),
"Init Containers": r.toContainers(i.Spec.InitContainers),
"Node Selectors": mapToStr(i.Spec.NodeSelector),
"Volumes": r.toVolumes(i.Spec.Volumes),
}
}
func (r *Pod) toVolumes(vv []v1.Volume) map[string]interface{} { func (r *Pod) toVolumes(vv []v1.Volume) map[string]interface{} {
m := make(map[string]interface{}, len(vv)) m := make(map[string]interface{}, len(vv))
for _, v := range vv { for _, v := range vv {
m[v.Name] = r.toVolume(v) m[v.Name] = r.toVolume(v)
} }
return m return m
} }
@ -280,6 +263,7 @@ func (r *Pod) toContainers(cc []v1.Container) map[string]interface{} {
"Environment": r.toEnv(c.Env), "Environment": r.toEnv(c.Env),
} }
} }
return m return m
} }
@ -297,6 +281,7 @@ func (r *Pod) toEnv(ee []v1.EnvVar) []string {
ss[i] = e.Name + "=" + e.Value + "(" + s + ")" ss[i] = e.Name + "=" + e.Value + "(" + s + ")"
} }
} }
return ss return ss
} }
@ -317,6 +302,7 @@ func (r *Pod) toEnvFrom(e *v1.EnvVarSource) string {
f := e.SecretKeyRef f := e.SecretKeyRef
s += f.Name + ":" + f.Key + "(" + r.boolPtrToStr(f.Optional) + ")" s += f.Name + ":" + f.Key + "(" + r.boolPtrToStr(f.Optional) + ")"
} }
return s return s
} }
@ -339,6 +325,7 @@ func (r *Pod) statuses() (cr, ct, rc int, cc []v1.ContainerStatus) {
} }
rc += int(c.RestartCount) rc += int(c.RestartCount)
} }
return return
} }
@ -357,5 +344,6 @@ func (*Pod) phase(s v1.PodStatus) string {
} }
} }
} }
return status return status
} }

View File

@ -35,8 +35,9 @@ func TestPodFields(t *testing.T) {
func TestPodMarshal(t *testing.T) { func TestPodMarshal(t *testing.T) {
setup(t) setup(t)
mx := NewMockMetricsIfc() mx := NewMockMetricsServer()
m.When(mx.PodMetrics()).ThenReturn(map[string]k8s.Metric{"fred": {}}, nil) // metrics := make(k8s.PodsMetrics, 1)
// m.When(mx.PodsMetrics([]mv1beta1.PodMetrics{}, metrics)).thenReturn()
ca := NewMockCaller() ca := NewMockCaller()
m.When(ca.Get("blee", "fred")).ThenReturn(k8sPod(), nil) m.When(ca.Get("blee", "fred")).ThenReturn(k8sPod(), nil)
@ -50,8 +51,8 @@ func TestPodMarshal(t *testing.T) {
func TestPodListData(t *testing.T) { func TestPodListData(t *testing.T) {
setup(t) setup(t)
mx := NewMockMetricsIfc() mx := NewMockMetricsServer()
m.When(mx.PodMetrics()).ThenReturn(map[string]k8s.Metric{"fred": {}}, nil) // m.When(mx.PodsMetrics("")).ThenReturn(map[string]k8s.Metric{"fred": {}}, nil)
ca := NewMockCaller() ca := NewMockCaller()
m.When(ca.List("")).ThenReturn(k8s.Collection{*k8sPod()}, nil) m.When(ca.List("")).ThenReturn(k8s.Collection{*k8sPod()}, nil)
@ -66,7 +67,6 @@ func TestPodListData(t *testing.T) {
td := l.Data() td := l.Data()
assert.Equal(t, 1, len(td.Rows)) assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.AllNamespaces, l.GetNamespace()) assert.Equal(t, resource.AllNamespaces, l.GetNamespace())
assert.True(t, l.HasXRay())
row := td.Rows["blee/fred"] row := td.Rows["blee/fred"]
assert.Equal(t, 11, len(row.Deltas)) assert.Equal(t, 11, len(row.Deltas))
for _, d := range row.Deltas { for _, d := range row.Deltas {
@ -75,21 +75,6 @@ func TestPodListData(t *testing.T) {
assert.Equal(t, resource.Row{"blee"}, row.Fields[:1]) assert.Equal(t, resource.Row{"blee"}, row.Fields[:1])
} }
func TestPodListDescribe(t *testing.T) {
setup(t)
mx := NewMockMetricsIfc()
m.When(mx.PodMetrics()).ThenReturn(map[string]k8s.Metric{"fred": {}}, nil)
ca := NewMockCaller()
m.When(ca.Get("blee", "fred")).ThenReturn(k8sPod(), nil)
l := resource.NewPodListWithArgs("blee", resource.NewPodWithArgs(ca, mx))
props, err := l.Describe("blee/fred")
ca.VerifyWasCalledOnce().Get("blee", "fred")
assert.Nil(t, err)
assert.Equal(t, 8, len(props))
}
// Helpers... // Helpers...
func k8sPod() *v1.Pod { func k8sPod() *v1.Pod {

View File

@ -16,51 +16,43 @@ type PV struct {
} }
// NewPVList returns a new resource list. // NewPVList returns a new resource list.
func NewPVList(ns string) List { func NewPVList(c k8s.Connection, ns string) List {
return NewPVListWithArgs(ns, NewPV()) return newList(
NotNamespaced,
"pv",
NewPV(c),
CRUDAccess|DescribeAccess,
)
} }
// NewPVListWithArgs returns a new resource list. // NewPV instantiates a new PV.
func NewPVListWithArgs(ns string, res Resource) List { func NewPV(c k8s.Connection) *PV {
return newList(NotNamespaced, "pv", res, CRUDAccess|DescribeAccess) p := &PV{&Base{connection: c, resource: k8s.NewPV(c)}, nil}
p.Factory = p
return p
} }
// NewPV instantiates a new Endpoint. // New builds a new PV instance from a k8s resource.
func NewPV() *PV { func (r *PV) New(i interface{}) Columnar {
return NewPVWithArgs(k8s.NewPV()) c := NewPV(r.connection)
} switch instance := i.(type) {
// NewPVWithArgs instantiates a new Endpoint.
func NewPVWithArgs(r k8s.Res) *PV {
ep := &PV{
Base: &Base{
caller: r,
},
}
ep.creator = ep
return ep
}
// NewInstance builds a new Endpoint instance from a k8s resource.
func (*PV) NewInstance(i interface{}) Columnar {
cm := NewPV()
switch i.(type) {
case *v1.PersistentVolume: case *v1.PersistentVolume:
cm.instance = i.(*v1.PersistentVolume) c.instance = instance
case v1.PersistentVolume: case v1.PersistentVolume:
ii := i.(v1.PersistentVolume) c.instance = &instance
cm.instance = &ii
default: default:
log.Fatal().Msgf("Unknown %#v", i) log.Fatal().Msgf("unknown PV type %#v", i)
} }
cm.path = cm.namespacedName(cm.instance.ObjectMeta) c.path = c.namespacedName(c.instance.ObjectMeta)
return cm
return c
} }
// Marshal resource to yaml. // Marshal resource to yaml.
func (r *PV) Marshal(path string) (string, error) { func (r *PV) Marshal(path string) (string, error) {
ns, n := namespaced(path) ns, n := namespaced(path)
i, err := r.caller.Get(ns, n) i, err := r.resource.Get(ns, n)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -68,6 +60,7 @@ func (r *PV) Marshal(path string) (string, error) {
pv := i.(*v1.PersistentVolume) pv := i.(*v1.PersistentVolume)
pv.TypeMeta.APIVersion = "v1" pv.TypeMeta.APIVersion = "v1"
pv.TypeMeta.Kind = "PeristentVolume" pv.TypeMeta.Kind = "PeristentVolume"
return r.marshalObject(pv) return r.marshalObject(pv)
} }
@ -77,6 +70,7 @@ func (*PV) Header(ns string) Row {
if ns == AllNamespaces { if ns == AllNamespaces {
hh = append(hh, "NAMESPACE") hh = append(hh, "NAMESPACE")
} }
return append(hh, "NAME", "CAPACITY", "ACCESS MODES", "RECLAIM POLICY", "STATUS", "CLAIM", "STORAGECLASS", "REASON", "AGE") return append(hh, "NAME", "CAPACITY", "ACCESS MODES", "RECLAIM POLICY", "STATUS", "CLAIM", "STORAGECLASS", "REASON", "AGE")
} }
@ -118,11 +112,7 @@ func (r *PV) Fields(ns string) Row {
) )
} }
// ExtFields returns extended fields in relation to headers. // ----------------------------------------------------------------------------
func (*PV) ExtFields() Properties {
return Properties{}
}
// Helpers... // Helpers...
func (r *PV) accessMode(aa []v1.PersistentVolumeAccessMode) string { func (r *PV) accessMode(aa []v1.PersistentVolumeAccessMode) string {
@ -138,6 +128,7 @@ func (r *PV) accessMode(aa []v1.PersistentVolumeAccessMode) string {
s = append(s, "RWX") s = append(s, "RWX")
} }
} }
return strings.Join(s, ",") return strings.Join(s, ",")
} }
@ -147,6 +138,7 @@ func (r *PV) accessContains(cc []v1.PersistentVolumeAccessMode, a v1.PersistentV
return true return true
} }
} }
return false return false
} }
@ -157,5 +149,6 @@ func (r *PV) accessDedup(cc []v1.PersistentVolumeAccessMode) []v1.PersistentVolu
set = append(set, c) set = append(set, c)
} }
} }
return set return set
} }

View File

@ -62,7 +62,6 @@ func TestPVListData(t *testing.T) {
td := l.Data() td := l.Data()
assert.Equal(t, 1, len(td.Rows)) assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.NotNamespaced, l.GetNamespace()) assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"] row := td.Rows["blee/fred"]
assert.Equal(t, 9, len(row.Deltas)) assert.Equal(t, 9, len(row.Deltas))
for _, d := range row.Deltas { for _, d := range row.Deltas {
@ -71,19 +70,6 @@ func TestPVListData(t *testing.T) {
assert.Equal(t, resource.Row{"fred"}, row.Fields[:1]) assert.Equal(t, resource.Row{"fred"}, row.Fields[:1])
} }
func TestPVListDescribe(t *testing.T) {
setup(t)
ca := NewMockCaller()
m.When(ca.Get("blee", "fred")).ThenReturn(k8sPV(), nil)
l := resource.NewPVListWithArgs("blee", resource.NewPVWithArgs(ca))
props, err := l.Describe("blee/fred")
ca.VerifyWasCalledOnce().Get("blee", "fred")
assert.Nil(t, err)
assert.Equal(t, 0, len(props))
}
// Helpers... // Helpers...
func k8sPV() *v1.PersistentVolume { func k8sPV() *v1.PersistentVolume {

View File

@ -13,51 +13,43 @@ type PVC struct {
} }
// NewPVCList returns a new resource list. // NewPVCList returns a new resource list.
func NewPVCList(ns string) List { func NewPVCList(c k8s.Connection, ns string) List {
return NewPVCListWithArgs(ns, NewPVC()) return newList(
ns,
"pvc",
NewPVC(c),
AllVerbsAccess|DescribeAccess,
)
} }
// NewPVCListWithArgs returns a new resource list. // NewPVC instantiates a new PVC.
func NewPVCListWithArgs(ns string, res Resource) List { func NewPVC(c k8s.Connection) *PVC {
return newList(ns, "pvc", res, AllVerbsAccess|DescribeAccess) p := &PVC{&Base{connection: c, resource: k8s.NewPVC(c)}, nil}
p.Factory = p
return p
} }
// NewPVC instantiates a new Endpoint. // New builds a new PVC instance from a k8s resource.
func NewPVC() *PVC { func (r *PVC) New(i interface{}) Columnar {
return NewPVCWithArgs(k8s.NewPVC()) c := NewPVC(r.connection)
} switch instance := i.(type) {
// NewPVCWithArgs instantiates a new Endpoint.
func NewPVCWithArgs(r k8s.Res) *PVC {
ep := &PVC{
Base: &Base{
caller: r,
},
}
ep.creator = ep
return ep
}
// NewInstance builds a new Endpoint instance from a k8s resource.
func (*PVC) NewInstance(i interface{}) Columnar {
cm := NewPVC()
switch i.(type) {
case *v1.PersistentVolumeClaim: case *v1.PersistentVolumeClaim:
cm.instance = i.(*v1.PersistentVolumeClaim) c.instance = instance
case v1.PersistentVolumeClaim: case v1.PersistentVolumeClaim:
ii := i.(v1.PersistentVolumeClaim) c.instance = &instance
cm.instance = &ii
default: default:
log.Fatal().Msgf("Unknown %#v", i) log.Fatal().Msgf("unknown PVC type %#v", i)
} }
cm.path = cm.namespacedName(cm.instance.ObjectMeta) c.path = c.namespacedName(c.instance.ObjectMeta)
return cm
return c
} }
// Marshal resource to yaml. // Marshal resource to yaml.
func (r *PVC) Marshal(path string) (string, error) { func (r *PVC) Marshal(path string) (string, error) {
ns, n := namespaced(path) ns, n := namespaced(path)
i, err := r.caller.Get(ns, n) i, err := r.resource.Get(ns, n)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -65,6 +57,7 @@ func (r *PVC) Marshal(path string) (string, error) {
pvc := i.(*v1.PersistentVolumeClaim) pvc := i.(*v1.PersistentVolumeClaim)
pvc.TypeMeta.APIVersion = "v1" pvc.TypeMeta.APIVersion = "v1"
pvc.TypeMeta.Kind = "PersistentVolumeClaim" pvc.TypeMeta.Kind = "PersistentVolumeClaim"
return r.marshalObject(pvc) return r.marshalObject(pvc)
} }
@ -74,6 +67,7 @@ func (*PVC) Header(ns string) Row {
if ns == AllNamespaces { if ns == AllNamespaces {
hh = append(hh, "NAMESPACE") hh = append(hh, "NAMESPACE")
} }
return append(hh, "NAME", "STATUS", "VOLUME", "CAPACITY", "ACCESS MODES", "STORAGECLASS", "AGE") return append(hh, "NAME", "STATUS", "VOLUME", "CAPACITY", "ACCESS MODES", "STORAGECLASS", "AGE")
} }
@ -116,8 +110,3 @@ func (r *PVC) Fields(ns string) Row {
toAge(i.ObjectMeta.CreationTimestamp), toAge(i.ObjectMeta.CreationTimestamp),
) )
} }
// ExtFields returns extended fields in relation to headers.
func (*PVC) ExtFields() Properties {
return Properties{}
}

View File

@ -63,7 +63,6 @@ func TestPVCListData(t *testing.T) {
td := l.Data() td := l.Data()
assert.Equal(t, 1, len(td.Rows)) assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.NotNamespaced, l.GetNamespace()) assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"] row := td.Rows["blee/fred"]
assert.Equal(t, 7, len(row.Deltas)) assert.Equal(t, 7, len(row.Deltas))
for _, d := range row.Deltas { for _, d := range row.Deltas {
@ -72,19 +71,6 @@ func TestPVCListData(t *testing.T) {
assert.Equal(t, resource.Row{"fred"}, row.Fields[:1]) assert.Equal(t, resource.Row{"fred"}, row.Fields[:1])
} }
func TestPVCListDescribe(t *testing.T) {
setup(t)
ca := NewMockCaller()
m.When(ca.Get("blee", "fred")).ThenReturn(k8sPVC(), nil)
l := resource.NewPVCListWithArgs("blee", resource.NewPVCWithArgs(ca))
props, err := l.Describe("blee/fred")
ca.VerifyWasCalledOnce().Get("blee", "fred")
assert.Nil(t, err)
assert.Equal(t, 0, len(props))
}
// Helpers... // Helpers...
func k8sPVC() *v1.PersistentVolumeClaim { func k8sPVC() *v1.PersistentVolumeClaim {

View File

@ -15,51 +15,43 @@ type ReplicationController struct {
} }
// NewReplicationControllerList returns a new resource list. // NewReplicationControllerList returns a new resource list.
func NewReplicationControllerList(ns string) List { func NewReplicationControllerList(c k8s.Connection, ns string) List {
return NewReplicationControllerListWithArgs(ns, NewReplicationController()) return newList(
ns,
"rc",
NewReplicationController(c),
AllVerbsAccess|DescribeAccess,
)
} }
// NewReplicationControllerListWithArgs returns a new resource list. // NewReplicationController instantiates a new ReplicationController.
func NewReplicationControllerListWithArgs(ns string, res Resource) List { func NewReplicationController(c k8s.Connection) *ReplicationController {
return newList(ns, "rc", res, AllVerbsAccess|DescribeAccess) r := &ReplicationController{&Base{connection: c, resource: k8s.NewReplicationController(c)}, nil}
r.Factory = r
return r
} }
// NewReplicationController instantiates a new Endpoint. // New builds a new ReplicationController instance from a k8s resource.
func NewReplicationController() *ReplicationController { func (r *ReplicationController) New(i interface{}) Columnar {
return NewReplicationControllerWithArgs(k8s.NewReplicationController()) c := NewReplicationController(r.connection)
} switch instance := i.(type) {
// NewReplicationControllerWithArgs instantiates a new Endpoint.
func NewReplicationControllerWithArgs(r k8s.Res) *ReplicationController {
ep := &ReplicationController{
Base: &Base{
caller: r,
},
}
ep.creator = ep
return ep
}
// NewInstance builds a new Endpoint instance from a k8s resource.
func (*ReplicationController) NewInstance(i interface{}) Columnar {
cm := NewReplicationController()
switch i.(type) {
case *v1.ReplicationController: case *v1.ReplicationController:
cm.instance = i.(*v1.ReplicationController) c.instance = instance
case v1.ReplicationController: case v1.ReplicationController:
ii := i.(v1.ReplicationController) c.instance = &instance
cm.instance = &ii
default: default:
log.Fatal().Msgf("Unknown %#v", i) log.Fatal().Msgf("unknown ReplicationController type %#v", i)
} }
cm.path = cm.namespacedName(cm.instance.ObjectMeta) c.path = c.namespacedName(c.instance.ObjectMeta)
return cm
return c
} }
// Marshal a deployment given a namespaced name. // Marshal a deployment given a namespaced name.
func (r *ReplicationController) Marshal(path string) (string, error) { func (r *ReplicationController) Marshal(path string) (string, error) {
ns, n := namespaced(path) ns, n := namespaced(path)
i, err := r.caller.Get(ns, n) i, err := r.resource.Get(ns, n)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -67,6 +59,7 @@ func (r *ReplicationController) Marshal(path string) (string, error) {
rc := i.(*v1.ReplicationController) rc := i.(*v1.ReplicationController)
rc.TypeMeta.APIVersion = "v1" rc.TypeMeta.APIVersion = "v1"
rc.TypeMeta.Kind = "ReplicationController" rc.TypeMeta.Kind = "ReplicationController"
return r.marshalObject(rc) return r.marshalObject(rc)
} }
@ -76,6 +69,7 @@ func (*ReplicationController) Header(ns string) Row {
if ns == AllNamespaces { if ns == AllNamespaces {
hh = append(hh, "NAMESPACE") hh = append(hh, "NAMESPACE")
} }
return append(hh, "NAME", "DESIRED", "CURRENT", "READY", "AGE") return append(hh, "NAME", "DESIRED", "CURRENT", "READY", "AGE")
} }
@ -85,8 +79,8 @@ func (r *ReplicationController) Fields(ns string) Row {
if ns == AllNamespaces { if ns == AllNamespaces {
ff = append(ff, r.instance.Namespace) ff = append(ff, r.instance.Namespace)
} }
i := r.instance i := r.instance
return append(ff, return append(ff,
i.Name, i.Name,
strconv.Itoa(int(*i.Spec.Replicas)), strconv.Itoa(int(*i.Spec.Replicas)),
@ -95,8 +89,3 @@ func (r *ReplicationController) Fields(ns string) Row {
toAge(i.ObjectMeta.CreationTimestamp), toAge(i.ObjectMeta.CreationTimestamp),
) )
} }
// ExtFields returns extended fields in relation to headers.
func (*ReplicationController) ExtFields() Properties {
return Properties{}
}

View File

@ -15,53 +15,43 @@ type Role struct {
} }
// NewRoleList returns a new resource list. // NewRoleList returns a new resource list.
func NewRoleList(ns string) List { func NewRoleList(c k8s.Connection, ns string) List {
return NewRoleListWithArgs(ns, NewRole()) return newList(
ns,
"role",
NewRole(c),
AllVerbsAccess|DescribeAccess,
)
} }
// NewRoleListWithArgs returns a new resource list. // NewRole instantiates a new Role.
func NewRoleListWithArgs(ns string, res Resource) List { func NewRole(c k8s.Connection) *Role {
l := newList(ns, "role", res, AllVerbsAccess|DescribeAccess) r := &Role{&Base{connection: c, resource: k8s.NewRole(c)}, nil}
l.xray = true r.Factory = r
return l
return r
} }
// NewRole instantiates a new Endpoint. // New builds a new Role instance from a k8s resource.
func NewRole() *Role { func (r *Role) New(i interface{}) Columnar {
return NewRoleWithArgs(k8s.NewRole()) c := NewRole(r.connection)
} switch instance := i.(type) {
// NewRoleWithArgs instantiates a new Endpoint.
func NewRoleWithArgs(r k8s.Res) *Role {
ep := &Role{
Base: &Base{
caller: r,
},
}
ep.creator = ep
return ep
}
// NewInstance builds a new Endpoint instance from a k8s resource.
func (*Role) NewInstance(i interface{}) Columnar {
cm := NewRole()
switch i.(type) {
case *v1.Role: case *v1.Role:
cm.instance = i.(*v1.Role) c.instance = instance
case v1.Role: case v1.Role:
ii := i.(v1.Role) c.instance = &instance
cm.instance = &ii
default: default:
log.Fatal().Msgf("Unknown %#v", i) log.Fatal().Msgf("unknown Role type %#v", i)
} }
cm.path = cm.namespacedName(cm.instance.ObjectMeta) c.path = c.namespacedName(c.instance.ObjectMeta)
return cm
return c
} }
// Marshal resource to yaml. // Marshal resource to yaml.
func (r *Role) Marshal(path string) (string, error) { func (r *Role) Marshal(path string) (string, error) {
ns, n := namespaced(path) ns, n := namespaced(path)
i, err := r.caller.Get(ns, n) i, err := r.resource.Get(ns, n)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -69,6 +59,7 @@ func (r *Role) Marshal(path string) (string, error) {
role := i.(*v1.Role) role := i.(*v1.Role)
role.TypeMeta.APIVersion = "rbac.authorization.k8s.io/v1" role.TypeMeta.APIVersion = "rbac.authorization.k8s.io/v1"
role.TypeMeta.Kind = "Role" role.TypeMeta.Kind = "Role"
return r.marshalObject(role) return r.marshalObject(role)
} }
@ -78,6 +69,7 @@ func (*Role) Header(ns string) Row {
if ns == AllNamespaces { if ns == AllNamespaces {
hh = append(hh, "NAMESPACE") hh = append(hh, "NAMESPACE")
} }
return append(hh, "NAME", "AGE") return append(hh, "NAME", "AGE")
} }
@ -95,16 +87,7 @@ func (r *Role) Fields(ns string) Row {
) )
} }
// ExtFields returns extended fields in relation to headers. // ----------------------------------------------------------------------------
func (r *Role) ExtFields() Properties {
i := r.instance
return Properties{
"Headers": Row{"RESOURCES", "NON-RESOURCE URLS", "RESOURCE NAMES", "VERBS"},
"Rows": r.parseRules(i.Rules),
}
}
// Helpers... // Helpers...
func (r *Role) parseRules(pp []v1.PolicyRule) []Row { func (r *Role) parseRules(pp []v1.PolicyRule) []Row {
@ -116,5 +99,6 @@ func (r *Role) parseRules(pp []v1.PolicyRule) []Row {
acc[i][2] = strings.Join(p.ResourceNames, ", ") acc[i][2] = strings.Join(p.ResourceNames, ", ")
acc[i][3] = strings.Join(p.Verbs, ", ") acc[i][3] = strings.Join(p.Verbs, ", ")
} }
return acc return acc
} }

View File

@ -15,51 +15,43 @@ type RoleBinding struct {
} }
// NewRoleBindingList returns a new resource list. // NewRoleBindingList returns a new resource list.
func NewRoleBindingList(ns string) List { func NewRoleBindingList(c k8s.Connection, ns string) List {
return NewRoleBindingListWithArgs(ns, NewRoleBinding()) return newList(
ns,
"rolebinding",
NewRoleBinding(c),
AllVerbsAccess|DescribeAccess,
)
} }
// NewRoleBindingListWithArgs returns a new resource list. // NewRoleBinding instantiates a new RoleBinding.
func NewRoleBindingListWithArgs(ns string, res Resource) List { func NewRoleBinding(c k8s.Connection) *RoleBinding {
return newList(ns, "rolebinding", res, AllVerbsAccess|DescribeAccess) r := &RoleBinding{&Base{connection: c, resource: k8s.NewRoleBinding(c)}, nil}
r.Factory = r
return r
} }
// NewRoleBinding instantiates a new Endpoint. // New builds a new RoleBinding instance from a k8s resource.
func NewRoleBinding() *RoleBinding { func (r *RoleBinding) New(i interface{}) Columnar {
return NewRoleBindingWithArgs(k8s.NewRoleBinding()) c := NewRoleBinding(r.connection)
} switch instance := i.(type) {
// NewRoleBindingWithArgs instantiates a new Endpoint.
func NewRoleBindingWithArgs(r k8s.Res) *RoleBinding {
ep := &RoleBinding{
Base: &Base{
caller: r,
},
}
ep.creator = ep
return ep
}
// NewInstance builds a new Endpoint instance from a k8s resource.
func (*RoleBinding) NewInstance(i interface{}) Columnar {
cm := NewRoleBinding()
switch i.(type) {
case *v1.RoleBinding: case *v1.RoleBinding:
cm.instance = i.(*v1.RoleBinding) c.instance = instance
case v1.RoleBinding: case v1.RoleBinding:
ii := i.(v1.RoleBinding) c.instance = &instance
cm.instance = &ii
default: default:
log.Fatal().Msgf("Unknown %#v", i) log.Fatal().Msgf("unknown RoleBinding type %#v", i)
} }
cm.path = cm.namespacedName(cm.instance.ObjectMeta) c.path = c.namespacedName(c.instance.ObjectMeta)
return cm
return c
} }
// Marshal resource to yaml. // Marshal resource to yaml.
func (r *RoleBinding) Marshal(path string) (string, error) { func (r *RoleBinding) Marshal(path string) (string, error) {
ns, n := namespaced(path) ns, n := namespaced(path)
i, err := r.caller.Get(ns, n) i, err := r.resource.Get(ns, n)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -67,6 +59,7 @@ func (r *RoleBinding) Marshal(path string) (string, error) {
rb := i.(*v1.RoleBinding) rb := i.(*v1.RoleBinding)
rb.TypeMeta.APIVersion = "rbac.authorization.k8s.io/v1" rb.TypeMeta.APIVersion = "rbac.authorization.k8s.io/v1"
rb.TypeMeta.Kind = "RoleBinding" rb.TypeMeta.Kind = "RoleBinding"
return r.marshalObject(rb) return r.marshalObject(rb)
} }
@ -76,6 +69,7 @@ func (*RoleBinding) Header(ns string) Row {
if ns == AllNamespaces { if ns == AllNamespaces {
hh = append(hh, "NAMESPACE") hh = append(hh, "NAMESPACE")
} }
return append(hh, "NAME", "ROLE", "SUBJECTS", "AGE") return append(hh, "NAME", "ROLE", "SUBJECTS", "AGE")
} }
@ -95,11 +89,7 @@ func (r *RoleBinding) Fields(ns string) Row {
) )
} }
// ExtFields returns extended fields in relation to headers. // ----------------------------------------------------------------------------
func (*RoleBinding) ExtFields() Properties {
return Properties{}
}
// Helpers... // Helpers...
func (r *RoleBinding) toSubjects(ss []v1.Subject) string { func (r *RoleBinding) toSubjects(ss []v1.Subject) string {
@ -110,6 +100,7 @@ func (r *RoleBinding) toSubjects(ss []v1.Subject) string {
acc += "," acc += ","
} }
} }
return acc return acc
} }

View File

@ -41,7 +41,6 @@ func TestRBListData(t *testing.T) {
td := l.Data() td := l.Data()
assert.Equal(t, 1, len(td.Rows)) assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, "blee", l.GetNamespace()) assert.Equal(t, "blee", l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"] row := td.Rows["blee/fred"]
assert.Equal(t, 4, len(row.Deltas)) assert.Equal(t, 4, len(row.Deltas))
for _, d := range row.Deltas { for _, d := range row.Deltas {
@ -50,19 +49,6 @@ func TestRBListData(t *testing.T) {
assert.Equal(t, resource.Row{"fred"}, row.Fields[:1]) assert.Equal(t, resource.Row{"fred"}, row.Fields[:1])
} }
func TestRBListDescribe(t *testing.T) {
setup(t)
ca := NewMockCaller()
m.When(ca.Get("blee", "fred")).ThenReturn(k8sRB(), nil)
l := resource.NewRoleBindingListWithArgs("blee", resource.NewRoleBindingWithArgs(ca))
props, err := l.Describe("blee/fred")
ca.VerifyWasCalledOnce().Get("blee", "fred")
assert.Nil(t, err)
assert.Equal(t, 0, len(props))
}
// Helpers... // Helpers...
func k8sRB() *v1.RoleBinding { func k8sRB() *v1.RoleBinding {

View File

@ -41,7 +41,6 @@ func TestRoleListData(t *testing.T) {
td := l.Data() td := l.Data()
assert.Equal(t, 1, len(td.Rows)) assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, "blee", l.GetNamespace()) assert.Equal(t, "blee", l.GetNamespace())
assert.True(t, l.HasXRay())
row := td.Rows["blee/fred"] row := td.Rows["blee/fred"]
assert.Equal(t, 2, len(row.Deltas)) assert.Equal(t, 2, len(row.Deltas))
for _, d := range row.Deltas { for _, d := range row.Deltas {
@ -50,19 +49,6 @@ func TestRoleListData(t *testing.T) {
assert.Equal(t, resource.Row{"fred"}, row.Fields[:1]) assert.Equal(t, resource.Row{"fred"}, row.Fields[:1])
} }
func TestRoleListDescribe(t *testing.T) {
setup(t)
ca := NewMockCaller()
m.When(ca.Get("blee", "fred")).ThenReturn(k8sRole(), nil)
l := resource.NewRoleListWithArgs("blee", resource.NewRoleWithArgs(ca))
props, err := l.Describe("blee/fred")
ca.VerifyWasCalledOnce().Get("blee", "fred")
assert.Nil(t, err)
assert.Equal(t, 2, len(props))
}
// Helpers... // Helpers...
func k8sRole() *v1.Role { func k8sRole() *v1.Role {

View File

@ -15,51 +15,43 @@ type ReplicaSet struct {
} }
// NewReplicaSetList returns a new resource list. // NewReplicaSetList returns a new resource list.
func NewReplicaSetList(ns string) List { func NewReplicaSetList(c k8s.Connection, ns string) List {
return NewReplicaSetListWithArgs(ns, NewReplicaSet()) return newList(
ns,
"rs",
NewReplicaSet(c),
AllVerbsAccess|DescribeAccess,
)
} }
// NewReplicaSetListWithArgs returns a new resource list. // NewReplicaSet instantiates a new ReplicaSet.
func NewReplicaSetListWithArgs(ns string, res Resource) List { func NewReplicaSet(c k8s.Connection) *ReplicaSet {
return newList(ns, "rs", res, AllVerbsAccess|DescribeAccess) r := &ReplicaSet{&Base{connection: c, resource: k8s.NewReplicaSet(c)}, nil}
r.Factory = r
return r
} }
// NewReplicaSet instantiates a new Endpoint. // New builds a new ReplicaSet instance from a k8s resource.
func NewReplicaSet() *ReplicaSet { func (r *ReplicaSet) New(i interface{}) Columnar {
return NewReplicaSetWithArgs(k8s.NewReplicaSet()) c := NewReplicaSet(r.connection)
} switch instance := i.(type) {
// NewReplicaSetWithArgs instantiates a new Endpoint.
func NewReplicaSetWithArgs(r k8s.Res) *ReplicaSet {
ep := &ReplicaSet{
Base: &Base{
caller: r,
},
}
ep.creator = ep
return ep
}
// NewInstance builds a new Endpoint instance from a k8s resource.
func (*ReplicaSet) NewInstance(i interface{}) Columnar {
cm := NewReplicaSet()
switch i.(type) {
case *v1.ReplicaSet: case *v1.ReplicaSet:
cm.instance = i.(*v1.ReplicaSet) c.instance = instance
case v1.ReplicaSet: case v1.ReplicaSet:
ii := i.(v1.ReplicaSet) c.instance = &instance
cm.instance = &ii
default: default:
log.Fatal().Msgf("Unknown %#v", i) log.Fatal().Msgf("unknown ReplicaSet type %#v", i)
} }
cm.path = cm.namespacedName(cm.instance.ObjectMeta) c.path = c.namespacedName(c.instance.ObjectMeta)
return cm
return c
} }
// Marshal a deployment given a namespaced name. // Marshal a deployment given a namespaced name.
func (r *ReplicaSet) Marshal(path string) (string, error) { func (r *ReplicaSet) Marshal(path string) (string, error) {
ns, n := namespaced(path) ns, n := namespaced(path)
i, err := r.caller.Get(ns, n) i, err := r.resource.Get(ns, n)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -67,6 +59,7 @@ func (r *ReplicaSet) Marshal(path string) (string, error) {
rs := i.(*v1.ReplicaSet) rs := i.(*v1.ReplicaSet)
rs.TypeMeta.APIVersion = "extensions/v1beta" rs.TypeMeta.APIVersion = "extensions/v1beta"
rs.TypeMeta.Kind = "ReplicaSet" rs.TypeMeta.Kind = "ReplicaSet"
return r.marshalObject(rs) return r.marshalObject(rs)
} }
@ -76,6 +69,7 @@ func (*ReplicaSet) Header(ns string) Row {
if ns == AllNamespaces { if ns == AllNamespaces {
hh = append(hh, "NAMESPACE") hh = append(hh, "NAMESPACE")
} }
return append(hh, "NAME", "DESIRED", "CURRENT", "READY", "AGE") return append(hh, "NAME", "DESIRED", "CURRENT", "READY", "AGE")
} }
@ -87,6 +81,7 @@ func (r *ReplicaSet) Fields(ns string) Row {
} }
i := r.instance i := r.instance
return append(ff, return append(ff,
i.Name, i.Name,
strconv.Itoa(int(*i.Spec.Replicas)), strconv.Itoa(int(*i.Spec.Replicas)),
@ -95,8 +90,3 @@ func (r *ReplicaSet) Fields(ns string) Row {
toAge(i.ObjectMeta.CreationTimestamp), toAge(i.ObjectMeta.CreationTimestamp),
) )
} }
// ExtFields returns extended fields in relation to headers.
func (*ReplicaSet) ExtFields() Properties {
return Properties{}
}

View File

@ -41,7 +41,6 @@ func TestReplicaSetListData(t *testing.T) {
td := l.Data() td := l.Data()
assert.Equal(t, 1, len(td.Rows)) assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, "blee", l.GetNamespace()) assert.Equal(t, "blee", l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"] row := td.Rows["blee/fred"]
assert.Equal(t, 5, len(row.Deltas)) assert.Equal(t, 5, len(row.Deltas))
for _, d := range row.Deltas { for _, d := range row.Deltas {
@ -50,19 +49,6 @@ func TestReplicaSetListData(t *testing.T) {
assert.Equal(t, resource.Row{"fred"}, row.Fields[:1]) assert.Equal(t, resource.Row{"fred"}, row.Fields[:1])
} }
func TestReplicaSetListDescribe(t *testing.T) {
setup(t)
ca := NewMockCaller()
m.When(ca.Get("blee", "fred")).ThenReturn(k8sReplicaSet(), nil)
l := resource.NewReplicaSetListWithArgs("blee", resource.NewReplicaSetWithArgs(ca))
props, err := l.Describe("blee/fred")
ca.VerifyWasCalledOnce().Get("blee", "fred")
assert.Nil(t, err)
assert.Equal(t, 0, len(props))
}
// Helpers... // Helpers...
func k8sReplicaSet() *v1.ReplicaSet { func k8sReplicaSet() *v1.ReplicaSet {

View File

@ -15,51 +15,43 @@ type ServiceAccount struct {
} }
// NewServiceAccountList returns a new resource list. // NewServiceAccountList returns a new resource list.
func NewServiceAccountList(ns string) List { func NewServiceAccountList(c k8s.Connection, ns string) List {
return NewServiceAccountListWithArgs(ns, NewServiceAccount()) return newList(
ns,
"sa",
NewServiceAccount(c),
AllVerbsAccess|DescribeAccess,
)
} }
// NewServiceAccountListWithArgs returns a new resource list. // NewServiceAccount instantiates a new ServiceAccount.
func NewServiceAccountListWithArgs(ns string, res Resource) List { func NewServiceAccount(c k8s.Connection) *ServiceAccount {
return newList(ns, "sa", res, AllVerbsAccess|DescribeAccess) s := &ServiceAccount{&Base{connection: c, resource: k8s.NewServiceAccount(c)}, nil}
s.Factory = s
return s
} }
// NewServiceAccount instantiates a new Endpoint. // New builds a new ServiceAccount instance from a k8s resource.
func NewServiceAccount() *ServiceAccount { func (r *ServiceAccount) New(i interface{}) Columnar {
return NewServiceAccountWithArgs(k8s.NewServiceAccount()) c := NewServiceAccount(r.connection)
} switch instance := i.(type) {
// NewServiceAccountWithArgs instantiates a new Endpoint.
func NewServiceAccountWithArgs(r k8s.Res) *ServiceAccount {
ep := &ServiceAccount{
Base: &Base{
caller: r,
},
}
ep.creator = ep
return ep
}
// NewInstance builds a new Endpoint instance from a k8s resource.
func (*ServiceAccount) NewInstance(i interface{}) Columnar {
cm := NewServiceAccount()
switch i.(type) {
case *v1.ServiceAccount: case *v1.ServiceAccount:
cm.instance = i.(*v1.ServiceAccount) c.instance = instance
case v1.ServiceAccount: case v1.ServiceAccount:
ii := i.(v1.ServiceAccount) c.instance = &instance
cm.instance = &ii
default: default:
log.Fatal().Msgf("Unknown %#v", i) log.Fatal().Msgf("unknown ServiceAccount type %#v", i)
} }
cm.path = cm.namespacedName(cm.instance.ObjectMeta) c.path = c.namespacedName(c.instance.ObjectMeta)
return cm
return c
} }
// Marshal resource to yaml. // Marshal resource to yaml.
func (r *ServiceAccount) Marshal(path string) (string, error) { func (r *ServiceAccount) Marshal(path string) (string, error) {
ns, n := namespaced(path) ns, n := namespaced(path)
i, err := r.caller.Get(ns, n) i, err := r.resource.Get(ns, n)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -67,6 +59,7 @@ func (r *ServiceAccount) Marshal(path string) (string, error) {
sa := i.(*v1.ServiceAccount) sa := i.(*v1.ServiceAccount)
sa.TypeMeta.APIVersion = "v1" sa.TypeMeta.APIVersion = "v1"
sa.TypeMeta.Kind = "ServiceAccount" sa.TypeMeta.Kind = "ServiceAccount"
return r.marshalObject(sa) return r.marshalObject(sa)
} }
@ -76,6 +69,7 @@ func (*ServiceAccount) Header(ns string) Row {
if ns == AllNamespaces { if ns == AllNamespaces {
hh = append(hh, "NAMESPACE") hh = append(hh, "NAMESPACE")
} }
return append(hh, "NAME", "SECRET", "AGE") return append(hh, "NAME", "SECRET", "AGE")
} }
@ -93,8 +87,3 @@ func (r *ServiceAccount) Fields(ns string) Row {
toAge(i.ObjectMeta.CreationTimestamp), toAge(i.ObjectMeta.CreationTimestamp),
) )
} }
// ExtFields returns extended fields in relation to headers.
func (*ServiceAccount) ExtFields() Properties {
return Properties{}
}

View File

@ -75,7 +75,6 @@ func TestSAListData(t *testing.T) {
td := l.Data() td := l.Data()
assert.Equal(t, 1, len(td.Rows)) assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.NotNamespaced, l.GetNamespace()) assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"] row := td.Rows["blee/fred"]
assert.Equal(t, 3, len(row.Deltas)) assert.Equal(t, 3, len(row.Deltas))
for _, d := range row.Deltas { for _, d := range row.Deltas {
@ -84,19 +83,6 @@ func TestSAListData(t *testing.T) {
assert.Equal(t, resource.Row{"fred"}, row.Fields[:1]) assert.Equal(t, resource.Row{"fred"}, row.Fields[:1])
} }
func TestSAListDescribe(t *testing.T) {
setup(t)
ca := NewMockCaller()
m.When(ca.Get("blee", "fred")).ThenReturn(k8sSA(), nil)
l := resource.NewServiceAccountListWithArgs("blee", resource.NewServiceAccountWithArgs(ca))
props, err := l.Describe("blee/fred")
ca.VerifyWasCalledOnce().Get("blee", "fred")
assert.Nil(t, err)
assert.Equal(t, 0, len(props))
}
// Helpers... // Helpers...
func k8sSA() *v1.ServiceAccount { func k8sSA() *v1.ServiceAccount {

View File

@ -1,10 +1,10 @@
package resource package resource
import ( import (
"log"
"strconv" "strconv"
"github.com/derailed/k9s/internal/k8s" "github.com/derailed/k9s/internal/k8s"
"github.com/rs/zerolog/log"
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
) )
@ -15,51 +15,43 @@ type Secret struct {
} }
// NewSecretList returns a new resource list. // NewSecretList returns a new resource list.
func NewSecretList(ns string) List { func NewSecretList(c k8s.Connection, ns string) List {
return NewSecretListWithArgs(ns, NewSecret()) return newList(
} ns,
"secret",
// NewSecretListWithArgs returns a new resource list. NewSecret(c),
func NewSecretListWithArgs(ns string, res Resource) List { AllVerbsAccess|DescribeAccess,
return newList(ns, "secret", res, AllVerbsAccess|DescribeAccess) )
} }
// NewSecret instantiates a new Secret. // NewSecret instantiates a new Secret.
func NewSecret() *Secret { func NewSecret(c k8s.Connection) *Secret {
return NewSecretWithArgs(k8s.NewSecret()) s := &Secret{&Base{connection: c, resource: k8s.NewSecret(c)}, nil}
s.Factory = s
return s
} }
// NewSecretWithArgs instantiates a new Secret. // New builds a new Secret instance from a k8s resource.
func NewSecretWithArgs(r k8s.Res) *Secret { func (r *Secret) New(i interface{}) Columnar {
cm := &Secret{ c := NewSecret(r.connection)
Base: &Base{ switch instance := i.(type) {
caller: r,
},
}
cm.creator = cm
return cm
}
// NewInstance builds a new Secret instance from a k8s resource.
func (*Secret) NewInstance(i interface{}) Columnar {
cm := NewSecret()
switch i.(type) {
case *v1.Secret: case *v1.Secret:
cm.instance = i.(*v1.Secret) c.instance = instance
case v1.Secret: case v1.Secret:
ii := i.(v1.Secret) c.instance = &instance
cm.instance = &ii
default: default:
log.Fatalf("Unknown %#v", i) log.Fatal().Msgf("unknown Secret type %#v", i)
} }
cm.path = cm.namespacedName(cm.instance.ObjectMeta) c.path = c.namespacedName(c.instance.ObjectMeta)
return cm
return c
} }
// Marshal resource to yaml. // Marshal resource to yaml.
func (r *Secret) Marshal(path string) (string, error) { func (r *Secret) Marshal(path string) (string, error) {
ns, n := namespaced(path) ns, n := namespaced(path)
i, err := r.caller.Get(ns, n) i, err := r.resource.Get(ns, n)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -67,6 +59,7 @@ func (r *Secret) Marshal(path string) (string, error) {
sec := i.(*v1.Secret) sec := i.(*v1.Secret)
sec.TypeMeta.APIVersion = "v1" sec.TypeMeta.APIVersion = "v1"
sec.TypeMeta.Kind = "Secret" sec.TypeMeta.Kind = "Secret"
return r.marshalObject(sec) return r.marshalObject(sec)
} }
@ -76,6 +69,7 @@ func (*Secret) Header(ns string) Row {
if ns == AllNamespaces { if ns == AllNamespaces {
hh = append(hh, "NAMESPACE") hh = append(hh, "NAMESPACE")
} }
return append(hh, "NAME", "TYPE", "DATA", "AGE") return append(hh, "NAME", "TYPE", "DATA", "AGE")
} }
@ -94,8 +88,3 @@ func (r *Secret) Fields(ns string) Row {
toAge(i.ObjectMeta.CreationTimestamp), toAge(i.ObjectMeta.CreationTimestamp),
) )
} }
// ExtFields returns extended fields in relation to headers.
func (*Secret) ExtFields() Properties {
return Properties{}
}

View File

@ -114,20 +114,6 @@ func TestSecretListHasResource(t *testing.T) {
assert.NotNil(t, l.Resource()) assert.NotNil(t, l.Resource())
} }
func TestSecretListDescribe(t *testing.T) {
setup(t)
ca := NewMockCaller()
m.When(ca.Get("blee", "fred")).ThenReturn(k8sSecret(), nil)
l := resource.NewSecretListWithArgs("blee", resource.NewSecretWithArgs(ca))
props, err := l.Describe("blee/fred")
ca.VerifyWasCalledOnce().Get("blee", "fred")
assert.Nil(t, err)
assert.Equal(t, 0, len(props))
}
func TestSecretListData(t *testing.T) { func TestSecretListData(t *testing.T) {
setup(t) setup(t)
@ -147,7 +133,6 @@ func TestSecretListData(t *testing.T) {
assert.Equal(t, 1, len(td.Rows)) assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, "blee", l.GetNamespace()) assert.Equal(t, "blee", l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"] row := td.Rows["blee/fred"]
assert.Equal(t, 4, len(row.Deltas)) assert.Equal(t, 4, len(row.Deltas))
for _, d := range row.Deltas { for _, d := range row.Deltas {

View File

@ -15,51 +15,43 @@ type StatefulSet struct {
} }
// NewStatefulSetList returns a new resource list. // NewStatefulSetList returns a new resource list.
func NewStatefulSetList(ns string) List { func NewStatefulSetList(c k8s.Connection, ns string) List {
return NewStatefulSetListWithArgs(ns, NewStatefulSet()) return newList(
ns,
"sts",
NewStatefulSet(c),
AllVerbsAccess|DescribeAccess,
)
} }
// NewStatefulSetListWithArgs returns a new resource list. // NewStatefulSet instantiates a new StatefulSet.
func NewStatefulSetListWithArgs(ns string, res Resource) List { func NewStatefulSet(c k8s.Connection) *StatefulSet {
return newList(ns, "sts", res, AllVerbsAccess|DescribeAccess) s := &StatefulSet{&Base{connection: c, resource: k8s.NewStatefulSet(c)}, nil}
s.Factory = s
return s
} }
// NewStatefulSet instantiates a new Endpoint. // New builds a new StatefulSet instance from a k8s resource.
func NewStatefulSet() *StatefulSet { func (r *StatefulSet) New(i interface{}) Columnar {
return NewStatefulSetWithArgs(k8s.NewStatefulSet()) c := NewStatefulSet(r.connection)
} switch instance := i.(type) {
// NewStatefulSetWithArgs instantiates a new Endpoint.
func NewStatefulSetWithArgs(r k8s.Res) *StatefulSet {
ep := &StatefulSet{
Base: &Base{
caller: r,
},
}
ep.creator = ep
return ep
}
// NewInstance builds a new Endpoint instance from a k8s resource.
func (*StatefulSet) NewInstance(i interface{}) Columnar {
cm := NewStatefulSet()
switch i.(type) {
case *v1.StatefulSet: case *v1.StatefulSet:
cm.instance = i.(*v1.StatefulSet) c.instance = instance
case v1.StatefulSet: case v1.StatefulSet:
ii := i.(v1.StatefulSet) c.instance = &instance
cm.instance = &ii
default: default:
log.Fatal().Msgf("Unknown %#v", i) log.Fatal().Msgf("unknown StatefulSet type %#v", i)
} }
cm.path = cm.namespacedName(cm.instance.ObjectMeta) c.path = c.namespacedName(c.instance.ObjectMeta)
return cm
return c
} }
// Marshal resource to yaml. // Marshal resource to yaml.
func (r *StatefulSet) Marshal(path string) (string, error) { func (r *StatefulSet) Marshal(path string) (string, error) {
ns, n := namespaced(path) ns, n := namespaced(path)
i, err := r.caller.Get(ns, n) i, err := r.resource.Get(ns, n)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -67,6 +59,7 @@ func (r *StatefulSet) Marshal(path string) (string, error) {
sts := i.(*v1.StatefulSet) sts := i.(*v1.StatefulSet)
sts.TypeMeta.APIVersion = "v1" sts.TypeMeta.APIVersion = "v1"
sts.TypeMeta.Kind = "StatefulSet" sts.TypeMeta.Kind = "StatefulSet"
return r.marshalObject(sts) return r.marshalObject(sts)
} }
@ -76,6 +69,7 @@ func (*StatefulSet) Header(ns string) Row {
if ns == AllNamespaces { if ns == AllNamespaces {
hh = append(hh, "NAMESPACE") hh = append(hh, "NAMESPACE")
} }
return append(hh, "NAME", "DESIRED", "CURRENT", "AGE") return append(hh, "NAME", "DESIRED", "CURRENT", "AGE")
} }
@ -94,8 +88,3 @@ func (r *StatefulSet) Fields(ns string) Row {
toAge(i.ObjectMeta.CreationTimestamp), toAge(i.ObjectMeta.CreationTimestamp),
) )
} }
// ExtFields returns extended fields in relation to headers.
func (*StatefulSet) ExtFields() Properties {
return Properties{}
}

View File

@ -75,7 +75,6 @@ func TestSTSListData(t *testing.T) {
td := l.Data() td := l.Data()
assert.Equal(t, 1, len(td.Rows)) assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, "blee", l.GetNamespace()) assert.Equal(t, "blee", l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"] row := td.Rows["blee/fred"]
assert.Equal(t, 4, len(row.Deltas)) assert.Equal(t, 4, len(row.Deltas))
for _, d := range row.Deltas { for _, d := range row.Deltas {
@ -84,19 +83,6 @@ func TestSTSListData(t *testing.T) {
assert.Equal(t, resource.Row{"fred"}, row.Fields[:1]) assert.Equal(t, resource.Row{"fred"}, row.Fields[:1])
} }
func TestSTSListDescribe(t *testing.T) {
setup(t)
ca := NewMockCaller()
m.When(ca.Get("blee", "fred")).ThenReturn(k8sSTS(), nil)
l := resource.NewStatefulSetListWithArgs("blee", resource.NewStatefulSetWithArgs(ca))
props, err := l.Describe("blee/fred")
ca.VerifyWasCalledOnce().Get("blee", "fred")
assert.Nil(t, err)
assert.Equal(t, 0, len(props))
}
// Helpers... // Helpers...
func k8sSTS() *v1.StatefulSet { func k8sSTS() *v1.StatefulSet {

View File

@ -19,52 +19,44 @@ type Service struct {
} }
// NewServiceList returns a new resource list. // NewServiceList returns a new resource list.
func NewServiceList(ns string) List { func NewServiceList(c k8s.Connection, ns string) List {
return NewServiceListWithArgs(ns, NewService()) return newList(
ns,
"svc",
NewService(c),
AllVerbsAccess|DescribeAccess,
)
} }
// NewServiceListWithArgs returns a new resource list. // NewService instantiates a new Service.
func NewServiceListWithArgs(ns string, res Resource) List { func NewService(c k8s.Connection) *Service {
return newList(ns, "svc", res, AllVerbsAccess|DescribeAccess) s := &Service{&Base{connection: c, resource: k8s.NewService(c)}, nil}
s.Factory = s
return s
} }
// NewService instantiates a new Endpoint. // New builds a new Service instance from a k8s resource.
func NewService() *Service { func (r *Service) New(i interface{}) Columnar {
return NewServiceWithArgs(k8s.NewService()) c := NewService(r.connection)
} switch instance := i.(type) {
// NewServiceWithArgs instantiates a new Endpoint.
func NewServiceWithArgs(r k8s.Res) *Service {
ep := &Service{
Base: &Base{
caller: r,
},
}
ep.creator = ep
return ep
}
// NewInstance builds a new Endpoint instance from a k8s resource.
func (*Service) NewInstance(i interface{}) Columnar {
cm := NewService()
switch i.(type) {
case *v1.Service: case *v1.Service:
cm.instance = i.(*v1.Service) c.instance = instance
case v1.Service: case v1.Service:
ii := i.(v1.Service) c.instance = &instance
cm.instance = &ii
default: default:
log.Fatal().Msgf("Unknown %#v", i) log.Fatal().Msgf("unknown Service type %#v", i)
} }
cm.path = cm.namespacedName(cm.instance.ObjectMeta) c.path = c.namespacedName(c.instance.ObjectMeta)
return cm
return c
} }
// Marshal resource to yaml. // Marshal resource to yaml.
// BOZO!! Why you need to fill type info?? // BOZO!! Why you need to fill type info??
func (r *Service) Marshal(path string) (string, error) { func (r *Service) Marshal(path string) (string, error) {
ns, n := namespaced(path) ns, n := namespaced(path)
i, err := r.caller.Get(ns, n) i, err := r.resource.Get(ns, n)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -72,6 +64,7 @@ func (r *Service) Marshal(path string) (string, error) {
svc := i.(*v1.Service) svc := i.(*v1.Service)
svc.TypeMeta.APIVersion = "v1" svc.TypeMeta.APIVersion = "v1"
svc.TypeMeta.Kind = "Service" svc.TypeMeta.Kind = "Service"
return r.marshalObject(svc) return r.marshalObject(svc)
} }
@ -81,6 +74,7 @@ func (*Service) Header(ns string) Row {
if ns == AllNamespaces { if ns == AllNamespaces {
hh = append(hh, "NAMESPACE") hh = append(hh, "NAMESPACE")
} }
return append(hh, return append(hh,
"NAME", "NAME",
"TYPE", "TYPE",
@ -110,11 +104,7 @@ func (r *Service) Fields(ns string) Row {
) )
} }
// ExtFields returns extended fields in relation to headers. // ----------------------------------------------------------------------------
func (r *Service) ExtFields() Properties {
return Properties{}
}
// Helpers... // Helpers...
func getSvcExtIPS(svc *v1.Service) []string { func getSvcExtIPS(svc *v1.Service) []string {
@ -139,6 +129,7 @@ func getSvcExtIPS(svc *v1.Service) []string {
case v1.ServiceTypeExternalName: case v1.ServiceTypeExternalName:
results = append(results, svc.Spec.ExternalName) results = append(results, svc.Spec.ExternalName)
} }
return results return results
} }
@ -152,6 +143,7 @@ func lbIngressIP(s v1.LoadBalancerStatus) string {
result = append(result, ingress[i].Hostname) result = append(result, ingress[i].Hostname)
} }
} }
return strings.Join(result, ",") return strings.Join(result, ",")
} }
@ -163,6 +155,7 @@ func (*Service) toIPs(svcType v1.ServiceType, ips []string) string {
return MissingValue return MissingValue
} }
sort.Strings(ips) sort.Strings(ips)
return strings.Join(ips, ",") return strings.Join(ips, ",")
} }
@ -179,5 +172,6 @@ func (*Service) toPorts(pp []v1.ServicePort) string {
ports[i] += "" + string(p.Protocol) ports[i] += "" + string(p.Protocol)
} }
} }
return strings.Join(ports, " ") return strings.Join(ports, " ")
} }

View File

@ -86,7 +86,6 @@ func TestSVCListData(t *testing.T) {
td := l.Data() td := l.Data()
assert.Equal(t, 1, len(td.Rows)) assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, "blee", l.GetNamespace()) assert.Equal(t, "blee", l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"] row := td.Rows["blee/fred"]
assert.Equal(t, 6, len(row.Deltas)) assert.Equal(t, 6, len(row.Deltas))
for _, d := range row.Deltas { for _, d := range row.Deltas {
@ -95,19 +94,6 @@ func TestSVCListData(t *testing.T) {
assert.Equal(t, resource.Row{"fred"}, row.Fields[:1]) assert.Equal(t, resource.Row{"fred"}, row.Fields[:1])
} }
func TestSVCListDescribe(t *testing.T) {
setup(t)
ca := NewMockCaller()
m.When(ca.Get("blee", "fred")).ThenReturn(k8sSVC(), nil)
l := resource.NewServiceListWithArgs("blee", resource.NewServiceWithArgs(ca))
props, err := l.Describe("blee/fred")
ca.VerifyWasCalledOnce().Get("blee", "fred")
assert.Nil(t, err)
assert.Equal(t, 0, len(props))
}
// Helpers... // Helpers...
func k8sSVC() *v1.Service { func k8sSVC() *v1.Service {

View File

@ -35,7 +35,7 @@ func newAliasView(app *appView) *aliasView {
v.actions[tcell.KeyEscape] = newKeyAction("Reset", v.resetCmd, false) v.actions[tcell.KeyEscape] = newKeyAction("Reset", v.resetCmd, false)
v.actions[KeySlash] = newKeyAction("Filter", v.activateCmd, false) v.actions[KeySlash] = newKeyAction("Filter", v.activateCmd, false)
v.actions[KeyShiftR] = newKeyAction("Sort Resources", v.sortResourceCmd, true) v.actions[KeyShiftR] = newKeyAction("Sort Resources", v.sortResourceCmd, true)
v.actions[KeyShiftG] = newKeyAction("Sort Groups", v.sortGroupCmd, true) v.actions[KeyShiftO] = newKeyAction("Sort Groups", v.sortGroupCmd, true)
ctx, cancel := context.WithCancel(context.TODO()) ctx, cancel := context.WithCancel(context.TODO())
v.cancel = cancel v.cancel = cancel
@ -128,7 +128,7 @@ func (v *aliasView) hints() hints {
} }
func (v *aliasView) hydrate() resource.TableData { func (v *aliasView) hydrate() resource.TableData {
cmds := helpCmds() cmds := helpCmds(v.app.conn())
data := resource.TableData{ data := resource.TableData{
Header: resource.Row{"NAME", "RESOURCE", "APIGROUP"}, Header: resource.Row{"NAME", "RESOURCE", "APIGROUP"},

View File

@ -6,6 +6,7 @@ import (
"time" "time"
"github.com/derailed/k9s/internal/config" "github.com/derailed/k9s/internal/config"
"github.com/derailed/k9s/internal/k8s"
"github.com/derailed/tview" "github.com/derailed/tview"
"github.com/gdamore/tcell" "github.com/gdamore/tcell"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
@ -34,7 +35,9 @@ type (
appView struct { appView struct {
*tview.Application *tview.Application
config *config.Config
version string version string
flags *genericclioptions.ConfigFlags
pages *tview.Pages pages *tview.Pages
content *tview.Pages content *tview.Pages
flashView *flashView flashView *flashView
@ -58,8 +61,8 @@ func init() {
} }
// NewApp returns a K9s app instance. // NewApp returns a K9s app instance.
func NewApp() *appView { func NewApp(cfg *config.Config) *appView {
v := appView{Application: tview.NewApplication()} v := appView{Application: tview.NewApplication(), config: cfg}
{ {
v.pages = tview.NewPages() v.pages = tview.NewPages()
v.actions = make(keyActions) v.actions = make(keyActions)
@ -92,6 +95,7 @@ func NewApp() *appView {
func (a *appView) Init(v string, rate int, flags *genericclioptions.ConfigFlags) { func (a *appView) Init(v string, rate int, flags *genericclioptions.ConfigFlags) {
a.version = v a.version = v
a.flags = flags
a.clusterInfoView.init() a.clusterInfoView.init()
a.cmdBuff.addListener(a.cmdView) a.cmdBuff.addListener(a.cmdView)
@ -118,8 +122,18 @@ func (a *appView) Init(v string, rate int, flags *genericclioptions.ConfigFlags)
a.SetRoot(a.pages, true) a.SetRoot(a.pages, true)
} }
func (a *appView) conn() k8s.Connection {
return a.config.GetConnection()
}
// Run starts the application loop // Run starts the application loop
func (a *appView) Run() { func (a *appView) Run() {
defer func() {
if err := recover(); err != nil {
log.Error().Msgf("%#v", err)
}
}()
go func() { go func() {
<-time.After(splashTime * time.Second) <-time.After(splashTime * time.Second)
a.showPage("main") a.showPage("main")
@ -256,7 +270,7 @@ func (a *appView) inject(p igniter) {
var ctx context.Context var ctx context.Context
{ {
ctx, a.cancel = context.WithCancel(context.TODO()) ctx, a.cancel = context.WithCancel(context.TODO())
p.init(ctx, config.Root.ActiveNamespace()) p.init(ctx, a.config.ActiveNamespace())
} }
a.content.AddPage("main", p, true, true) a.content.AddPage("main", p, true, true)

View File

@ -10,34 +10,37 @@ import (
type clusterInfoView struct { type clusterInfoView struct {
*tview.Table *tview.Table
app *appView app *appView
cluster *resource.Cluster
} }
func newInfoView(app *appView) *clusterInfoView { func newInfoView(app *appView) *clusterInfoView {
return &clusterInfoView{app: app, Table: tview.NewTable()} return &clusterInfoView{
app: app,
Table: tview.NewTable(),
cluster: resource.NewCluster(app.conn(), &log.Logger),
}
} }
func (v *clusterInfoView) init() { func (v *clusterInfoView) init() {
cluster := resource.NewCluster()
var row int var row int
v.SetCell(row, 0, v.sectionCell("Context")) v.SetCell(row, 0, v.sectionCell("Context"))
v.SetCell(row, 1, v.infoCell(cluster.ContextName())) v.SetCell(row, 1, v.infoCell(v.cluster.ContextName()))
row++ row++
v.SetCell(row, 0, v.sectionCell("Cluster")) v.SetCell(row, 0, v.sectionCell("Cluster"))
v.SetCell(row, 1, v.infoCell(cluster.ClusterName())) v.SetCell(row, 1, v.infoCell(v.cluster.ClusterName()))
row++ row++
v.SetCell(row, 0, v.sectionCell("User")) v.SetCell(row, 0, v.sectionCell("User"))
v.SetCell(row, 1, v.infoCell(cluster.UserName())) v.SetCell(row, 1, v.infoCell(v.cluster.UserName()))
row++ row++
v.SetCell(row, 0, v.sectionCell("K9s Rev")) v.SetCell(row, 0, v.sectionCell("K9s Rev"))
v.SetCell(row, 1, v.infoCell(v.app.version)) v.SetCell(row, 1, v.infoCell(v.app.version))
row++ row++
rev := cluster.Version() rev := v.cluster.Version()
v.SetCell(row, 0, v.sectionCell("K8s Rev")) v.SetCell(row, 0, v.sectionCell("K8s Rev"))
v.SetCell(row, 1, v.infoCell(rev)) v.SetCell(row, 1, v.infoCell(rev))
row++ row++
@ -67,24 +70,30 @@ func (*clusterInfoView) infoCell(t string) *tview.TableCell {
func (v *clusterInfoView) refresh() { func (v *clusterInfoView) refresh() {
var row int var row int
cluster := resource.NewCluster() v.GetCell(row, 1).SetText(v.cluster.ContextName())
v.GetCell(row, 1).SetText(cluster.ContextName())
row++ row++
v.GetCell(row, 1).SetText(cluster.ClusterName()) v.GetCell(row, 1).SetText(v.cluster.ClusterName())
row++ row++
v.GetCell(row, 1).SetText(cluster.UserName()) v.GetCell(row, 1).SetText(v.cluster.UserName())
row += 2 row += 2
v.GetCell(row, 1).SetText(cluster.Version()) v.GetCell(row, 1).SetText(v.cluster.Version())
row++ row++
mx, err := cluster.Metrics() nodes, err := v.cluster.GetNodes()
if err != nil { if err != nil {
log.Warn().Msgf("%s", err) log.Warn().Msgf("ClusterInfo %s", err)
return return
} }
mxNodes, err := v.cluster.GetNodesMetrics()
if err != nil {
log.Warn().Msgf("ClusterInfo %s", err)
return
}
mx := v.cluster.Metrics(nodes, mxNodes)
c := v.GetCell(row, 1) c := v.GetCell(row, 1)
c.SetText(deltas(c.Text, mx.CPU)) c.SetText(deltas(c.Text, toPerc(mx.PercCPU)))
row++ row++
c = v.GetCell(row, 1) c = v.GetCell(row, 1)
c.SetText(deltas(c.Text, mx.Mem)) c.SetText(deltas(c.Text, toPerc(mx.PercMEM)))
} }

View File

@ -3,8 +3,8 @@ package views
import ( import (
"fmt" "fmt"
"github.com/derailed/k9s/internal/config"
"github.com/derailed/k9s/internal/resource" "github.com/derailed/k9s/internal/resource"
"github.com/rs/zerolog/log"
) )
type command struct { type command struct {
@ -29,14 +29,20 @@ func (c *command) previousCmd() (string, bool) {
// DefaultCmd reset default command ie show pods. // DefaultCmd reset default command ie show pods.
func (c *command) defaultCmd() { func (c *command) defaultCmd() {
c.pushCmd(config.Root.ActiveView()) c.pushCmd(c.app.config.ActiveView())
c.run(config.Root.ActiveView()) c.run(c.app.config.ActiveView())
} }
// Helpers... // Helpers...
// Exec the command by showing associated display. // Exec the command by showing associated display.
func (c *command) run(cmd string) bool { func (c *command) run(cmd string) bool {
defer func() {
if err := recover(); err != nil {
log.Debug().Msgf("Command failed %v", err)
}
}()
var v igniter var v igniter
switch cmd { switch cmd {
case "q", "quit": case "q", "quit":
@ -47,14 +53,14 @@ func (c *command) run(cmd string) bool {
return true return true
default: default:
if res, ok := resourceViews()[cmd]; ok { if res, ok := resourceViews()[cmd]; ok {
v = res.viewFn(res.title, c.app, res.listFn(resource.DefaultNamespace), res.colorerFn) v = res.viewFn(res.title, c.app, res.listFn(c.app.conn(), resource.DefaultNamespace), res.colorerFn)
c.app.flash(flashInfo, fmt.Sprintf("Viewing %s in namespace %s...", res.title, config.Root.ActiveNamespace())) c.app.flash(flashInfo, fmt.Sprintf("Viewing %s in namespace %s...", res.title, c.app.config.ActiveNamespace()))
c.exec(cmd, v) c.exec(cmd, v)
return true return true
} }
} }
res, ok := allCRDs()[cmd] res, ok := allCRDs(c.app.conn())[cmd]
if !ok { if !ok {
c.app.flash(flashWarn, fmt.Sprintf("Huh? `%s` command not found", cmd)) c.app.flash(flashWarn, fmt.Sprintf("Huh? `%s` command not found", cmd))
return false return false
@ -67,7 +73,7 @@ func (c *command) run(cmd string) bool {
v = newResourceView( v = newResourceView(
res.Kind, res.Kind,
c.app, c.app,
resource.NewCustomList("", res.Group, res.Version, n), resource.NewCustomList(c.app.conn(), "", res.Group, res.Version, n),
defaultColorer, defaultColorer,
) )
c.exec(cmd, v) c.exec(cmd, v)
@ -76,8 +82,8 @@ func (c *command) run(cmd string) bool {
func (c *command) exec(cmd string, v igniter) { func (c *command) exec(cmd string, v igniter) {
if v != nil { if v != nil {
config.Root.SetActiveView(cmd) c.app.config.SetActiveView(cmd)
config.Root.Save() c.app.config.Save()
c.app.inject(v) c.app.inject(v)
} }
} }

View File

@ -3,7 +3,6 @@ package views
import ( import (
"strings" "strings"
"github.com/derailed/k9s/internal/config"
"github.com/derailed/k9s/internal/resource" "github.com/derailed/k9s/internal/resource"
"github.com/gdamore/tcell" "github.com/gdamore/tcell"
) )
@ -57,8 +56,8 @@ func (v *contextView) useContext(name string) error {
return err return err
} }
config.Root.Reset() v.app.config.Reset()
config.Root.Save() v.app.config.Save()
v.app.flash(flashInfo, "Switching context to", ctx) v.app.flash(flashInfo, "Switching context to", ctx)
v.refresh() v.refresh()
if tv, ok := v.GetPrimitive("ctx").(*tableView); ok { if tv, ok := v.GetPrimitive("ctx").(*tableView); ok {

View File

@ -40,7 +40,7 @@ func newFlashView(app *tview.Application, m string) *flashView {
f.SetTextColor(tcell.ColorAqua) f.SetTextColor(tcell.ColorAqua)
f.SetTextAlign(tview.AlignLeft) f.SetTextAlign(tview.AlignLeft)
f.SetBorderPadding(0, 0, 1, 1) f.SetBorderPadding(0, 0, 1, 1)
f.SetText(m) f.SetText("")
} }
return &f return &f
} }

View File

@ -1,10 +1,15 @@
package views package views
import ( import (
"fmt"
"strconv" "strconv"
"strings" "strings"
) )
func toPerc(f float64) string {
return fmt.Sprintf("%.0f%%", f)
}
func deltas(c, n string) string { func deltas(c, n string) string {
if c == "n/a" { if c == "n/a" {
return n return n

View File

@ -4,7 +4,6 @@ import (
"fmt" "fmt"
"io" "io"
"github.com/derailed/k9s/internal/config"
"github.com/derailed/tview" "github.com/derailed/tview"
) )
@ -21,7 +20,7 @@ func newLogView(title string, parent loggable) *logView {
v.SetDynamicColors(true) v.SetDynamicColors(true)
v.SetWrap(true) v.SetWrap(true)
v.setTitle(parent.getSelection()) v.setTitle(parent.getSelection())
v.SetMaxBuffer(config.Root.K9s.LogBufferSize) v.SetMaxBuffer(parent.appView().config.K9s.LogBufferSize)
} }
v.ansiWriter = tview.ANSIWriter(v) v.ansiWriter = tview.ANSIWriter(v)
return &v return &v

View File

@ -6,7 +6,6 @@ import (
"strconv" "strconv"
"time" "time"
"github.com/derailed/k9s/internal/config"
"github.com/derailed/k9s/internal/resource" "github.com/derailed/k9s/internal/resource"
"github.com/derailed/tview" "github.com/derailed/tview"
"github.com/gdamore/tcell" "github.com/gdamore/tcell"
@ -163,7 +162,7 @@ func (v *logsView) doLoad(path, co string) error {
if !ok { if !ok {
return fmt.Errorf("Resource %T is not tailable", v.parent.getList().Resource) return fmt.Errorf("Resource %T is not tailable", v.parent.getList().Resource)
} }
maxBuff := int64(config.Root.K9s.LogRequestSize) maxBuff := int64(v.parent.appView().config.K9s.LogRequestSize)
cancelFn, err := res.Logs(c, ns, po, co, maxBuff, false) cancelFn, err := res.Logs(c, ns, po, co, maxBuff, false)
if err != nil { if err != nil {
cancelFn() cancelFn()

View File

@ -8,6 +8,7 @@ import (
"github.com/derailed/k9s/internal/k8s" "github.com/derailed/k9s/internal/k8s"
"github.com/derailed/k9s/internal/resource" "github.com/derailed/k9s/internal/resource"
"github.com/gdamore/tcell" "github.com/gdamore/tcell"
"github.com/rs/zerolog/log"
) )
const ( const (
@ -55,12 +56,12 @@ func (v *namespaceView) useNsCmd(evt *tcell.EventKey) *tcell.EventKey {
} }
func (v *namespaceView) useNamespace(name string) { func (v *namespaceView) useNamespace(name string) {
if err := config.Root.SetActiveNamespace(name); err != nil { if err := v.app.config.SetActiveNamespace(name); err != nil {
v.app.flash(flashErr, err.Error()) v.app.flash(flashErr, err.Error())
} else { } else {
v.app.flash(flashInfo, fmt.Sprintf("Namespace %s is now active!", name)) v.app.flash(flashInfo, fmt.Sprintf("Namespace %s is now active!", name))
} }
config.Root.Save() v.app.config.Save()
} }
func (v *namespaceView) getSelectedItem() string { func (v *namespaceView) getSelectedItem() string {
@ -73,7 +74,7 @@ func (*namespaceView) cleanser(s string) string {
func (v *namespaceView) decorate(data resource.TableData) resource.TableData { func (v *namespaceView) decorate(data resource.TableData) resource.TableData {
if _, ok := data.Rows[resource.AllNamespaces]; !ok { if _, ok := data.Rows[resource.AllNamespaces]; !ok {
if k8s.CanIAccess("", "list", "namespaces", "namespace.v1") { if k8s.CanIAccess(v.app.conn().Config(), log.Logger, "", "list", "namespaces", "namespace.v1") {
data.Rows[resource.AllNamespace] = &resource.RowEvent{ data.Rows[resource.AllNamespace] = &resource.RowEvent{
Action: resource.Unchanged, Action: resource.Unchanged,
Fields: resource.Row{resource.AllNamespace, "Active", "0"}, Fields: resource.Row{resource.AllNamespace, "Active", "0"},
@ -81,14 +82,14 @@ func (v *namespaceView) decorate(data resource.TableData) resource.TableData {
} }
} }
} }
for k, v := range data.Rows { for k, r := range data.Rows {
if config.InList(config.Root.FavNamespaces(), k) { if config.InList(v.app.config.FavNamespaces(), k) {
v.Fields[0] += "+" r.Fields[0] += "+"
v.Action = resource.Unchanged r.Action = resource.Unchanged
} }
if config.Root.ActiveNamespace() == k { if v.app.config.ActiveNamespace() == k {
v.Fields[0] += "(*)" r.Fields[0] += "(*)"
v.Action = resource.Unchanged r.Action = resource.Unchanged
} }
} }
return data return data

35
internal/views/no.go Normal file
View File

@ -0,0 +1,35 @@
package views
import (
"github.com/derailed/k9s/internal/resource"
"github.com/gdamore/tcell"
)
type nodeView struct {
*resourceView
}
func newNodeView(t string, app *appView, list resource.List, c colorerFn) resourceViewer {
v := nodeView{newResourceView(t, app, list, c).(*resourceView)}
{
v.extraActionsFn = v.extraActions
v.switchPage("no")
}
return &v
}
func (v *nodeView) extraActions(aa keyActions) {
aa[KeyShiftC] = newKeyAction("Sort CPU", v.sortColCmd(7, false), true)
aa[KeyShiftM] = newKeyAction("Sort MEM", v.sortColCmd(8, false), true)
}
func (v *nodeView) sortColCmd(col int, asc bool) func(evt *tcell.EventKey) *tcell.EventKey {
return func(evt *tcell.EventKey) *tcell.EventKey {
t := v.getTV()
t.sortCol.index, t.sortCol.asc = t.nameColIndex()+col, asc
t.refresh()
return nil
}
}

View File

@ -3,7 +3,6 @@ package views
import ( import (
"fmt" "fmt"
"github.com/derailed/k9s/internal/config"
"github.com/derailed/k9s/internal/resource" "github.com/derailed/k9s/internal/resource"
"github.com/gdamore/tcell" "github.com/gdamore/tcell"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
@ -113,7 +112,7 @@ func (v *podView) shellIn(path, co string) {
ns, po := namespaced(path) ns, po := namespaced(path)
args := make([]string, 0, 12) args := make([]string, 0, 12)
args = append(args, "exec", "-it") args = append(args, "exec", "-it")
args = append(args, "--context", config.Root.K9s.CurrentContext) args = append(args, "--context", v.app.config.K9s.CurrentContext)
args = append(args, "-n", ns) args = append(args, "-n", ns)
args = append(args, po) args = append(args, po)
if len(co) != 0 { if len(co) != 0 {
@ -129,7 +128,7 @@ func (v *podView) showLogs(path, co string, previous bool) {
args := make([]string, 0, 10) args := make([]string, 0, 10)
args = append(args, "logs", "-f") args = append(args, "logs", "-f")
args = append(args, "-n", ns) args = append(args, "-n", ns)
args = append(args, "--context", config.Root.K9s.CurrentContext) args = append(args, "--context", v.app.config.K9s.CurrentContext)
if len(co) != 0 { if len(co) != 0 {
args = append(args, "-c", co) args = append(args, "-c", co)
v.app.flash(flashInfo, fmt.Sprintf("Viewing logs from container %s on pod %s", co, po)) v.app.flash(flashInfo, fmt.Sprintf("Viewing logs from container %s on pod %s", co, po))

View File

@ -7,9 +7,9 @@ import (
) )
type ( type (
viewFn func(string, *appView, resource.List, colorerFn) resourceViewer viewFn func(ns string, app *appView, list resource.List, colorer colorerFn) resourceViewer
listFn func(string) resource.List listFn func(c k8s.Connection, ns string) resource.List
colorerFn func(string, *resource.RowEvent) tcell.Color colorerFn func(ns string, evt *resource.RowEvent) tcell.Color
resCmd struct { resCmd struct {
title string title string
@ -20,49 +20,50 @@ type (
} }
) )
func helpCmds() map[string]resCmd { func helpCmds(c k8s.Connection) map[string]resCmd {
cmdMap := resourceViews() cmdMap := resourceViews()
cmds := make(map[string]resCmd, len(cmdMap)) cmds := make(map[string]resCmd, len(cmdMap))
for k, v := range cmdMap { for k, v := range cmdMap {
cmds[k] = v cmds[k] = v
} }
for k, v := range allCRDs() { for k, v := range allCRDs(c) {
cmds[k] = resCmd{title: v.Kind, api: v.Group} cmds[k] = resCmd{title: v.Kind, api: v.Group}
} }
return cmds return cmds
} }
func allCRDs() map[string]k8s.APIGroup { func allCRDs(c k8s.Connection) map[string]k8s.APIGroup {
m := map[string]k8s.APIGroup{} m := map[string]k8s.APIGroup{}
list := resource.NewCRDList(resource.AllNamespaces)
ll, _ := list.Resource().List(resource.AllNamespaces) crds, _ := resource.
for _, l := range ll { NewCRDList(c, resource.AllNamespaces).
ff := l.ExtFields() Resource().
List(resource.AllNamespaces)
for _, crd := range crds {
ff := crd.ExtFields()
grp := k8s.APIGroup{ grp := k8s.APIGroup{
Version: ff["version"].(string),
Group: ff["group"].(string), Group: ff["group"].(string),
Kind: ff["kind"].(string), Kind: ff["kind"].(string),
Version: ff["version"].(string),
} }
if p, ok := ff["plural"].(string); ok {
grp.Plural = p
m[p] = grp
}
if s, ok := ff["singular"].(string); ok {
grp.Singular = s
m[s] = grp
}
if aa, ok := ff["aliases"].([]interface{}); ok { if aa, ok := ff["aliases"].([]interface{}); ok {
if n, ok := ff["plural"].(string); ok {
grp.Plural = n
}
if n, ok := ff["singular"].(string); ok {
grp.Singular = n
}
for _, a := range aa { for _, a := range aa {
m[a.(string)] = grp m[a.(string)] = grp
} }
} else if s, ok := ff["singular"].(string); ok {
grp.Singular = s
if p, ok := ff["plural"].(string); ok {
grp.Plural = p
}
m[s] = grp
} else if s, ok := ff["plural"].(string); ok {
grp.Plural = s
m[s] = grp
} }
} }
@ -165,7 +166,7 @@ func resourceViews() map[string]resCmd {
"no": { "no": {
title: "Nodes", title: "Nodes",
api: "", api: "",
viewFn: newResourceView, viewFn: newNodeView,
listFn: resource.NewNodeList, listFn: resource.NewNodeList,
colorerFn: nsColorer, colorerFn: nsColorer,
}, },
@ -177,7 +178,7 @@ func resourceViews() map[string]resCmd {
colorerFn: nsColorer, colorerFn: nsColorer,
}, },
"pdb": { "pdb": {
title: "PodDiscruptionBudgets", title: "PodDisruptionBudgets",
api: "v1.beta1", api: "v1.beta1",
viewFn: newResourceView, viewFn: newResourceView,
listFn: resource.NewPDBList, listFn: resource.NewPDBList,

View File

@ -88,7 +88,7 @@ func (v *resourceView) init(ctx context.Context, ns string) {
return return
case <-time.After(time.Duration(initTick) * time.Second): case <-time.After(time.Duration(initTick) * time.Second):
v.refresh() v.refresh()
initTick = float64(config.Root.K9s.RefreshRate) initTick = float64(v.app.config.K9s.RefreshRate)
} }
} }
}(ctx) }(ctx)
@ -170,10 +170,10 @@ func (v *resourceView) describeCmd(evt *tcell.EventKey) *tcell.EventKey {
return evt return evt
} }
sel := v.getSelectedItem() sel := v.getSelectedItem()
raw, err := v.list.Resource().Describe(v.title, sel) raw, err := v.list.Resource().Describe(v.title, sel, v.app.flags)
if err != nil { if err != nil {
v.app.flash(flashErr, err.Error()) v.app.flash(flashErr, err.Error())
log.Warn().Msg(err.Error()) log.Warn().Msgf("Describe %v", err.Error())
return evt return evt
} }
details := v.GetPrimitive("details").(*detailsView) details := v.GetPrimitive("details").(*detailsView)
@ -220,7 +220,7 @@ func (v *resourceView) editCmd(evt *tcell.EventKey) *tcell.EventKey {
args = append(args, "edit") args = append(args, "edit")
args = append(args, v.list.GetName()) args = append(args, v.list.GetName())
args = append(args, "-n", ns) args = append(args, "-n", ns)
args = append(args, "--context", config.Root.K9s.CurrentContext) args = append(args, "--context", v.app.config.K9s.CurrentContext)
args = append(args, po) args = append(args, po)
runK(v.app, args...) runK(v.app, args...)
return evt return evt
@ -249,8 +249,8 @@ func (v *resourceView) doSwitchNamespace(ns string) {
v.getTV().resetTitle() v.getTV().resetTitle()
v.getTV().Select(0, 0) v.getTV().Select(0, 0)
v.app.cmdBuff.reset() v.app.cmdBuff.reset()
config.Root.SetActiveNamespace(v.selectedNS) v.app.config.SetActiveNamespace(v.selectedNS)
config.Root.Save() v.app.config.Save()
} }
func (v *resourceView) refresh() { func (v *resourceView) refresh() {
@ -264,7 +264,7 @@ func (v *resourceView) refresh() {
v.list.SetNamespace(v.selectedNS) v.list.SetNamespace(v.selectedNS)
} }
if err := v.list.Reconcile(); err != nil { if err := v.list.Reconcile(); err != nil {
log.Warn().Msgf("%s", err) log.Warn().Msgf("Reconcile %v", err)
v.app.flash(flashErr, err.Error()) v.app.flash(flashErr, err.Error())
} }
data := v.list.Data() data := v.list.Data()
@ -338,11 +338,11 @@ func (v *resourceView) refreshActions() {
var nn []interface{} var nn []interface{}
aa := make(keyActions) aa := make(keyActions)
if k8s.CanIAccess("", "list", "namespaces", "namespace.v1") { if k8s.CanIAccess(v.app.conn().Config(), log.Logger, "", "list", "namespaces", "namespace.v1") {
var err error var err error
nn, err = k8s.NewNamespace().List(resource.AllNamespaces) nn, err = k8s.NewNamespace(v.app.conn()).List(resource.AllNamespaces)
if err != nil { if err != nil {
log.Warn().Msgf("%s", err) log.Warn().Msgf("Access %v", err)
v.app.flash(flashErr, err.Error()) v.app.flash(flashErr, err.Error())
} }
@ -354,7 +354,7 @@ func (v *resourceView) refreshActions() {
if v.list.Access(resource.NamespaceAccess) { if v.list.Access(resource.NamespaceAccess) {
v.namespaces = make(map[int]string, config.MaxFavoritesNS) v.namespaces = make(map[int]string, config.MaxFavoritesNS)
for i, n := range config.Root.FavNamespaces() { for i, n := range v.app.config.FavNamespaces() {
aa[tcell.Key(numKeys[i])] = newKeyAction(n, v.switchNamespaceCmd, true) aa[tcell.Key(numKeys[i])] = newKeyAction(n, v.switchNamespaceCmd, true)
v.namespaces[i] = n v.namespaces[i] = n
} }

View File

@ -283,7 +283,7 @@ func (v *tableView) displayCol(index int, name string) string {
func (v *tableView) doUpdate(data resource.TableData) { func (v *tableView) doUpdate(data resource.TableData) {
v.currentNS = data.Namespace v.currentNS = data.Namespace
if v.currentNS == resource.AllNamespaces { if v.currentNS == resource.AllNamespaces {
v.actions[KeyShiftG] = newKeyAction("Sort Namespace", v.sortNamespaceCmd, true) v.actions[KeyShiftS] = newKeyAction("Sort Namespace", v.sortNamespaceCmd, true)
} else { } else {
delete(v.actions, KeyShiftS) delete(v.actions, KeyShiftS)
} }
@ -308,9 +308,14 @@ func (v *tableView) doUpdate(data resource.TableData) {
} }
row++ row++
// for k := range data.Rows {
// log.Debug().Msgf("Keys: %s", k)
// }
keys := v.sortRows(data) keys := v.sortRows(data)
groupKeys := map[string][]string{} groupKeys := map[string][]string{}
for _, k := range keys { for _, k := range keys {
// log.Debug().Msgf("RKEY: %s", k)
grp := data.Rows[k].Fields[v.sortCol.index] grp := data.Rows[k].Fields[v.sortCol.index]
if s, ok := groupKeys[grp]; ok { if s, ok := groupKeys[grp]; ok {
s = append(s, k) s = append(s, k)