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()))
fmt.Printf(printer.Colorize("Boom!! ", printer.ColorRed))
fmt.Println(printer.Colorize(fmt.Sprintf("%v.", err), printer.ColorDarkGray))
// debug.PrintStack()
}
}()
zerolog.SetGlobalLevel(parseLevel(logLevel))
loadConfiguration()
app := views.NewApp()
cfg := loadConfiguration()
app := views.NewApp(cfg)
{
defer app.Stop()
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...")
// Load K9s config file...
cfg := k8s.NewConfig(k8sFlags)
config.Root = config.NewConfig(cfg)
if err := config.Root.Load(config.K9sConfigFile); err != nil {
k8sCfg := k8s.NewConfig(k8sFlags)
k9sCfg := config.NewConfig(k8sCfg)
if err := k9sCfg.Load(config.K9sConfigFile); err != nil {
log.Warn().Msg("Unable to locate K9s config. Generating new configuration...")
}
config.Root.K9s.RefreshRate = refreshRate
mergeConfigs()
// Init K8s connection...
k8s.InitConnectionOrDie(cfg)
k9sCfg.K9s.RefreshRate = refreshRate
k9sCfg.Refine(k8sFlags)
k9sCfg.SetConnection(k8s.InitConnectionOrDie(k8sCfg, log.Logger))
log.Info().Msg("✅ Kubernetes connectivity")
config.Root.Save()
}
k9sCfg.Save()
func mergeConfigs() {
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
}
return k9sCfg
}
func parseLevel(level string) zerolog.Level {
@ -251,7 +220,3 @@ func initK8sFlags() {
func clearScreen() {
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/derailed/tview v0.1.4
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/fatih/camelcase v1.0.0 // indirect
github.com/gdamore/tcell v1.1.1
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/gofuzz v0.0.0-20170612174753-24818f796faf // 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/reflect2 v1.0.1 // 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/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/sirupsen/logrus v1.4.0 // indirect
github.com/spf13/cobra v0.0.3
@ -35,9 +39,12 @@ require (
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.2.2
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/apiserver v0.0.0-20190322225753-5eae03fa38e7 // indirect
k8s.io/cli-runtime v0.0.0-20190207094101-a32b78e5dd0a
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/kube-openapi v0.0.0-20190215190454-ea82251f3668 // indirect
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/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/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/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
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/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/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/mock v1.1.1/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/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
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.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/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/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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
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/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
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/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
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=
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/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/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/go.mod h1:qWnH3/b8sp/l7EvlDh7ulDU3UWA4P4N1NFbEEP791tM=
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/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/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/kube-openapi v0.0.0-20190215190454-ea82251f3668 h1:M80qeWaBNOX2Uc4plRHcb6k+3YE5VWMaJXKZo+tX9aU=

View File

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

View File

@ -9,14 +9,15 @@ import (
"os"
"path/filepath"
"github.com/derailed/k9s/internal/k8s"
"github.com/derailed/k9s/internal/resource"
"github.com/rs/zerolog/log"
"gopkg.in/yaml.v2"
v1 "k8s.io/api/core/v1"
"k8s.io/cli-runtime/pkg/genericclioptions"
)
var (
// Root K9s configuration.
Root *Config
// K9sHome represent K9s home directory.
K9sHome = filepath.Join(mustK9sHome(), ".k9s")
// K9sConfigFile represents K9s config file location.
@ -31,12 +32,13 @@ type KubeSettings interface {
CurrentClusterName() (string, error)
CurrentNamespaceName() (string, error)
ClusterNames() ([]string, error)
NamespaceNames() ([]string, error)
NamespaceNames(nn []v1.Namespace) []string
}
// Config tracks K9s configuration options.
type Config struct {
K9s *K9s `yaml:"k9s"`
client k8s.Connection
settings KubeSettings
}
@ -45,6 +47,42 @@ func NewConfig(ks KubeSettings) *Config {
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.
// if it does not exist.
func (c *Config) Reset() {
@ -96,6 +134,16 @@ func (c *Config) SetActiveView(view string) {
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
func (c *Config) Load(path string) error {
f, err := ioutil.ReadFile(path)
@ -134,7 +182,7 @@ func (c *Config) SaveFile(path string) error {
// Validate the configuration.
func (c *Config) Validate() {
c.K9s.Validate(c.settings)
c.K9s.Validate(c.client, c.settings)
}
// Dump debug...

View File

@ -1,5 +1,7 @@
package config
import "github.com/derailed/k9s/internal/k8s"
const (
defaultRefreshRate = 2
defaultLogRequestSize = 200
@ -45,7 +47,7 @@ func (k *K9s) ActiveCluster() *Cluster {
}
// Validate the current configuration.
func (k *K9s) Validate(ks KubeSettings) {
func (k *K9s) Validate(c k8s.Connection, ks KubeSettings) {
if k.RefreshRate <= 0 {
k.RefreshRate = defaultRefreshRate
}
@ -87,5 +89,5 @@ func (k *K9s) Validate(ks KubeSettings) {
if _, ok := k.Clusters[k.CurrentCluster]; !ok {
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
import (
"github.com/derailed/k9s/internal/k8s"
"github.com/rs/zerolog/log"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
const (
@ -26,12 +28,13 @@ func NewNamespace() *Namespace {
}
// Validate a namespace is setup correctly
func (n *Namespace) Validate(ks KubeSettings) {
nn, err := ks.NamespaceNames()
func (n *Namespace) Validate(c k8s.Connection, ks KubeSettings) {
nns, err := c.DialOrDie().CoreV1().Namespaces().List(metav1.ListOptions{})
if err != nil {
return
}
nn := ks.NamespaceNames(nns.Items)
if !n.isAllNamespace() && !InList(nn, n.Active) {
log.Debug().Msg("[Config] Validation error active namespace resetting to `default")
n.Active = defaultNS

View File

@ -8,34 +8,50 @@ import (
"github.com/rs/zerolog/log"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/cli-runtime/pkg/genericclioptions"
"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"
versioned "k8s.io/kubernetes/pkg/kubectl/describe/versioned"
v "k8s.io/metrics/pkg/client/clientset/versioned"
)
type (
// Creator can create a new resources.
Creator interface {
NewInstance(interface{}) Columnar
// Cruder represent a crudable Kubernetes resource.
Cruder interface {
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.
Caller interface {
k8s.Res
// Connection represents a Kubenetes apiserver connection.
Connection interface {
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.
APIFn func() k8s.Res
// InstanceFn instantiates a concrete resource.
InstanceFn func(interface{}) Columnar
// Factory creates new tabular resources.
Factory interface {
New(interface{}) Columnar
}
// Base resource.
Base struct {
path string
Factory
caller Caller
creator Creator
connection Connection
path string
resource Cruder
}
)
@ -44,32 +60,39 @@ func (b *Base) Name() string {
return b.path
}
// ExtFields returns extended fields in relation to headers.
func (*Base) ExtFields() Properties {
return Properties{}
}
// Get a resource by name
func (b *Base) Get(path string) (Columnar, error) {
ns, n := namespaced(path)
i, err := b.caller.Get(ns, n)
i, err := b.resource.Get(ns, n)
if err != nil {
return nil, err
}
return b.creator.NewInstance(i), nil
return b.New(i), nil
}
// List all resources
func (b *Base) List(ns string) (Columnars, error) {
ii, err := b.caller.List(ns)
ii, err := b.resource.List(ns)
if err != nil {
return nil, err
}
cc := make(Columnars, 0, len(ii))
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
}
// 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)
mapping, err := k8s.RestMapping.Find(kind)
@ -77,20 +100,22 @@ func (b *Base) Describe(kind, pa string) (string, error) {
return "", err
}
d, err := versioned.Describer(k8s.KubeConfig.Flags(), mapping)
d, err := versioned.Describer(flags, mapping)
if err != nil {
return "", err
}
opts := describe.DescriberSettings{
ShowEvents: true,
}
return d.Describe(ns, n, opts)
}
// Delete a resource by name.
func (b *Base) Delete(path string) error {
ns, n := namespaced(path)
return b.caller.Delete(ns, n)
return b.resource.Delete(ns, n)
}
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)
return "", err
}
return buff.String(), nil
}

View File

@ -2,39 +2,52 @@ package resource
import (
"github.com/derailed/k9s/internal/k8s"
"github.com/rs/zerolog"
v1 "k8s.io/api/core/v1"
mv1beta1 "k8s.io/metrics/pkg/apis/metrics/v1beta1"
)
type (
// ClusterIfc represents a cluster.
ClusterIfc interface {
// ClusterMeta represents metadata about a Kubernetes cluster.
ClusterMeta interface {
Connection
Version() (string, error)
ContextName() string
ClusterName() string
UserName() string
}
// MetricsIfc represents a metrics server.
MetricsIfc interface {
NodeMetrics() (k8s.Metric, error)
PerNodeMetrics([]v1.Node) (map[string]k8s.Metric, error)
PodMetrics() (map[string]k8s.Metric, error)
// MetricsServer gather metrics information from pods and nodes.
MetricsServer interface {
MetricsService
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 struct {
api ClusterIfc
mx MetricsIfc
api ClusterMeta
mx MetricsServer
}
)
// NewCluster returns a new cluster info resource.
func NewCluster() *Cluster {
return NewClusterWithArgs(k8s.NewCluster(), k8s.NewMetricsServer())
func NewCluster(c Connection, log *zerolog.Logger) *Cluster {
return NewClusterWithArgs(k8s.NewCluster(c, log), k8s.NewMetricsServer(c))
}
// NewClusterWithArgs for tests only!
func NewClusterWithArgs(ci ClusterIfc, mx MetricsIfc) *Cluster {
func NewClusterWithArgs(ci ClusterMeta, mx MetricsServer) *Cluster {
return &Cluster{api: ci, mx: mx}
}
@ -44,6 +57,7 @@ func (c *Cluster) Version() string {
if err != nil {
return "n/a"
}
return info
}
@ -63,6 +77,25 @@ func (c *Cluster) UserName() string {
}
// Metrics gathers node level metrics and compute utilization percentages.
func (c *Cluster) Metrics() (k8s.Metric, error) {
return c.mx.NodeMetrics()
func (c *Cluster) Metrics(nodes []v1.Node, nmx []mv1beta1.NodeMetrics) k8s.ClusterMetrics {
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"
m "github.com/petergtz/pegomock"
"github.com/stretchr/testify/assert"
v1 "k8s.io/api/core/v1"
mv1beta1 "k8s.io/metrics/pkg/apis/metrics/v1beta1"
)
func TestClusterVersion(t *testing.T) {
setup(t)
cIfc, mxIfc := NewMockClusterIfc(), NewMockMetricsIfc()
cIfc, mxIfc := NewMockClusterMeta(), NewMockMetricsServer()
m.When(cIfc.Version()).ThenReturn("1.2.3", nil)
ci := resource.NewClusterWithArgs(cIfc, mxIfc)
@ -23,7 +25,7 @@ func TestClusterVersion(t *testing.T) {
func TestClusterNoVersion(t *testing.T) {
setup(t)
cIfc, mxIfc := NewMockClusterIfc(), NewMockMetricsIfc()
cIfc, mxIfc := NewMockClusterMeta(), NewMockMetricsServer()
m.When(cIfc.Version()).ThenReturn("bad", fmt.Errorf("No data"))
ci := resource.NewClusterWithArgs(cIfc, mxIfc)
@ -33,7 +35,7 @@ func TestClusterNoVersion(t *testing.T) {
func TestClusterName(t *testing.T) {
setup(t)
cIfc, mxIfc := NewMockClusterIfc(), NewMockMetricsIfc()
cIfc, mxIfc := NewMockClusterMeta(), NewMockMetricsServer()
m.When(cIfc.ClusterName()).ThenReturn("fred")
ci := resource.NewClusterWithArgs(cIfc, mxIfc)
@ -43,13 +45,11 @@ func TestClusterName(t *testing.T) {
func TestClusterMetrics(t *testing.T) {
setup(t)
cIfc, mxIfc := NewMockClusterIfc(), NewMockMetricsIfc()
m.When(mxIfc.NodeMetrics()).ThenReturn(testMetric(), nil)
cIfc, mxIfc := NewMockClusterMeta(), NewMockMetricsServer()
m.When(mxIfc.ClusterLoad([]v1.Node{}, []mv1beta1.NodeMetrics{})).ThenReturn(clusterMetric())
c := resource.NewClusterWithArgs(cIfc, mxIfc)
m, err := c.Metrics()
assert.Nil(t, err)
assert.Equal(t, testMetric(), m)
assert.Equal(t, clusterMetric(), c.Metrics([]v1.Node{}, []mv1beta1.NodeMetrics{}))
}
// Helpers...
@ -61,11 +61,9 @@ func setup(t *testing.T) {
})
}
func testMetric() k8s.Metric {
return k8s.Metric{
CPU: "100m",
AvailCPU: "1000m",
Mem: "256Gi",
AvailMem: "512Gi",
func clusterMetric() k8s.ClusterMetrics {
return k8s.ClusterMetrics{
PercCPU: 100,
PercMEM: 1000,
}
}

View File

@ -15,51 +15,43 @@ type ConfigMap struct {
}
// NewConfigMapList returns a new resource list.
func NewConfigMapList(ns string) List {
return NewConfigMapListWithArgs(ns, NewConfigMap())
}
// NewConfigMapListWithArgs returns a new resource list.
func NewConfigMapListWithArgs(ns string, res Resource) List {
return newList(ns, "cm", res, AllVerbsAccess|DescribeAccess)
func NewConfigMapList(c k8s.Connection, ns string) List {
return newList(
ns,
"cm",
NewConfigMap(c),
AllVerbsAccess|DescribeAccess,
)
}
// NewConfigMap instantiates a new ConfigMap.
func NewConfigMap() *ConfigMap {
return NewConfigMapWithArgs(k8s.NewConfigMap())
func NewConfigMap(c k8s.Connection) *ConfigMap {
m := &ConfigMap{&Base{connection: c, resource: k8s.NewConfigMap(c)}, nil}
m.Factory = m
return m
}
// NewConfigMapWithArgs instantiates a new ConfigMap.
func NewConfigMapWithArgs(r k8s.Res) *ConfigMap {
cm := &ConfigMap{
Base: &Base{
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) {
// New builds a new ConfigMap instance from a k8s resource.
func (r *ConfigMap) New(i interface{}) Columnar {
cm := NewConfigMap(r.connection)
switch instance := i.(type) {
case *v1.ConfigMap:
cm.instance = i.(*v1.ConfigMap)
cm.instance = instance
case v1.ConfigMap:
ii := i.(v1.ConfigMap)
cm.instance = &ii
cm.instance = &instance
default:
log.Fatalf("Unknown %#v", i)
}
cm.path = cm.namespacedName(cm.instance.ObjectMeta)
return cm
}
// Marshal resource to yaml.
func (r *ConfigMap) Marshal(path string) (string, error) {
ns, n := namespaced(path)
i, err := r.caller.Get(ns, n)
i, err := r.resource.Get(ns, n)
if err != nil {
return "", err
}
@ -67,6 +59,7 @@ func (r *ConfigMap) Marshal(path string) (string, error) {
cm := i.(*v1.ConfigMap)
cm.TypeMeta.APIVersion = "v1"
cm.TypeMeta.Kind = "ConfigMap"
return r.marshalObject(cm)
}
@ -76,6 +69,7 @@ func (*ConfigMap) Header(ns string) Row {
if ns == AllNamespaces {
hh = append(hh, "NAMESPACE")
}
return append(hh, "NAME", "DATA", "AGE")
}
@ -93,8 +87,3 @@ func (r *ConfigMap) Fields(ns string) Row {
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) {
setup(t)
ca := NewMockCaller()
conn := NewMockConnection()
ca := NewMockCruder()
m.When(ca.Get("blee", "fred")).ThenReturn(k8sCM(), nil)
cm := resource.NewConfigMapWithArgs(ca)
cm := resource.NewConfigMap(conn)
ma, err := cm.Get("blee/fred")
assert.Nil(t, err)
ca.VerifyWasCalledOnce().Get("blee", "fred")
assert.Equal(t, cm.NewInstance(k8sCM()), ma)
assert.Equal(t, cm.New(k8sCM()), ma)
}
func TestCMList(t *testing.T) {
setup(t)
ca := NewMockCaller()
conn := NewMockConnection()
ca := NewMockCruder()
m.When(ca.List("blee")).ThenReturn(k8s.Collection{*k8sCM()}, nil)
cm := resource.NewConfigMapWithArgs(ca)
cm := resource.NewConfigMap(conn)
ma, err := cm.List("blee")
assert.Nil(t, err)
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) {
setup(t)
ca := NewMockCaller()
conn := NewMockConnection()
ca := NewMockCruder()
m.When(ca.Delete("blee", "fred")).ThenReturn(nil)
cm := resource.NewConfigMapWithArgs(ca)
cm := resource.NewConfigMap(conn)
assert.Nil(t, cm.Delete("blee/fred"))
ca.VerifyWasCalledOnce().Delete("blee", "fred")
}
@ -78,10 +81,11 @@ func TestCMDelete(t *testing.T) {
func TestCMMarshal(t *testing.T) {
setup(t)
ca := NewMockCaller()
conn := NewMockConnection()
ca := NewMockCruder()
m.When(ca.Get("blee", "fred")).ThenReturn(k8sCM(), nil)
cm := resource.NewConfigMapWithArgs(ca)
cm := resource.NewConfigMap(conn)
ma, err := cm.Marshal("blee/fred")
ca.VerifyWasCalledOnce().Get("blee", "fred")
@ -92,48 +96,38 @@ func TestCMMarshal(t *testing.T) {
func TestCMListHasName(t *testing.T) {
setup(t)
ca := NewMockCaller()
l := resource.NewConfigMapListWithArgs("blee", resource.NewConfigMapWithArgs(ca))
conn := NewMockConnection()
ca := NewMockCruder()
l := resource.NewConfigMapList(conn, "blee")
assert.Equal(t, "cm", l.GetName())
}
func TestCMListHasNamespace(t *testing.T) {
setup(t)
ca := NewMockCaller()
l := resource.NewConfigMapListWithArgs("blee", resource.NewConfigMapWithArgs(ca))
conn := NewMockConnection()
ca := NewMockCruder()
l := resource.NewConfigMapList(conn, "blee")
assert.Equal(t, "blee", l.GetNamespace())
}
func TestCMListHasResource(t *testing.T) {
setup(t)
ca := NewMockCaller()
l := resource.NewConfigMapListWithArgs("blee", resource.NewConfigMapWithArgs(ca))
conn := NewMockConnection()
ca := NewMockCruder()
l := resource.NewConfigMapList(conn, "blee")
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) {
setup(t)
ca := NewMockCaller()
conn := NewMockConnection()
ca := NewMockCruder()
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!
for i := 0; i < 2; i++ {
err := l.Reconcile()
@ -146,7 +140,6 @@ func TestCMListData(t *testing.T) {
assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, "blee", l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"]
assert.Equal(t, 3, len(row.Deltas))
for _, d := range row.Deltas {
@ -158,7 +151,8 @@ func TestCMListData(t *testing.T) {
// Helpers...
func newConfigMap() resource.Columnar {
return resource.NewConfigMap().NewInstance(k8sCM())
conn := NewMockConnection()
return resource.NewConfigMap(conn).New(k8sCM())
}
func k8sCM() *v1.ConfigMap {

View File

@ -7,6 +7,7 @@ import (
// SwitchableRes represents a resource that can be switched.
type SwitchableRes interface {
k8s.Connection
k8s.ContextRes
}
@ -17,50 +18,37 @@ type Context struct {
}
// NewContextList returns a new resource list.
func NewContextList(ns string) List {
return NewContextListWithArgs(ns, NewContext())
}
// NewContextListWithArgs returns a new resource list.
func NewContextListWithArgs(ns string, res Resource) List {
return newList(NotNamespaced, "ctx", res, SwitchAccess)
func NewContextList(c k8s.Connection, ns string) List {
return newList(NotNamespaced, "ctx", NewContext(c), SwitchAccess)
}
// NewContext instantiates a new Context.
func NewContext() *Context {
return NewContextWithArgs(k8s.NewContext().(SwitchableRes))
}
func NewContext(c k8s.Connection) *Context {
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
}
// NewInstance builds a new Context instance from a k8s resource.
func (r *Context) NewInstance(i interface{}) Columnar {
c := NewContext()
switch i.(type) {
// New builds a new Context instance from a k8s resource.
func (r *Context) New(i interface{}) Columnar {
c := NewContext(r.connection)
switch instance := i.(type) {
case *k8s.NamedContext:
c.instance = i.(*k8s.NamedContext)
c.instance = instance
case k8s.NamedContext:
ii := i.(k8s.NamedContext)
c.instance = &ii
c.instance = &instance
default:
log.Fatal().Msgf("unknown context type %#v", i)
}
c.path = c.instance.Name
return c
}
// Switch out current context.
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.
@ -90,8 +78,3 @@ func (r *Context) Fields(ns string) Row {
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())
}
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...
func newContext() resource.Columnar {

View File

@ -13,51 +13,43 @@ type ClusterRole struct {
}
// NewClusterRoleList returns a new resource list.
func NewClusterRoleList(ns string) List {
return NewClusterRoleListWithArgs(ns, NewClusterRole())
}
// NewClusterRoleListWithArgs returns a new resource list.
func NewClusterRoleListWithArgs(ns string, res Resource) List {
return newList(NotNamespaced, "clusterrole", res, CRUDAccess|DescribeAccess)
func NewClusterRoleList(c k8s.Connection, ns string) List {
return newList(
NotNamespaced,
"clusterrole",
NewClusterRole(c),
CRUDAccess|DescribeAccess,
)
}
// NewClusterRole instantiates a new ClusterRole.
func NewClusterRole() *ClusterRole {
return NewClusterRoleWithArgs(k8s.NewClusterRole())
func NewClusterRole(c k8s.Connection) *ClusterRole {
cr := &ClusterRole{&Base{connection: c, resource: k8s.NewClusterRole(c)}, nil}
cr.Factory = cr
return cr
}
// NewClusterRoleWithArgs instantiates a new Context.
func NewClusterRoleWithArgs(r k8s.Res) *ClusterRole {
ctx := &ClusterRole{
Base: &Base{
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) {
// New builds a new ClusterRole instance from a k8s resource.
func (r *ClusterRole) New(i interface{}) Columnar {
c := NewClusterRole(r.connection)
switch instance := i.(type) {
case *v1.ClusterRole:
c.instance = i.(*v1.ClusterRole)
c.instance = instance
case v1.ClusterRole:
ii := i.(v1.ClusterRole)
c.instance = &ii
c.instance = &instance
default:
log.Fatal().Msgf("unknown context type %#v", i)
}
c.path = c.instance.Name
return c
}
// Marshal resource to yaml.
func (r *ClusterRole) Marshal(path string) (string, error) {
ns, n := namespaced(path)
i, err := r.caller.Get(ns, n)
i, err := r.resource.Get(ns, n)
if err != nil {
return "", err
}
@ -65,6 +57,7 @@ func (r *ClusterRole) Marshal(path string) (string, error) {
cr := i.(*v1.ClusterRole)
cr.TypeMeta.APIVersion = "rbac.authorization.k8s.io/v1"
cr.TypeMeta.Kind = "ClusterRole"
return r.marshalObject(cr)
}
@ -83,8 +76,3 @@ func (r *ClusterRole) Fields(ns string) Row {
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.
func NewClusterRoleBindingList(ns string) List {
return NewClusterRoleBindingListWithArgs(ns, NewClusterRoleBinding())
}
// NewClusterRoleBindingListWithArgs returns a new resource list.
func NewClusterRoleBindingListWithArgs(ns string, res Resource) List {
return newList(NotNamespaced, "ctx", res, SwitchAccess|ViewAccess|DeleteAccess|DescribeAccess)
func NewClusterRoleBindingList(c k8s.Connection, _ string) List {
return newList(
NotNamespaced,
"ctx",
NewClusterRoleBinding(c),
SwitchAccess|ViewAccess|DeleteAccess|DescribeAccess,
)
}
// NewClusterRoleBinding instantiates a new ClusterRoleBinding.
func NewClusterRoleBinding() *ClusterRoleBinding {
return NewClusterRoleBindingWithArgs(k8s.NewClusterRoleBinding())
func NewClusterRoleBinding(c k8s.Connection) *ClusterRoleBinding {
crb := &ClusterRoleBinding{&Base{connection: c, resource: k8s.NewClusterRoleBinding(c)}, nil}
crb.Factory = crb
return crb
}
// NewClusterRoleBindingWithArgs instantiates a new Context.
func NewClusterRoleBindingWithArgs(r k8s.Res) *ClusterRoleBinding {
ctx := &ClusterRoleBinding{
Base: &Base{
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) {
// New builds a new tabular instance from a k8s resource.
func (r *ClusterRoleBinding) New(i interface{}) Columnar {
crb := NewClusterRoleBinding(r.connection)
switch instance := i.(type) {
case *v1.ClusterRoleBinding:
c.instance = i.(*v1.ClusterRoleBinding)
crb.instance = instance
case v1.ClusterRoleBinding:
ii := i.(v1.ClusterRoleBinding)
c.instance = &ii
crb.instance = &instance
default:
log.Fatal().Msgf("unknown context type %#v", i)
}
c.path = c.instance.Name
return c
crb.path = crb.instance.Name
return crb
}
// Marshal resource to yaml.
func (r *ClusterRoleBinding) Marshal(path string) (string, error) {
ns, n := namespaced(path)
i, err := r.caller.Get(ns, n)
i, err := r.resource.Get(ns, n)
if err != nil {
return "", err
}
@ -65,6 +57,7 @@ func (r *ClusterRoleBinding) Marshal(path string) (string, error) {
crb := i.(*v1.ClusterRoleBinding)
crb.TypeMeta.APIVersion = "rbac.authorization.k8s.io/v1"
crb.TypeMeta.Kind = "ClusterRoleBinding"
return r.marshalObject(crb)
}
@ -76,15 +69,9 @@ func (*ClusterRoleBinding) Header(_ string) Row {
// Fields retrieves displayable fields.
func (r *ClusterRoleBinding) Fields(ns string) Row {
ff := make(Row, 0, len(r.Header(ns)))
i := r.instance
return append(ff,
i.Name,
toAge(i.ObjectMeta.CreationTimestamp),
r.instance.Name,
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()
assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["fred"]
assert.Equal(t, 2, len(row.Deltas))
for _, d := range row.Deltas {

View File

@ -74,7 +74,6 @@ func TestCRListData(t *testing.T) {
td := l.Data()
assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["fred"]
assert.Equal(t, 2, len(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])
}
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...
func k8sCR() *rbacv1.ClusterRole {

View File

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

View File

@ -70,7 +70,6 @@ func TestCRDListData(t *testing.T) {
td := l.Data()
assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["fred"]
assert.Equal(t, 2, len(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])
}
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...
func k8sCRD() *unstructured.Unstructured {

View File

@ -28,51 +28,43 @@ type (
)
// NewCronJobList returns a new resource list.
func NewCronJobList(ns string) List {
return NewCronJobListWithArgs(ns, NewCronJob())
}
// NewCronJobListWithArgs returns a new resource list.
func NewCronJobListWithArgs(ns string, res Resource) List {
return newList(ns, "cronjob", res, AllVerbsAccess|DescribeAccess)
func NewCronJobList(c k8s.Connection, ns string) List {
return newList(
ns,
"cronjob",
NewCronJob(c),
AllVerbsAccess|DescribeAccess,
)
}
// NewCronJob instantiates a new CronJob.
func NewCronJob() *CronJob {
return NewCronJobWithArgs(k8s.NewCronJob())
func NewCronJob(c k8s.Connection) *CronJob {
cj := &CronJob{&Base{connection: c, resource: k8s.NewCronJob(c)}, nil}
cj.Factory = cj
return cj
}
// NewCronJobWithArgs instantiates a new CronJob.
func NewCronJobWithArgs(r k8s.Res) *CronJob {
cm := &CronJob{
Base: &Base{
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) {
// New builds a new CronJob instance from a k8s resource.
func (r *CronJob) New(i interface{}) Columnar {
c := NewCronJob(r.connection)
switch instance := i.(type) {
case *batchv1beta1.CronJob:
job.instance = i.(*batchv1beta1.CronJob)
c.instance = instance
case batchv1beta1.CronJob:
ii := i.(batchv1beta1.CronJob)
job.instance = &ii
c.instance = &instance
default:
log.Fatal().Msgf("Unknown %#v", i)
log.Fatal().Msgf("unknown CronJob type %#v", i)
}
job.path = job.namespacedName(job.instance.ObjectMeta)
return job
c.path = c.namespacedName(c.instance.ObjectMeta)
return c
}
// Marshal resource to yaml.
func (r *CronJob) Marshal(path string) (string, error) {
ns, n := namespaced(path)
i, err := r.caller.Get(ns, n)
i, err := r.resource.Get(ns, n)
if err != nil {
return "", err
}
@ -80,15 +72,17 @@ func (r *CronJob) Marshal(path string) (string, error) {
cj := i.(*batchv1beta1.CronJob)
cj.TypeMeta.APIVersion = "extensions/batchv1beta1"
cj.TypeMeta.Kind = "CronJob"
return r.marshalObject(cj)
}
// Run a given cronjob.
func (r *CronJob) Run(pa string) error {
ns, n := namespaced(pa)
if c, ok := r.caller.(Runnable); ok {
if c, ok := r.resource.(Runnable); ok {
return c.Run(ns, n)
}
return fmt.Errorf("unable to run cronjob %s", pa)
}
@ -98,6 +92,7 @@ func (*CronJob) Header(ns string) Row {
if ns == AllNamespaces {
hh = append(hh, "NAMESPACE")
}
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),
)
}
// 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()
assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"]
assert.Equal(t, 6, len(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])
}
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...
func k8sCronJob() *batchv1beta1.CronJob {

View File

@ -16,49 +16,41 @@ import (
// Custom tracks a kubernetes resource.
type Custom struct {
*Base
// instance *unstructured.Unstructured
instance *metav1beta1.TableRow
group, version, name string
headers Row
}
// NewCustomList returns a new resource list.
func NewCustomList(ns, g, v, n string) List {
return NewCustomListWithArgs(ns, n, NewCustom(g, v, n))
}
// NewCustomListWithArgs returns a new resource list.
func NewCustomListWithArgs(ns, n string, res Resource) List {
return newList(ns, n, res, AllVerbsAccess)
func NewCustomList(c k8s.Connection, ns, group, version, name string) List {
if !c.IsNamespaced(name) {
ns = NotNamespaced
}
return newList(
ns,
name,
NewCustom(c, group, version, name), AllVerbsAccess,
)
}
// NewCustom instantiates a new Kubernetes Resource.
func NewCustom(g, v, n string) *Custom {
return NewCustomWithArgs(k8s.NewResource(g, v, n))
}
func NewCustom(c k8s.Connection, group, version, name string) *Custom {
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
}
// NewInstance builds a new Custom instance from a k8s resource.
func (*Custom) NewInstance(i interface{}) Columnar {
cr := NewCustom("", "", "")
switch i.(type) {
// New builds a new Custom instance from a k8s resource.
func (r *Custom) New(i interface{}) Columnar {
cr := NewCustom(r.connection, "", "", "")
switch instance := i.(type) {
case *metav1beta1.TableRow:
cr.instance = i.(*metav1beta1.TableRow)
cr.instance = instance
case metav1beta1.TableRow:
t := i.(metav1beta1.TableRow)
cr.instance = &t
cr.instance = &instance
default:
log.Fatal().Msgf("Unknown %#v", i)
}
@ -75,13 +67,14 @@ func (*Custom) NewInstance(i interface{}) Columnar {
name := meta["name"].(string)
cr.path = path.Join(ns, name)
cr.group, cr.version, cr.name = obj["kind"].(string), obj["apiVersion"].(string), name
return cr
}
// Marshal resource to yaml.
func (r *Custom) Marshal(path string) (string, error) {
ns, n := namespaced(path)
i, err := r.caller.Get(ns, n)
i, err := r.resource.Get(ns, n)
if err != nil {
return "", err
}
@ -90,12 +83,13 @@ func (r *Custom) Marshal(path string) (string, error) {
if err != nil {
return "", err
}
return string(raw), nil
}
// List all resources
func (r *Custom) List(ns string) (Columnars, error) {
ii, err := r.caller.List(ns)
ii, err := r.resource.List(ns)
if err != nil {
return nil, err
}
@ -112,21 +106,23 @@ func (r *Custom) List(ns string) (Columnars, error) {
rows := table.Rows
cc := make(Columnars, 0, len(rows))
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
}
// Header return resource header.
func (r *Custom) Header(ns string) Row {
hh := make(Row, 0, len(r.headers)+1)
if ns == AllNamespaces {
hh = append(hh, "NAMESPACE")
}
for _, h := range r.headers {
hh = append(hh, strings.ToUpper(h))
}
return hh
}
@ -142,55 +138,17 @@ func (r *Custom) Fields(ns string) Row {
}
meta := obj["metadata"].(map[string]interface{})
rns, ok := meta["namespace"].(string)
if ns == AllNamespaces {
ff = append(ff, meta["namespace"].(string))
if ok {
ff = append(ff, rns)
}
}
for _, c := range r.instance.Cells {
ff = append(ff, fmt.Sprintf("%v", c))
}
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.
func NewDeploymentList(ns string) List {
return NewDeploymentListWithArgs(ns, NewDeployment())
}
// NewDeploymentListWithArgs returns a new resource list.
func NewDeploymentListWithArgs(ns string, res Resource) List {
return newList(ns, "deploy", res, AllVerbsAccess|DescribeAccess)
func NewDeploymentList(c k8s.Connection, ns string) List {
return newList(
ns,
"deploy",
NewDeployment(c),
AllVerbsAccess|DescribeAccess,
)
}
// NewDeployment instantiates a new Deployment.
func NewDeployment() *Deployment {
return NewDeploymentWithArgs(k8s.NewDeployment())
func NewDeployment(c k8s.Connection) *Deployment {
d := &Deployment{&Base{connection: c, resource: k8s.NewDeployment(c)}, nil}
d.Factory = d
return d
}
// NewDeploymentWithArgs instantiates a new Deployment.
func NewDeploymentWithArgs(r k8s.Res) *Deployment {
cm := &Deployment{
Base: &Base{
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) {
// New builds a new Deployment instance from a k8s resource.
func (r *Deployment) New(i interface{}) Columnar {
c := NewDeployment(r.connection)
switch instance := i.(type) {
case *v1.Deployment:
cm.instance = i.(*v1.Deployment)
c.instance = instance
case v1.Deployment:
ii := i.(v1.Deployment)
cm.instance = &ii
c.instance = &instance
default:
log.Fatal().Msgf("Unknown %#v", i)
log.Fatal().Msgf("unknown Deployment type %#v", i)
}
cm.path = cm.namespacedName(cm.instance.ObjectMeta)
return cm
c.path = c.namespacedName(c.instance.ObjectMeta)
return c
}
// Marshal resource to yaml.
func (r *Deployment) Marshal(path string) (string, error) {
ns, n := namespaced(path)
i, err := r.caller.Get(ns, n)
i, err := r.resource.Get(ns, n)
if err != nil {
return "", err
}
@ -67,6 +59,7 @@ func (r *Deployment) Marshal(path string) (string, error) {
dp := i.(*v1.Deployment)
dp.TypeMeta.APIVersion = "apps/v1"
dp.TypeMeta.Kind = "Deployment"
return r.marshalObject(dp)
}
@ -76,6 +69,7 @@ func (*Deployment) Header(ns string) Row {
if ns == AllNamespaces {
hh = append(hh, "NAMESPACE")
}
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 {
ff = append(ff, i.Namespace)
}
return append(ff,
i.Name,
strconv.Itoa(int(*i.Spec.Replicas)),
@ -96,8 +91,3 @@ func (r *Deployment) Fields(ns string) Row {
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()
assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"]
assert.Equal(t, 6, len(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])
}
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...
func k8sDeployment() *appsv1.Deployment {

View File

@ -15,51 +15,43 @@ type DaemonSet struct {
}
// NewDaemonSetList returns a new resource list.
func NewDaemonSetList(ns string) List {
return NewDaemonSetListWithArgs(ns, NewDaemonSet())
}
// NewDaemonSetListWithArgs returns a new resource list.
func NewDaemonSetListWithArgs(ns string, res Resource) List {
return newList(ns, "ds", res, AllVerbsAccess|DescribeAccess)
func NewDaemonSetList(c k8s.Connection, ns string) List {
return newList(
ns,
"ds",
NewDaemonSet(c),
AllVerbsAccess|DescribeAccess,
)
}
// NewDaemonSet instantiates a new DaemonSet.
func NewDaemonSet() *DaemonSet {
return NewDaemonSetWithArgs(k8s.NewDaemonSet())
func NewDaemonSet(c k8s.Connection) *DaemonSet {
ds := &DaemonSet{&Base{connection: c, resource: k8s.NewDaemonSet(c)}, nil}
ds.Factory = ds
return ds
}
// NewDaemonSetWithArgs instantiates a new DaemonSet.
func NewDaemonSetWithArgs(r k8s.Res) *DaemonSet {
cm := &DaemonSet{
Base: &Base{
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) {
// New builds a new DaemonSet instance from a k8s resource.
func (r *DaemonSet) New(i interface{}) Columnar {
c := NewDaemonSet(r.connection)
switch instance := i.(type) {
case *extv1beta1.DaemonSet:
cm.instance = i.(*extv1beta1.DaemonSet)
c.instance = instance
case extv1beta1.DaemonSet:
ii := i.(extv1beta1.DaemonSet)
cm.instance = &ii
c.instance = &instance
default:
log.Fatal().Msgf("Unknown %#v", i)
log.Fatal().Msgf("unknown DaemonSet type %#v", i)
}
cm.path = cm.namespacedName(cm.instance.ObjectMeta)
return cm
c.path = c.namespacedName(c.instance.ObjectMeta)
return c
}
// Marshal resource to yaml.
func (r *DaemonSet) Marshal(path string) (string, error) {
ns, n := namespaced(path)
i, err := r.caller.Get(ns, n)
i, err := r.resource.Get(ns, n)
if err != nil {
return "", err
}
@ -67,6 +59,7 @@ func (r *DaemonSet) Marshal(path string) (string, error) {
ds := i.(*extv1beta1.DaemonSet)
ds.TypeMeta.APIVersion = "extensions/v1beta1"
ds.TypeMeta.Kind = "DaemonSet"
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, "AVAILABLE", "NODE_SELECTOR", "AGE")
return hh
}
@ -89,6 +83,7 @@ func (r *DaemonSet) Fields(ns string) Row {
if ns == AllNamespaces {
ff = append(ff, i.Namespace)
}
return append(ff,
i.Name,
strconv.Itoa(int(i.Status.DesiredNumberScheduled)),
@ -100,8 +95,3 @@ func (r *DaemonSet) Fields(ns string) Row {
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()
assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"]
assert.Equal(t, 8, len(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])
}
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...
func k8sDS() *extv1beta1.DaemonSet {

View File

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

View File

@ -62,7 +62,6 @@ func TestEndpointsListData(t *testing.T) {
td := l.Data()
assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"]
assert.Equal(t, 3, len(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])
}
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...
func k8sEndpoints() *v1.Endpoints {

View File

@ -16,51 +16,43 @@ type Event struct {
}
// NewEventList returns a new resource list.
func NewEventList(ns string) List {
return NewEventListWithArgs(ns, NewEvent())
func NewEventList(c k8s.Connection, ns string) List {
return newList(
ns,
"ev",
NewEvent(c),
ListAccess+NamespaceAccess,
)
}
// NewEventListWithArgs returns a new resource list.
func NewEventListWithArgs(ns string, res Resource) List {
return newList(ns, "event", res, ListAccess+NamespaceAccess)
// NewEvent instantiates a new Event.
func NewEvent(c k8s.Connection) *Event {
ev := &Event{&Base{connection: c, resource: k8s.NewEvent(c)}, nil}
ev.Factory = ev
return ev
}
// NewEvent instantiates a new Endpoint.
func NewEvent() *Event {
return NewEventWithArgs(k8s.NewEvent())
}
// 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) {
// New builds a new Event instance from a k8s resource.
func (r *Event) New(i interface{}) Columnar {
c := NewEvent(r.connection)
switch instance := i.(type) {
case *v1.Event:
cm.instance = i.(*v1.Event)
c.instance = instance
case v1.Event:
ii := i.(v1.Event)
cm.instance = &ii
c.instance = &instance
default:
log.Fatal().Msgf("Unknown %#v", i)
log.Fatal().Msgf("unknown Event type %#v", i)
}
cm.path = cm.namespacedName(cm.instance.ObjectMeta)
return cm
c.path = c.namespacedName(c.instance.ObjectMeta)
return c
}
// Marshal resource to yaml.
func (r *Event) Marshal(path string) (string, error) {
ns, n := namespaced(path)
i, err := r.caller.Get(ns, n)
i, err := r.resource.Get(ns, n)
if err != nil {
return "", err
}
@ -68,19 +60,10 @@ func (r *Event) Marshal(path string) (string, error) {
ev := i.(*v1.Event)
ev.TypeMeta.APIVersion = "v1"
ev.TypeMeta.Kind = "Event"
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.
func (r *Event) Delete(path string) error {
return nil
@ -92,6 +75,7 @@ func (*Event) Header(ns string) Row {
if ns == AllNamespaces {
ff = append(ff, "NAMESPACE")
}
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...
func (*Event) toEmoji(t, r string) string {

View File

@ -62,7 +62,6 @@ func TestEventListData(t *testing.T) {
td := l.Data()
assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"]
assert.Equal(t, 6, len(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])
}
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...
func k8sEvent() *v1.Event {

View File

@ -38,6 +38,7 @@ const (
func namespaced(n string) (string, string) {
ns, po := path.Split(n)
return strings.Trim(ns, "/"), po
}
@ -53,6 +54,7 @@ func check(s, sub string) string {
if len(s) == 0 {
return sub
}
return s
}
@ -73,12 +75,14 @@ func toAge(timestamp metav1.Time) string {
if timestamp.IsZero() {
return "<unknown>"
}
return duration.HumanDuration(time.Since(timestamp.Time))
}
// Pad a string up to the given length.
func Pad(s string, l int) string {
fmat := "%-" + strconv.Itoa(l) + "s"
return fmt.Sprintf(fmat, s)
}
@ -104,5 +108,16 @@ func mapToStr(m map[string]string) (s string) {
s += ","
}
}
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)
}
}
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.
func NewHPAList(ns string) List {
return NewHPAListWithArgs(ns, NewHPA())
func NewHPAList(c k8s.Connection, ns string) List {
return newList(
ns,
"hpa",
NewHPA(c),
AllVerbsAccess|DescribeAccess,
)
}
// NewHPAListWithArgs returns a new resource list.
func NewHPAListWithArgs(ns string, res Resource) List {
return newList(ns, "hpa", res, AllVerbsAccess|DescribeAccess)
// NewHPA instantiates a new HPA.
func NewHPA(c k8s.Connection) *HPA {
hpa := &HPA{&Base{connection: c, resource: k8s.NewHPA(c)}, nil}
hpa.Factory = hpa
return hpa
}
// NewHPA instantiates a new Endpoint.
func NewHPA() *HPA {
return NewHPAWithArgs(k8s.NewHPA())
}
// 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) {
// New builds a new HPA instance from a k8s resource.
func (r *HPA) New(i interface{}) Columnar {
c := NewHPA(r.connection)
switch instance := i.(type) {
case *autoscalingv2beta2.HorizontalPodAutoscaler:
cm.instance = i.(*autoscalingv2beta2.HorizontalPodAutoscaler)
c.instance = instance
case autoscalingv2beta2.HorizontalPodAutoscaler:
ii := i.(autoscalingv2beta2.HorizontalPodAutoscaler)
cm.instance = &ii
c.instance = &instance
default:
log.Fatal().Msgf("Unknown %#v", i)
log.Fatal().Msgf("unknown HPA type %#v", i)
}
cm.path = cm.namespacedName(cm.instance.ObjectMeta)
return cm
c.path = c.namespacedName(c.instance.ObjectMeta)
return c
}
// Marshal resource to yaml.
func (r *HPA) Marshal(path string) (string, error) {
ns, n := namespaced(path)
i, err := r.caller.Get(ns, n)
i, err := r.resource.Get(ns, n)
if err != nil {
return "", err
}
@ -69,6 +61,7 @@ func (r *HPA) Marshal(path string) (string, error) {
hpa := i.(*autoscalingv2beta2.HorizontalPodAutoscaler)
hpa.TypeMeta.APIVersion = "autoscaling/v2beta2"
hpa.TypeMeta.Kind = "HorizontalPodAutoscaler"
return r.marshalObject(hpa)
}
@ -78,6 +71,7 @@ func (*HPA) Header(ns string) Row {
if ns == AllNamespaces {
hh = append(hh, "NAMESPACE")
}
return append(hh,
"NAME",
"REFERENCE",
@ -108,60 +102,33 @@ func (r *HPA) Fields(ns string) Row {
)
}
// ExtFields returns extended fields in relation to headers.
func (*HPA) ExtFields() Properties {
return Properties{}
}
// ----------------------------------------------------------------------------
// Helpers...
func toMetrics(specs []autoscalingv2beta2.MetricSpec, statuses []autoscalingv2beta2.MetricStatus) string {
if len(specs) == 0 {
return "<none>"
}
list, max, more, count := []string{}, 2, false, 0
for i, spec := range specs {
current := "<unknown>"
switch spec.Type {
case autoscalingv2beta2.ExternalMetricSourceType:
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()
}
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()))
}
list = append(list, externalMetrics(i, spec, statuses))
case autoscalingv2beta2.PodsMetricSourceType:
current := "<unknown>"
if len(statuses) > i && statuses[i].Pods != nil {
current = statuses[i].Pods.Current.AverageValue.String()
}
list = append(list, fmt.Sprintf("%s/%s", current, spec.Pods.Target.AverageValue.String()))
case autoscalingv2beta2.ObjectMetricSourceType:
current := "<unknown>"
if len(statuses) > i && statuses[i].Object != nil {
current = statuses[i].Object.Current.Value.String()
}
list = append(list, fmt.Sprintf("%s/%s", current, spec.Object.Target.Value.String()))
case autoscalingv2beta2.ResourceMetricSourceType:
current := "<unknown>"
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))
}
list = append(list, resourceMetrics(i, spec, statuses))
default:
list = append(list, "<unknown type>")
}
@ -169,13 +136,50 @@ func toMetrics(specs []autoscalingv2beta2.MetricSpec, statuses []autoscalingv2be
}
if count > max {
list = list[:max]
more = true
list, more = list[:max], true
}
ret := strings.Join(list, ", ")
if more {
return fmt.Sprintf("%s + %d more...", ret, count-max)
}
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()
assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"]
assert.Equal(t, 7, len(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])
}
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...
func k8sHPA() *autoscalingv2beta2.HorizontalPodAutoscaler {

View File

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

View File

@ -62,7 +62,6 @@ func TestIngressListData(t *testing.T) {
td := l.Data()
assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"]
assert.Equal(t, 5, len(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])
}
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...
func k8sIngress() *v1beta1.Ingress {

View File

@ -19,51 +19,43 @@ type Job struct {
}
// NewJobList returns a new resource list.
func NewJobList(ns string) List {
return NewJobListWithArgs(ns, NewJob())
}
// NewJobListWithArgs returns a new resource list.
func NewJobListWithArgs(ns string, res Resource) List {
return newList(ns, "job", res, AllVerbsAccess|DescribeAccess)
func NewJobList(c k8s.Connection, ns string) List {
return newList(
ns,
"job",
NewJob(c),
AllVerbsAccess|DescribeAccess,
)
}
// NewJob instantiates a new Job.
func NewJob() *Job {
return NewJobWithArgs(k8s.NewJob())
func NewJob(c k8s.Connection) *Job {
j := &Job{&Base{connection: c, resource: k8s.NewJob(c)}, nil}
j.Factory = j
return j
}
// NewJobWithArgs instantiates a new Job.
func NewJobWithArgs(r k8s.Res) *Job {
cm := &Job{
Base: &Base{
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) {
// New builds a new Job instance from a k8s resource.
func (r *Job) New(i interface{}) Columnar {
c := NewJob(r.connection)
switch instance := i.(type) {
case *v1.Job:
job.instance = i.(*v1.Job)
c.instance = instance
case v1.Job:
ii := i.(v1.Job)
job.instance = &ii
c.instance = &instance
default:
log.Fatal().Msgf("Unknown %#v", i)
log.Fatal().Msgf("unknown Job type %#v", i)
}
job.path = job.namespacedName(job.instance.ObjectMeta)
return job
c.path = c.namespacedName(c.instance.ObjectMeta)
return c
}
// Marshal resource to yaml.
func (r *Job) Marshal(path string) (string, error) {
ns, n := namespaced(path)
i, err := r.caller.Get(ns, n)
i, err := r.resource.Get(ns, n)
if err != nil {
return "", err
}
@ -71,18 +63,20 @@ func (r *Job) Marshal(path string) (string, error) {
jo := i.(*v1.Job)
jo.TypeMeta.APIVersion = "extensions/v1beta1"
jo.TypeMeta.Kind = "Job"
return r.marshalObject(jo)
}
// Containers fetch all the containers on this job, may include init containers.
func (r *Job) Containers(path string, includeInit bool) ([]string, error) {
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.
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())
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()
}
}()
return cancel, nil
}
@ -125,6 +120,7 @@ func (*Job) Header(ns string) Row {
if ns == AllNamespaces {
hh = append(hh, "NAMESPACE")
}
return append(hh, "NAME", "COMPLETIONS", "DURATION", "AGE")
}
@ -136,6 +132,7 @@ func (r *Job) Fields(ns string) Row {
if ns == AllNamespaces {
ff = append(ff, i.Namespace)
}
return append(ff,
i.Name,
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...
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 {
return fmt.Sprintf("%d/1 of %d", status.Succeeded, parallelism)
}
return fmt.Sprintf("%d/1", status.Succeeded)
}
@ -171,5 +165,6 @@ func (*Job) toDuration(status v1.JobStatus) string {
case status.CompletionTime == nil:
return duration.HumanDuration(time.Since(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()
assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"]
assert.Equal(t, 4, len(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])
}
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...
func k8sJob() *v1.Job {

View File

@ -3,8 +3,8 @@ package resource
import (
"reflect"
"github.com/derailed/k9s/internal/k8s"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/cli-runtime/pkg/genericclioptions"
)
const (
@ -63,10 +63,8 @@ type (
GetNamespace() string
SetNamespace(string)
Reconcile() error
Describe(pa string) (Properties, error)
GetName() string
Access(flag int) bool
HasXRay() bool
}
// Columnar tracks resources that can be diplayed in a tabular fashion.
@ -86,20 +84,13 @@ type (
// Columnars a collection of columnars.
Columnars []Columnar
// MxColumnar tracks resource metrics.
MxColumnar interface {
Columnar
Metrics() k8s.Metric
SetMetrics(k8s.Metric)
}
// Resource tracks generic Kubernetes resources.
Resource interface {
NewInstance(interface{}) Columnar
New(interface{}) Columnar
Get(path string) (Columnar, error)
List(ns string) (Columnars, 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)
Header(ns string) Row
}
@ -107,8 +98,7 @@ type (
list struct {
namespace, name string
verbs int
xray bool
api Resource
resource Resource
cache RowEvents
}
)
@ -117,20 +107,16 @@ func newRowEvent(a watch.EventType, f, d Row) *RowEvent {
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{
namespace: ns,
name: name,
verbs: v,
api: api,
verbs: verbs,
resource: res,
cache: RowEvents{},
}
}
func (l *list) HasXRay() bool {
return l.xray
}
// Access check access control on a given resource.
func (l *list) Access(f int) bool {
return l.verbs&f == f
@ -151,6 +137,7 @@ func (l *list) GetNamespace() string {
if !l.Access(NamespaceAccess) {
l.namespace = NotNamespaced
}
return l.namespace
}
@ -179,28 +166,18 @@ func (l *list) GetName() string {
// Resource returns a resource api connection.
func (l *list) Resource() Resource {
return l.api
return l.resource
}
// Cache tracks previous resource state.
func (l *list) Data() TableData {
return TableData{
Header: l.api.Header(l.namespace),
Header: l.resource.Header(l.namespace),
Rows: l.cache,
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.
func (l *list) Reconcile() error {
var (
@ -208,7 +185,7 @@ func (l *list) Reconcile() 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
}
@ -254,5 +231,6 @@ func (l *list) Reconcile() error {
delete(l.cache, k)
}
}
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.
// Source: github.com/derailed/k9s/internal/resource (interfaces: Caller)
// Source: github.com/derailed/k9s/internal/resource (interfaces: Cruder)
package resource_test
@ -10,17 +10,17 @@ import (
"time"
)
type MockCaller struct {
type MockCruder struct {
fail func(message string, callerSkip ...int)
}
func NewMockCaller() *MockCaller {
return &MockCaller{fail: pegomock.GlobalFailHandler}
func NewMockCruder() *MockCruder {
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 {
panic("mock must not be nil. Use myMock := NewMockCaller().")
panic("mock must not be nil. Use myMock := NewMockCruder().")
}
params := []pegomock.Param{_param0, _param1}
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
}
func (mock *MockCaller) Get(_param0 string, _param1 string) (interface{}, error) {
func (mock *MockCruder) Get(_param0 string, _param1 string) (interface{}, error) {
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}
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
}
func (mock *MockCaller) List(_param0 string) (k8s.Collection, error) {
func (mock *MockCruder) List(_param0 string) (k8s.Collection, error) {
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}
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
}
func (mock *MockCaller) VerifyWasCalledOnce() *VerifierCaller {
return &VerifierCaller{
func (mock *MockCruder) VerifyWasCalledOnce() *VerifierCruder {
return &VerifierCruder{
mock: mock,
invocationCountMatcher: pegomock.Times(1),
}
}
func (mock *MockCaller) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierCaller {
return &VerifierCaller{
func (mock *MockCruder) VerifyWasCalled(invocationCountMatcher pegomock.Matcher) *VerifierCruder {
return &VerifierCruder{
mock: mock,
invocationCountMatcher: invocationCountMatcher,
}
}
func (mock *MockCaller) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierCaller {
return &VerifierCaller{
func (mock *MockCruder) VerifyWasCalledInOrder(invocationCountMatcher pegomock.Matcher, inOrderContext *pegomock.InOrderContext) *VerifierCruder {
return &VerifierCruder{
mock: mock,
invocationCountMatcher: invocationCountMatcher,
inOrderContext: inOrderContext,
}
}
func (mock *MockCaller) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierCaller {
return &VerifierCaller{
func (mock *MockCruder) VerifyWasCalledEventually(invocationCountMatcher pegomock.Matcher, timeout time.Duration) *VerifierCruder {
return &VerifierCruder{
mock: mock,
invocationCountMatcher: invocationCountMatcher,
timeout: timeout,
}
}
type VerifierCaller struct {
mock *MockCaller
type VerifierCruder struct {
mock *MockCruder
invocationCountMatcher pegomock.Matcher
inOrderContext *pegomock.InOrderContext
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}
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 {
mock *MockCaller
type Cruder_Delete_OngoingVerification struct {
mock *MockCruder
methodInvocations []pegomock.MethodInvocation
}
func (c *Caller_Delete_OngoingVerification) GetCapturedArguments() (string, string) {
func (c *Cruder_Delete_OngoingVerification) GetCapturedArguments() (string, string) {
_param0, _param1 := c.GetAllCapturedArguments()
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)
if len(params) > 0 {
_param0 = make([]string, len(params[0]))
@ -139,23 +139,23 @@ func (c *Caller_Delete_OngoingVerification) GetAllCapturedArguments() (_param0 [
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}
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 {
mock *MockCaller
type Cruder_Get_OngoingVerification struct {
mock *MockCruder
methodInvocations []pegomock.MethodInvocation
}
func (c *Caller_Get_OngoingVerification) GetCapturedArguments() (string, string) {
func (c *Cruder_Get_OngoingVerification) GetCapturedArguments() (string, string) {
_param0, _param1 := c.GetAllCapturedArguments()
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)
if len(params) > 0 {
_param0 = make([]string, len(params[0]))
@ -170,23 +170,23 @@ func (c *Caller_Get_OngoingVerification) GetAllCapturedArguments() (_param0 []st
return
}
func (verifier *VerifierCaller) List(_param0 string) *Caller_List_OngoingVerification {
func (verifier *VerifierCruder) List(_param0 string) *Cruder_List_OngoingVerification {
params := []pegomock.Param{_param0}
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 {
mock *MockCaller
type Cruder_List_OngoingVerification struct {
mock *MockCruder
methodInvocations []pegomock.MethodInvocation
}
func (c *Caller_List_OngoingVerification) GetCapturedArguments() string {
func (c *Cruder_List_OngoingVerification) GetCapturedArguments() string {
_param0 := c.GetAllCapturedArguments()
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)
if 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.
type Node struct {
*Base
instance *v1.Node
metricSvc MetricsIfc
metrics k8s.Metric
instance *v1.Node
metricsServer MetricsServer
metrics k8s.NodeMetrics
}
// NewNodeList returns a new resource list.
func NewNodeList(ns string) List {
return NewNodeListWithArgs(ns, NewNode())
func NewNodeList(c k8s.Connection, ns string) List {
return newList(
NotNamespaced,
"no",
NewNode(c),
ViewAccess|DescribeAccess,
)
}
// NewNodeListWithArgs returns a new resource list.
func NewNodeListWithArgs(ns string, res Resource) List {
return newList(NotNamespaced, "no", res, ViewAccess|DescribeAccess)
// NewNode instantiates a new Node.
func NewNode(c k8s.Connection) *Node {
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.
func NewNode() *Node {
return NewNodeWithArgs(k8s.NewNode(), k8s.NewMetricsServer())
}
// 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) {
// New builds a new Node instance from a k8s resource.
func (r *Node) New(i interface{}) Columnar {
c := NewNode(r.connection)
switch instance := i.(type) {
case *v1.Node:
cm.instance = i.(*v1.Node)
c.instance = instance
case v1.Node:
ii := i.(v1.Node)
cm.instance = &ii
c.instance = &instance
default:
log.Fatal().Msgf("Unknown %#v", i)
log.Fatal().Msgf("unknown Node type %#v", i)
}
cm.path = cm.namespacedName(cm.instance.ObjectMeta)
return cm
c.path = c.namespacedName(c.instance.ObjectMeta)
return c
}
// List all resources for a given namespace.
func (r *Node) List(ns string) (Columnars, error) {
ii, err := r.caller.List(AllNamespaces)
nn, err := r.resource.List(ns)
if err != nil {
return nil, err
}
nn := make([]v1.Node, len(ii))
for k, i := range ii {
nn[k] = i.(v1.Node)
nodes := make([]v1.Node, 0, len(nn))
for _, n := range nn {
nodes = append(nodes, n.(v1.Node))
}
cc := make(Columnars, 0, len(nn))
mx, err := r.metricSvc.PerNodeMetrics(nn)
if err != nil {
log.Warn().Msgf("No metrics: %#v", err)
mx := make(k8s.NodesMetrics, len(nodes))
if r.metricsServer.HasMetrics() {
nmx, _ := r.metricsServer.FetchNodesMetrics()
r.metricsServer.NodesMetrics(nodes, nmx, mx)
}
for i := 0; i < len(nn); i++ {
n := r.NewInstance(&nn[i]).(*Node)
if err == nil {
n.metrics = mx[nn[i].Name]
}
cc = append(cc, n)
cc := make(Columnars, 0, len(nodes))
for i := range nodes {
no := r.New(&nodes[i]).(*Node)
no.metrics = mx[nodes[i].Name]
cc = append(cc, no)
}
return cc, nil
}
// Marshal a resource to yaml.
func (r *Node) Marshal(path string) (string, error) {
ns, n := namespaced(path)
i, err := r.caller.Get(ns, n)
i, err := r.resource.Get(ns, n)
if err != nil {
log.Error().Err(err)
return "", err
@ -106,6 +97,7 @@ func (r *Node) Marshal(path string) (string, error) {
no := i.(*v1.Node)
no.TypeMeta.APIVersion = "v1"
no.TypeMeta.Kind = "Node"
return r.marshalObject(no)
}
@ -116,12 +108,15 @@ func (*Node) Header(ns string) Row {
"STATUS",
"ROLES",
"VERSION",
"KERNEL",
"INTERNAL-IP",
"EXTERNAL-IP",
"CPU",
"MEM",
"AVAILABLE_CPU",
"AVAILABLE_MEM",
"AVA CPU",
"AVA MEM",
"CAP CPU",
"CAP MEM",
"AGE",
}
}
@ -131,33 +126,28 @@ func (r *Node) Fields(ns string) Row {
ff := make(Row, 0, len(r.Header(ns)))
i := r.instance
status := r.status(i)
iIP, eIP := r.getIPs(i.Status.Addresses)
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,
i.Name,
status,
roles,
r.status(i),
missing(strings.Join(findNodeRoles(i), ",")),
i.Status.NodeInfo.KubeletVersion,
i.Status.NodeInfo.KernelVersion,
iIP,
eIP,
cpu,
mem,
acpu,
amem,
ToMillicore(r.metrics.CurrentCPU),
ToMi(r.metrics.CurrentMEM),
ToMillicore(r.metrics.AvailCPU),
ToMi(r.metrics.AvailMEM),
ToMillicore(r.metrics.TotalCPU),
ToMi(r.metrics.TotalMEM),
toAge(i.ObjectMeta.CreationTimestamp),
)
}
// ExtFields returns extended fields in relation to headers.
func (*Node) ExtFields() Properties {
return Properties{}
}
// ----------------------------------------------------------------------------
// Helpers...
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
}
}
return
}
@ -195,6 +186,7 @@ func (r *Node) status(i *v1.Node) string {
if i.Spec.Unschedulable {
status = append(status, "SchedulingDisabled")
}
return strings.Join(status, ",")
}
@ -210,5 +202,6 @@ func findNodeRoles(i *v1.Node) []string {
roles.Insert(v)
}
}
return roles.List()
}

View File

@ -8,7 +8,10 @@ import (
m "github.com/petergtz/pegomock"
"github.com/stretchr/testify/assert"
v1 "k8s.io/api/core/v1"
res "k8s.io/apimachinery/pkg/api/resource"
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) {
@ -31,9 +34,9 @@ func TestNodeFields(t *testing.T) {
func TestNodeMarshal(t *testing.T) {
setup(t)
mx := NewMockMetricsIfc()
m.When(mx.PerNodeMetrics([]v1.Node{*k8sNode()})).
ThenReturn(map[string]k8s.Metric{"fred": {}}, nil)
mx := NewMockMetricsServer()
// m.When(mx.NodesMetrics([]v1.Node{*k8sNode()})).
// ThenReturn(map[string]k8s.RawMetric{"fred": {}}, nil)
ca := NewMockCaller()
m.When(ca.Get("blee", "fred")).ThenReturn(k8sNode(), nil)
@ -47,48 +50,34 @@ func TestNodeMarshal(t *testing.T) {
func TestNodeListData(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.List("")).ThenReturn(k8s.Collection{*k8sNode()}, nil)
mockServer := NewMockMetricsServer()
m.When(mockServer.HasMetrics()).ThenReturn(true)
m.When(mockServer.FetchNodesMetrics()).
ThenReturn([]mv1beta1.NodeMetrics{makeMxNode("fred", "100m", "100Mi")}, 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!
for i := 0; i < 2; i++ {
err := l.Reconcile()
assert.Nil(t, err)
}
ca.VerifyWasCalled(m.Times(2)).List("")
ca.VerifyWasCalled(m.Times(2)).List("-")
td := l.Data()
assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["fred"]
assert.Equal(t, 11, len(row.Deltas))
row, ok := td.Rows["fred"]
assert.True(t, ok)
assert.Equal(t, 12, len(row.Deltas))
for _, d := range row.Deltas {
assert.Equal(t, "", d)
}
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...
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 {
return resource.NewNode().NewInstance(k8sNode())
}

View File

@ -13,51 +13,43 @@ type Namespace struct {
}
// NewNamespaceList returns a new resource list.
func NewNamespaceList(ns string) List {
return NewNamespaceListWithArgs(ns, NewNamespace())
func NewNamespaceList(c k8s.Connection, ns string) List {
return newList(
NotNamespaced,
"ns",
NewNamespace(c),
CRUDAccess|DescribeAccess,
)
}
// NewNamespaceListWithArgs returns a new resource list.
func NewNamespaceListWithArgs(ns string, res Resource) List {
return newList(NotNamespaced, "ns", res, CRUDAccess|DescribeAccess)
// NewNamespace instantiates a new Namespace.
func NewNamespace(c k8s.Connection) *Namespace {
n := &Namespace{&Base{connection: c, resource: k8s.NewNamespace(c)}, nil}
n.Factory = n
return n
}
// NewNamespace instantiates a new Endpoint.
func NewNamespace() *Namespace {
return NewNamespaceWithArgs(k8s.NewNamespace())
}
// 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) {
// New builds a new Namespace instance from a k8s resource.
func (r *Namespace) New(i interface{}) Columnar {
c := NewNamespace(r.connection)
switch instance := i.(type) {
case *v1.Namespace:
cm.instance = i.(*v1.Namespace)
c.instance = instance
case v1.Namespace:
ii := i.(v1.Namespace)
cm.instance = &ii
c.instance = &instance
default:
log.Fatal().Msgf("Unknown %#v", i)
log.Fatal().Msgf("unknown Namespace type %#v", i)
}
cm.path = cm.namespacedName(cm.instance.ObjectMeta)
return cm
c.path = c.namespacedName(c.instance.ObjectMeta)
return c
}
// Marshal a resource to yaml.
func (r *Namespace) Marshal(path string) (string, error) {
ns, n := namespaced(path)
i, err := r.caller.Get(ns, n)
i, err := r.resource.Get(ns, n)
if err != nil {
log.Error().Err(err)
return "", err
@ -66,6 +58,7 @@ func (r *Namespace) Marshal(path string) (string, error) {
nss := i.(*v1.Namespace)
nss.TypeMeta.APIVersion = "v1"
nss.TypeMeta.Kind = "Namespace"
return r.marshalObject(nss)
}
@ -78,14 +71,10 @@ func (*Namespace) Header(ns string) Row {
func (r *Namespace) Fields(ns string) Row {
ff := make(Row, 0, len(r.Header(ns)))
i := r.instance
return append(ff,
i.Name,
string(i.Status.Phase),
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()
assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"]
assert.Equal(t, 3, len(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])
}
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...
func k8sNamespace() *v1.Namespace {

View File

@ -11,59 +11,52 @@ import (
// PodDisruptionBudget that can be displayed in a table and interacted with.
type PodDisruptionBudget struct {
*Base
instance *v1beta1.PodDisruptionBudget
}
// NewPDBList returns a new resource list.
func NewPDBList(ns string) List {
return NewPDBListWithArgs(ns, NewPDB())
func NewPDBList(c k8s.Connection, ns string) List {
return newList(
ns,
"pdb",
NewPDB(c),
AllVerbsAccess|DescribeAccess,
)
}
// NewPDBListWithArgs returns a new resource list.
func NewPDBListWithArgs(ns string, res Resource) List {
return newList(ns, "pdb", res, AllVerbsAccess|DescribeAccess)
}
// NewPDB instantiates a new PDB.
func NewPDB(c k8s.Connection) *PodDisruptionBudget {
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
}
// NewInstance builds a new PodDisruptionBudget instance from a k8s resource.
func (r *PodDisruptionBudget) NewInstance(i interface{}) Columnar {
pdb := NewPDB()
switch i.(type) {
// New builds a new PDB instance from a k8s resource.
func (r *PodDisruptionBudget) New(i interface{}) Columnar {
c := NewPDB(r.connection)
switch instance := i.(type) {
case *v1beta1.PodDisruptionBudget:
pdb.instance = i.(*v1beta1.PodDisruptionBudget)
c.instance = instance
case v1beta1.PodDisruptionBudget:
ii := i.(v1beta1.PodDisruptionBudget)
pdb.instance = &ii
c.instance = &instance
case *interface{}:
ptr := *i.(*interface{})
pdbi := ptr.(v1beta1.PodDisruptionBudget)
pdb.instance = &pdbi
c.instance = &pdbi
default:
log.Fatal().Msgf("Unknown %#v", i)
log.Fatal().Msgf("unknown PDB type %#v", i)
}
pdb.path = r.namespacedName(pdb.instance.ObjectMeta)
return pdb
c.path = c.namespacedName(c.instance.ObjectMeta)
return c
}
// Marshal resource to yaml.
func (r *PodDisruptionBudget) Marshal(path string) (string, error) {
ns, n := namespaced(path)
i, err := r.caller.Get(ns, n)
i, err := r.resource.Get(ns, n)
if err != nil {
return "", err
}
@ -71,6 +64,7 @@ func (r *PodDisruptionBudget) Marshal(path string) (string, error) {
pdb := i.(*v1beta1.PodDisruptionBudget)
pdb.TypeMeta.APIVersion = "v1beta1"
pdb.TypeMeta.Kind = "PodDisruptionBudget"
return r.marshalObject(pdb)
}
@ -80,6 +74,7 @@ func (*PodDisruptionBudget) Header(ns string) Row {
if ns == AllNamespaces {
hh = append(hh, "NAMESPACE")
}
return append(hh,
"NAME",
"MIN AVAILABLE",
@ -122,8 +117,3 @@ func (r *PodDisruptionBudget) Fields(ns string) Row {
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()
assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"]
assert.Equal(t, 8, len(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])
}
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...
func k8sPDB() *v1beta1.PodDisruptionBudget {

View File

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

View File

@ -35,8 +35,9 @@ func TestPodFields(t *testing.T) {
func TestPodMarshal(t *testing.T) {
setup(t)
mx := NewMockMetricsIfc()
m.When(mx.PodMetrics()).ThenReturn(map[string]k8s.Metric{"fred": {}}, nil)
mx := NewMockMetricsServer()
// metrics := make(k8s.PodsMetrics, 1)
// m.When(mx.PodsMetrics([]mv1beta1.PodMetrics{}, metrics)).thenReturn()
ca := NewMockCaller()
m.When(ca.Get("blee", "fred")).ThenReturn(k8sPod(), nil)
@ -50,8 +51,8 @@ func TestPodMarshal(t *testing.T) {
func TestPodListData(t *testing.T) {
setup(t)
mx := NewMockMetricsIfc()
m.When(mx.PodMetrics()).ThenReturn(map[string]k8s.Metric{"fred": {}}, nil)
mx := NewMockMetricsServer()
// m.When(mx.PodsMetrics("")).ThenReturn(map[string]k8s.Metric{"fred": {}}, nil)
ca := NewMockCaller()
m.When(ca.List("")).ThenReturn(k8s.Collection{*k8sPod()}, nil)
@ -66,7 +67,6 @@ func TestPodListData(t *testing.T) {
td := l.Data()
assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.AllNamespaces, l.GetNamespace())
assert.True(t, l.HasXRay())
row := td.Rows["blee/fred"]
assert.Equal(t, 11, len(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])
}
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...
func k8sPod() *v1.Pod {

View File

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

View File

@ -62,7 +62,6 @@ func TestPVListData(t *testing.T) {
td := l.Data()
assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"]
assert.Equal(t, 9, len(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])
}
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...
func k8sPV() *v1.PersistentVolume {

View File

@ -13,51 +13,43 @@ type PVC struct {
}
// NewPVCList returns a new resource list.
func NewPVCList(ns string) List {
return NewPVCListWithArgs(ns, NewPVC())
func NewPVCList(c k8s.Connection, ns string) List {
return newList(
ns,
"pvc",
NewPVC(c),
AllVerbsAccess|DescribeAccess,
)
}
// NewPVCListWithArgs returns a new resource list.
func NewPVCListWithArgs(ns string, res Resource) List {
return newList(ns, "pvc", res, AllVerbsAccess|DescribeAccess)
// NewPVC instantiates a new PVC.
func NewPVC(c k8s.Connection) *PVC {
p := &PVC{&Base{connection: c, resource: k8s.NewPVC(c)}, nil}
p.Factory = p
return p
}
// NewPVC instantiates a new Endpoint.
func NewPVC() *PVC {
return NewPVCWithArgs(k8s.NewPVC())
}
// 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) {
// New builds a new PVC instance from a k8s resource.
func (r *PVC) New(i interface{}) Columnar {
c := NewPVC(r.connection)
switch instance := i.(type) {
case *v1.PersistentVolumeClaim:
cm.instance = i.(*v1.PersistentVolumeClaim)
c.instance = instance
case v1.PersistentVolumeClaim:
ii := i.(v1.PersistentVolumeClaim)
cm.instance = &ii
c.instance = &instance
default:
log.Fatal().Msgf("Unknown %#v", i)
log.Fatal().Msgf("unknown PVC type %#v", i)
}
cm.path = cm.namespacedName(cm.instance.ObjectMeta)
return cm
c.path = c.namespacedName(c.instance.ObjectMeta)
return c
}
// Marshal resource to yaml.
func (r *PVC) Marshal(path string) (string, error) {
ns, n := namespaced(path)
i, err := r.caller.Get(ns, n)
i, err := r.resource.Get(ns, n)
if err != nil {
return "", err
}
@ -65,6 +57,7 @@ func (r *PVC) Marshal(path string) (string, error) {
pvc := i.(*v1.PersistentVolumeClaim)
pvc.TypeMeta.APIVersion = "v1"
pvc.TypeMeta.Kind = "PersistentVolumeClaim"
return r.marshalObject(pvc)
}
@ -74,6 +67,7 @@ func (*PVC) Header(ns string) Row {
if ns == AllNamespaces {
hh = append(hh, "NAMESPACE")
}
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),
)
}
// 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()
assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"]
assert.Equal(t, 7, len(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])
}
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...
func k8sPVC() *v1.PersistentVolumeClaim {

View File

@ -15,51 +15,43 @@ type ReplicationController struct {
}
// NewReplicationControllerList returns a new resource list.
func NewReplicationControllerList(ns string) List {
return NewReplicationControllerListWithArgs(ns, NewReplicationController())
func NewReplicationControllerList(c k8s.Connection, ns string) List {
return newList(
ns,
"rc",
NewReplicationController(c),
AllVerbsAccess|DescribeAccess,
)
}
// NewReplicationControllerListWithArgs returns a new resource list.
func NewReplicationControllerListWithArgs(ns string, res Resource) List {
return newList(ns, "rc", res, AllVerbsAccess|DescribeAccess)
// NewReplicationController instantiates a new ReplicationController.
func NewReplicationController(c k8s.Connection) *ReplicationController {
r := &ReplicationController{&Base{connection: c, resource: k8s.NewReplicationController(c)}, nil}
r.Factory = r
return r
}
// NewReplicationController instantiates a new Endpoint.
func NewReplicationController() *ReplicationController {
return NewReplicationControllerWithArgs(k8s.NewReplicationController())
}
// 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) {
// New builds a new ReplicationController instance from a k8s resource.
func (r *ReplicationController) New(i interface{}) Columnar {
c := NewReplicationController(r.connection)
switch instance := i.(type) {
case *v1.ReplicationController:
cm.instance = i.(*v1.ReplicationController)
c.instance = instance
case v1.ReplicationController:
ii := i.(v1.ReplicationController)
cm.instance = &ii
c.instance = &instance
default:
log.Fatal().Msgf("Unknown %#v", i)
log.Fatal().Msgf("unknown ReplicationController type %#v", i)
}
cm.path = cm.namespacedName(cm.instance.ObjectMeta)
return cm
c.path = c.namespacedName(c.instance.ObjectMeta)
return c
}
// Marshal a deployment given a namespaced name.
func (r *ReplicationController) Marshal(path string) (string, error) {
ns, n := namespaced(path)
i, err := r.caller.Get(ns, n)
i, err := r.resource.Get(ns, n)
if err != nil {
return "", err
}
@ -67,6 +59,7 @@ func (r *ReplicationController) Marshal(path string) (string, error) {
rc := i.(*v1.ReplicationController)
rc.TypeMeta.APIVersion = "v1"
rc.TypeMeta.Kind = "ReplicationController"
return r.marshalObject(rc)
}
@ -76,6 +69,7 @@ func (*ReplicationController) Header(ns string) Row {
if ns == AllNamespaces {
hh = append(hh, "NAMESPACE")
}
return append(hh, "NAME", "DESIRED", "CURRENT", "READY", "AGE")
}
@ -85,8 +79,8 @@ func (r *ReplicationController) Fields(ns string) Row {
if ns == AllNamespaces {
ff = append(ff, r.instance.Namespace)
}
i := r.instance
return append(ff,
i.Name,
strconv.Itoa(int(*i.Spec.Replicas)),
@ -95,8 +89,3 @@ func (r *ReplicationController) Fields(ns string) Row {
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.
func NewRoleList(ns string) List {
return NewRoleListWithArgs(ns, NewRole())
func NewRoleList(c k8s.Connection, ns string) List {
return newList(
ns,
"role",
NewRole(c),
AllVerbsAccess|DescribeAccess,
)
}
// NewRoleListWithArgs returns a new resource list.
func NewRoleListWithArgs(ns string, res Resource) List {
l := newList(ns, "role", res, AllVerbsAccess|DescribeAccess)
l.xray = true
return l
// NewRole instantiates a new Role.
func NewRole(c k8s.Connection) *Role {
r := &Role{&Base{connection: c, resource: k8s.NewRole(c)}, nil}
r.Factory = r
return r
}
// NewRole instantiates a new Endpoint.
func NewRole() *Role {
return NewRoleWithArgs(k8s.NewRole())
}
// 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) {
// New builds a new Role instance from a k8s resource.
func (r *Role) New(i interface{}) Columnar {
c := NewRole(r.connection)
switch instance := i.(type) {
case *v1.Role:
cm.instance = i.(*v1.Role)
c.instance = instance
case v1.Role:
ii := i.(v1.Role)
cm.instance = &ii
c.instance = &instance
default:
log.Fatal().Msgf("Unknown %#v", i)
log.Fatal().Msgf("unknown Role type %#v", i)
}
cm.path = cm.namespacedName(cm.instance.ObjectMeta)
return cm
c.path = c.namespacedName(c.instance.ObjectMeta)
return c
}
// Marshal resource to yaml.
func (r *Role) Marshal(path string) (string, error) {
ns, n := namespaced(path)
i, err := r.caller.Get(ns, n)
i, err := r.resource.Get(ns, n)
if err != nil {
return "", err
}
@ -69,6 +59,7 @@ func (r *Role) Marshal(path string) (string, error) {
role := i.(*v1.Role)
role.TypeMeta.APIVersion = "rbac.authorization.k8s.io/v1"
role.TypeMeta.Kind = "Role"
return r.marshalObject(role)
}
@ -78,6 +69,7 @@ func (*Role) Header(ns string) Row {
if ns == AllNamespaces {
hh = append(hh, "NAMESPACE")
}
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...
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][3] = strings.Join(p.Verbs, ", ")
}
return acc
}

View File

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

View File

@ -41,7 +41,6 @@ func TestRBListData(t *testing.T) {
td := l.Data()
assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, "blee", l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"]
assert.Equal(t, 4, len(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])
}
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...
func k8sRB() *v1.RoleBinding {

View File

@ -41,7 +41,6 @@ func TestRoleListData(t *testing.T) {
td := l.Data()
assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, "blee", l.GetNamespace())
assert.True(t, l.HasXRay())
row := td.Rows["blee/fred"]
assert.Equal(t, 2, len(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])
}
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...
func k8sRole() *v1.Role {

View File

@ -15,51 +15,43 @@ type ReplicaSet struct {
}
// NewReplicaSetList returns a new resource list.
func NewReplicaSetList(ns string) List {
return NewReplicaSetListWithArgs(ns, NewReplicaSet())
func NewReplicaSetList(c k8s.Connection, ns string) List {
return newList(
ns,
"rs",
NewReplicaSet(c),
AllVerbsAccess|DescribeAccess,
)
}
// NewReplicaSetListWithArgs returns a new resource list.
func NewReplicaSetListWithArgs(ns string, res Resource) List {
return newList(ns, "rs", res, AllVerbsAccess|DescribeAccess)
// NewReplicaSet instantiates a new ReplicaSet.
func NewReplicaSet(c k8s.Connection) *ReplicaSet {
r := &ReplicaSet{&Base{connection: c, resource: k8s.NewReplicaSet(c)}, nil}
r.Factory = r
return r
}
// NewReplicaSet instantiates a new Endpoint.
func NewReplicaSet() *ReplicaSet {
return NewReplicaSetWithArgs(k8s.NewReplicaSet())
}
// 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) {
// New builds a new ReplicaSet instance from a k8s resource.
func (r *ReplicaSet) New(i interface{}) Columnar {
c := NewReplicaSet(r.connection)
switch instance := i.(type) {
case *v1.ReplicaSet:
cm.instance = i.(*v1.ReplicaSet)
c.instance = instance
case v1.ReplicaSet:
ii := i.(v1.ReplicaSet)
cm.instance = &ii
c.instance = &instance
default:
log.Fatal().Msgf("Unknown %#v", i)
log.Fatal().Msgf("unknown ReplicaSet type %#v", i)
}
cm.path = cm.namespacedName(cm.instance.ObjectMeta)
return cm
c.path = c.namespacedName(c.instance.ObjectMeta)
return c
}
// Marshal a deployment given a namespaced name.
func (r *ReplicaSet) Marshal(path string) (string, error) {
ns, n := namespaced(path)
i, err := r.caller.Get(ns, n)
i, err := r.resource.Get(ns, n)
if err != nil {
return "", err
}
@ -67,6 +59,7 @@ func (r *ReplicaSet) Marshal(path string) (string, error) {
rs := i.(*v1.ReplicaSet)
rs.TypeMeta.APIVersion = "extensions/v1beta"
rs.TypeMeta.Kind = "ReplicaSet"
return r.marshalObject(rs)
}
@ -76,6 +69,7 @@ func (*ReplicaSet) Header(ns string) Row {
if ns == AllNamespaces {
hh = append(hh, "NAMESPACE")
}
return append(hh, "NAME", "DESIRED", "CURRENT", "READY", "AGE")
}
@ -87,6 +81,7 @@ func (r *ReplicaSet) Fields(ns string) Row {
}
i := r.instance
return append(ff,
i.Name,
strconv.Itoa(int(*i.Spec.Replicas)),
@ -95,8 +90,3 @@ func (r *ReplicaSet) Fields(ns string) Row {
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()
assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, "blee", l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"]
assert.Equal(t, 5, len(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])
}
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...
func k8sReplicaSet() *v1.ReplicaSet {

View File

@ -15,51 +15,43 @@ type ServiceAccount struct {
}
// NewServiceAccountList returns a new resource list.
func NewServiceAccountList(ns string) List {
return NewServiceAccountListWithArgs(ns, NewServiceAccount())
func NewServiceAccountList(c k8s.Connection, ns string) List {
return newList(
ns,
"sa",
NewServiceAccount(c),
AllVerbsAccess|DescribeAccess,
)
}
// NewServiceAccountListWithArgs returns a new resource list.
func NewServiceAccountListWithArgs(ns string, res Resource) List {
return newList(ns, "sa", res, AllVerbsAccess|DescribeAccess)
// NewServiceAccount instantiates a new ServiceAccount.
func NewServiceAccount(c k8s.Connection) *ServiceAccount {
s := &ServiceAccount{&Base{connection: c, resource: k8s.NewServiceAccount(c)}, nil}
s.Factory = s
return s
}
// NewServiceAccount instantiates a new Endpoint.
func NewServiceAccount() *ServiceAccount {
return NewServiceAccountWithArgs(k8s.NewServiceAccount())
}
// 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) {
// New builds a new ServiceAccount instance from a k8s resource.
func (r *ServiceAccount) New(i interface{}) Columnar {
c := NewServiceAccount(r.connection)
switch instance := i.(type) {
case *v1.ServiceAccount:
cm.instance = i.(*v1.ServiceAccount)
c.instance = instance
case v1.ServiceAccount:
ii := i.(v1.ServiceAccount)
cm.instance = &ii
c.instance = &instance
default:
log.Fatal().Msgf("Unknown %#v", i)
log.Fatal().Msgf("unknown ServiceAccount type %#v", i)
}
cm.path = cm.namespacedName(cm.instance.ObjectMeta)
return cm
c.path = c.namespacedName(c.instance.ObjectMeta)
return c
}
// Marshal resource to yaml.
func (r *ServiceAccount) Marshal(path string) (string, error) {
ns, n := namespaced(path)
i, err := r.caller.Get(ns, n)
i, err := r.resource.Get(ns, n)
if err != nil {
return "", err
}
@ -67,6 +59,7 @@ func (r *ServiceAccount) Marshal(path string) (string, error) {
sa := i.(*v1.ServiceAccount)
sa.TypeMeta.APIVersion = "v1"
sa.TypeMeta.Kind = "ServiceAccount"
return r.marshalObject(sa)
}
@ -76,6 +69,7 @@ func (*ServiceAccount) Header(ns string) Row {
if ns == AllNamespaces {
hh = append(hh, "NAMESPACE")
}
return append(hh, "NAME", "SECRET", "AGE")
}
@ -93,8 +87,3 @@ func (r *ServiceAccount) Fields(ns string) Row {
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()
assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, resource.NotNamespaced, l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"]
assert.Equal(t, 3, len(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])
}
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...
func k8sSA() *v1.ServiceAccount {

View File

@ -1,10 +1,10 @@
package resource
import (
"log"
"strconv"
"github.com/derailed/k9s/internal/k8s"
"github.com/rs/zerolog/log"
v1 "k8s.io/api/core/v1"
)
@ -15,51 +15,43 @@ type Secret struct {
}
// NewSecretList returns a new resource list.
func NewSecretList(ns string) List {
return NewSecretListWithArgs(ns, NewSecret())
}
// NewSecretListWithArgs returns a new resource list.
func NewSecretListWithArgs(ns string, res Resource) List {
return newList(ns, "secret", res, AllVerbsAccess|DescribeAccess)
func NewSecretList(c k8s.Connection, ns string) List {
return newList(
ns,
"secret",
NewSecret(c),
AllVerbsAccess|DescribeAccess,
)
}
// NewSecret instantiates a new Secret.
func NewSecret() *Secret {
return NewSecretWithArgs(k8s.NewSecret())
func NewSecret(c k8s.Connection) *Secret {
s := &Secret{&Base{connection: c, resource: k8s.NewSecret(c)}, nil}
s.Factory = s
return s
}
// NewSecretWithArgs instantiates a new Secret.
func NewSecretWithArgs(r k8s.Res) *Secret {
cm := &Secret{
Base: &Base{
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) {
// New builds a new Secret instance from a k8s resource.
func (r *Secret) New(i interface{}) Columnar {
c := NewSecret(r.connection)
switch instance := i.(type) {
case *v1.Secret:
cm.instance = i.(*v1.Secret)
c.instance = instance
case v1.Secret:
ii := i.(v1.Secret)
cm.instance = &ii
c.instance = &instance
default:
log.Fatalf("Unknown %#v", i)
log.Fatal().Msgf("unknown Secret type %#v", i)
}
cm.path = cm.namespacedName(cm.instance.ObjectMeta)
return cm
c.path = c.namespacedName(c.instance.ObjectMeta)
return c
}
// Marshal resource to yaml.
func (r *Secret) Marshal(path string) (string, error) {
ns, n := namespaced(path)
i, err := r.caller.Get(ns, n)
i, err := r.resource.Get(ns, n)
if err != nil {
return "", err
}
@ -67,6 +59,7 @@ func (r *Secret) Marshal(path string) (string, error) {
sec := i.(*v1.Secret)
sec.TypeMeta.APIVersion = "v1"
sec.TypeMeta.Kind = "Secret"
return r.marshalObject(sec)
}
@ -76,6 +69,7 @@ func (*Secret) Header(ns string) Row {
if ns == AllNamespaces {
hh = append(hh, "NAMESPACE")
}
return append(hh, "NAME", "TYPE", "DATA", "AGE")
}
@ -94,8 +88,3 @@ func (r *Secret) Fields(ns string) Row {
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())
}
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) {
setup(t)
@ -147,7 +133,6 @@ func TestSecretListData(t *testing.T) {
assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, "blee", l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"]
assert.Equal(t, 4, len(row.Deltas))
for _, d := range row.Deltas {

View File

@ -15,51 +15,43 @@ type StatefulSet struct {
}
// NewStatefulSetList returns a new resource list.
func NewStatefulSetList(ns string) List {
return NewStatefulSetListWithArgs(ns, NewStatefulSet())
func NewStatefulSetList(c k8s.Connection, ns string) List {
return newList(
ns,
"sts",
NewStatefulSet(c),
AllVerbsAccess|DescribeAccess,
)
}
// NewStatefulSetListWithArgs returns a new resource list.
func NewStatefulSetListWithArgs(ns string, res Resource) List {
return newList(ns, "sts", res, AllVerbsAccess|DescribeAccess)
// NewStatefulSet instantiates a new StatefulSet.
func NewStatefulSet(c k8s.Connection) *StatefulSet {
s := &StatefulSet{&Base{connection: c, resource: k8s.NewStatefulSet(c)}, nil}
s.Factory = s
return s
}
// NewStatefulSet instantiates a new Endpoint.
func NewStatefulSet() *StatefulSet {
return NewStatefulSetWithArgs(k8s.NewStatefulSet())
}
// 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) {
// New builds a new StatefulSet instance from a k8s resource.
func (r *StatefulSet) New(i interface{}) Columnar {
c := NewStatefulSet(r.connection)
switch instance := i.(type) {
case *v1.StatefulSet:
cm.instance = i.(*v1.StatefulSet)
c.instance = instance
case v1.StatefulSet:
ii := i.(v1.StatefulSet)
cm.instance = &ii
c.instance = &instance
default:
log.Fatal().Msgf("Unknown %#v", i)
log.Fatal().Msgf("unknown StatefulSet type %#v", i)
}
cm.path = cm.namespacedName(cm.instance.ObjectMeta)
return cm
c.path = c.namespacedName(c.instance.ObjectMeta)
return c
}
// Marshal resource to yaml.
func (r *StatefulSet) Marshal(path string) (string, error) {
ns, n := namespaced(path)
i, err := r.caller.Get(ns, n)
i, err := r.resource.Get(ns, n)
if err != nil {
return "", err
}
@ -67,6 +59,7 @@ func (r *StatefulSet) Marshal(path string) (string, error) {
sts := i.(*v1.StatefulSet)
sts.TypeMeta.APIVersion = "v1"
sts.TypeMeta.Kind = "StatefulSet"
return r.marshalObject(sts)
}
@ -76,6 +69,7 @@ func (*StatefulSet) Header(ns string) Row {
if ns == AllNamespaces {
hh = append(hh, "NAMESPACE")
}
return append(hh, "NAME", "DESIRED", "CURRENT", "AGE")
}
@ -94,8 +88,3 @@ func (r *StatefulSet) Fields(ns string) Row {
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()
assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, "blee", l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"]
assert.Equal(t, 4, len(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])
}
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...
func k8sSTS() *v1.StatefulSet {

View File

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

View File

@ -86,7 +86,6 @@ func TestSVCListData(t *testing.T) {
td := l.Data()
assert.Equal(t, 1, len(td.Rows))
assert.Equal(t, "blee", l.GetNamespace())
assert.False(t, l.HasXRay())
row := td.Rows["blee/fred"]
assert.Equal(t, 6, len(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])
}
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...
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[KeySlash] = newKeyAction("Filter", v.activateCmd, false)
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())
v.cancel = cancel
@ -128,7 +128,7 @@ func (v *aliasView) hints() hints {
}
func (v *aliasView) hydrate() resource.TableData {
cmds := helpCmds()
cmds := helpCmds(v.app.conn())
data := resource.TableData{
Header: resource.Row{"NAME", "RESOURCE", "APIGROUP"},

View File

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

View File

@ -10,34 +10,37 @@ import (
type clusterInfoView struct {
*tview.Table
app *appView
app *appView
cluster *resource.Cluster
}
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() {
cluster := resource.NewCluster()
var row int
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++
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++
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++
v.SetCell(row, 0, v.sectionCell("K9s Rev"))
v.SetCell(row, 1, v.infoCell(v.app.version))
row++
rev := cluster.Version()
rev := v.cluster.Version()
v.SetCell(row, 0, v.sectionCell("K8s Rev"))
v.SetCell(row, 1, v.infoCell(rev))
row++
@ -67,24 +70,30 @@ func (*clusterInfoView) infoCell(t string) *tview.TableCell {
func (v *clusterInfoView) refresh() {
var row int
cluster := resource.NewCluster()
v.GetCell(row, 1).SetText(cluster.ContextName())
v.GetCell(row, 1).SetText(v.cluster.ContextName())
row++
v.GetCell(row, 1).SetText(cluster.ClusterName())
v.GetCell(row, 1).SetText(v.cluster.ClusterName())
row++
v.GetCell(row, 1).SetText(cluster.UserName())
v.GetCell(row, 1).SetText(v.cluster.UserName())
row += 2
v.GetCell(row, 1).SetText(cluster.Version())
v.GetCell(row, 1).SetText(v.cluster.Version())
row++
mx, err := cluster.Metrics()
nodes, err := v.cluster.GetNodes()
if err != nil {
log.Warn().Msgf("%s", err)
log.Warn().Msgf("ClusterInfo %s", err)
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.SetText(deltas(c.Text, mx.CPU))
c.SetText(deltas(c.Text, toPerc(mx.PercCPU)))
row++
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 (
"fmt"
"github.com/derailed/k9s/internal/config"
"github.com/derailed/k9s/internal/resource"
"github.com/rs/zerolog/log"
)
type command struct {
@ -29,14 +29,20 @@ func (c *command) previousCmd() (string, bool) {
// DefaultCmd reset default command ie show pods.
func (c *command) defaultCmd() {
c.pushCmd(config.Root.ActiveView())
c.run(config.Root.ActiveView())
c.pushCmd(c.app.config.ActiveView())
c.run(c.app.config.ActiveView())
}
// Helpers...
// Exec the command by showing associated display.
func (c *command) run(cmd string) bool {
defer func() {
if err := recover(); err != nil {
log.Debug().Msgf("Command failed %v", err)
}
}()
var v igniter
switch cmd {
case "q", "quit":
@ -47,14 +53,14 @@ func (c *command) run(cmd string) bool {
return true
default:
if res, ok := resourceViews()[cmd]; ok {
v = res.viewFn(res.title, c.app, res.listFn(resource.DefaultNamespace), res.colorerFn)
c.app.flash(flashInfo, fmt.Sprintf("Viewing %s in namespace %s...", res.title, config.Root.ActiveNamespace()))
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, c.app.config.ActiveNamespace()))
c.exec(cmd, v)
return true
}
}
res, ok := allCRDs()[cmd]
res, ok := allCRDs(c.app.conn())[cmd]
if !ok {
c.app.flash(flashWarn, fmt.Sprintf("Huh? `%s` command not found", cmd))
return false
@ -67,7 +73,7 @@ func (c *command) run(cmd string) bool {
v = newResourceView(
res.Kind,
c.app,
resource.NewCustomList("", res.Group, res.Version, n),
resource.NewCustomList(c.app.conn(), "", res.Group, res.Version, n),
defaultColorer,
)
c.exec(cmd, v)
@ -76,8 +82,8 @@ func (c *command) run(cmd string) bool {
func (c *command) exec(cmd string, v igniter) {
if v != nil {
config.Root.SetActiveView(cmd)
config.Root.Save()
c.app.config.SetActiveView(cmd)
c.app.config.Save()
c.app.inject(v)
}
}

View File

@ -3,7 +3,6 @@ package views
import (
"strings"
"github.com/derailed/k9s/internal/config"
"github.com/derailed/k9s/internal/resource"
"github.com/gdamore/tcell"
)
@ -57,8 +56,8 @@ func (v *contextView) useContext(name string) error {
return err
}
config.Root.Reset()
config.Root.Save()
v.app.config.Reset()
v.app.config.Save()
v.app.flash(flashInfo, "Switching context to", ctx)
v.refresh()
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.SetTextAlign(tview.AlignLeft)
f.SetBorderPadding(0, 0, 1, 1)
f.SetText(m)
f.SetText("")
}
return &f
}

View File

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

View File

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

View File

@ -6,7 +6,6 @@ import (
"strconv"
"time"
"github.com/derailed/k9s/internal/config"
"github.com/derailed/k9s/internal/resource"
"github.com/derailed/tview"
"github.com/gdamore/tcell"
@ -163,7 +162,7 @@ func (v *logsView) doLoad(path, co string) error {
if !ok {
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)
if err != nil {
cancelFn()

View File

@ -8,6 +8,7 @@ import (
"github.com/derailed/k9s/internal/k8s"
"github.com/derailed/k9s/internal/resource"
"github.com/gdamore/tcell"
"github.com/rs/zerolog/log"
)
const (
@ -55,12 +56,12 @@ func (v *namespaceView) useNsCmd(evt *tcell.EventKey) *tcell.EventKey {
}
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())
} else {
v.app.flash(flashInfo, fmt.Sprintf("Namespace %s is now active!", name))
}
config.Root.Save()
v.app.config.Save()
}
func (v *namespaceView) getSelectedItem() string {
@ -73,7 +74,7 @@ func (*namespaceView) cleanser(s string) string {
func (v *namespaceView) decorate(data resource.TableData) resource.TableData {
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{
Action: resource.Unchanged,
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 {
if config.InList(config.Root.FavNamespaces(), k) {
v.Fields[0] += "+"
v.Action = resource.Unchanged
for k, r := range data.Rows {
if config.InList(v.app.config.FavNamespaces(), k) {
r.Fields[0] += "+"
r.Action = resource.Unchanged
}
if config.Root.ActiveNamespace() == k {
v.Fields[0] += "(*)"
v.Action = resource.Unchanged
if v.app.config.ActiveNamespace() == k {
r.Fields[0] += "(*)"
r.Action = resource.Unchanged
}
}
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 (
"fmt"
"github.com/derailed/k9s/internal/config"
"github.com/derailed/k9s/internal/resource"
"github.com/gdamore/tcell"
"github.com/rs/zerolog/log"
@ -113,7 +112,7 @@ func (v *podView) shellIn(path, co string) {
ns, po := namespaced(path)
args := make([]string, 0, 12)
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, po)
if len(co) != 0 {
@ -129,7 +128,7 @@ func (v *podView) showLogs(path, co string, previous bool) {
args := make([]string, 0, 10)
args = append(args, "logs", "-f")
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 {
args = append(args, "-c", co)
v.app.flash(flashInfo, fmt.Sprintf("Viewing logs from container %s on pod %s", co, po))

View File

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

View File

@ -88,7 +88,7 @@ func (v *resourceView) init(ctx context.Context, ns string) {
return
case <-time.After(time.Duration(initTick) * time.Second):
v.refresh()
initTick = float64(config.Root.K9s.RefreshRate)
initTick = float64(v.app.config.K9s.RefreshRate)
}
}
}(ctx)
@ -170,10 +170,10 @@ func (v *resourceView) describeCmd(evt *tcell.EventKey) *tcell.EventKey {
return evt
}
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 {
v.app.flash(flashErr, err.Error())
log.Warn().Msg(err.Error())
log.Warn().Msgf("Describe %v", err.Error())
return evt
}
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, v.list.GetName())
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)
runK(v.app, args...)
return evt
@ -249,8 +249,8 @@ func (v *resourceView) doSwitchNamespace(ns string) {
v.getTV().resetTitle()
v.getTV().Select(0, 0)
v.app.cmdBuff.reset()
config.Root.SetActiveNamespace(v.selectedNS)
config.Root.Save()
v.app.config.SetActiveNamespace(v.selectedNS)
v.app.config.Save()
}
func (v *resourceView) refresh() {
@ -264,7 +264,7 @@ func (v *resourceView) refresh() {
v.list.SetNamespace(v.selectedNS)
}
if err := v.list.Reconcile(); err != nil {
log.Warn().Msgf("%s", err)
log.Warn().Msgf("Reconcile %v", err)
v.app.flash(flashErr, err.Error())
}
data := v.list.Data()
@ -338,11 +338,11 @@ func (v *resourceView) refreshActions() {
var nn []interface{}
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
nn, err = k8s.NewNamespace().List(resource.AllNamespaces)
nn, err = k8s.NewNamespace(v.app.conn()).List(resource.AllNamespaces)
if err != nil {
log.Warn().Msgf("%s", err)
log.Warn().Msgf("Access %v", err)
v.app.flash(flashErr, err.Error())
}
@ -354,7 +354,7 @@ func (v *resourceView) refreshActions() {
if v.list.Access(resource.NamespaceAccess) {
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)
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) {
v.currentNS = data.Namespace
if v.currentNS == resource.AllNamespaces {
v.actions[KeyShiftG] = newKeyAction("Sort Namespace", v.sortNamespaceCmd, true)
v.actions[KeyShiftS] = newKeyAction("Sort Namespace", v.sortNamespaceCmd, true)
} else {
delete(v.actions, KeyShiftS)
}
@ -308,9 +308,14 @@ func (v *tableView) doUpdate(data resource.TableData) {
}
row++
// for k := range data.Rows {
// log.Debug().Msgf("Keys: %s", k)
// }
keys := v.sortRows(data)
groupKeys := map[string][]string{}
for _, k := range keys {
// log.Debug().Msgf("RKEY: %s", k)
grp := data.Rows[k].Fields[v.sortCol.index]
if s, ok := groupKeys[grp]; ok {
s = append(s, k)