parent
0249f7cf2c
commit
34eab38afb
2
Makefile
2
Makefile
|
|
@ -5,7 +5,7 @@ PACKAGE := github.com/derailed/$(NAME)
|
||||||
GIT_REV ?= $(shell git rev-parse --short HEAD)
|
GIT_REV ?= $(shell git rev-parse --short HEAD)
|
||||||
SOURCE_DATE_EPOCH ?= $(shell date +%s)
|
SOURCE_DATE_EPOCH ?= $(shell date +%s)
|
||||||
DATE ?= $(shell date -u -d @${SOURCE_DATE_EPOCH} +"%Y-%m-%dT%H:%M:%SZ")
|
DATE ?= $(shell date -u -d @${SOURCE_DATE_EPOCH} +"%Y-%m-%dT%H:%M:%SZ")
|
||||||
VERSION ?= v0.25.8
|
VERSION ?= v0.25.9
|
||||||
IMG_NAME := derailed/k9s
|
IMG_NAME := derailed/k9s
|
||||||
IMAGE := ${IMG_NAME}:${VERSION}
|
IMAGE := ${IMG_NAME}:${VERSION}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -883,4 +883,4 @@ We always enjoy hearing from folks who benefit from our work!
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<img src="assets/imhotep_logo.png" width="32" height="auto" alt="Imhotep"/> © 2020 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
|
<img src="assets/imhotep_logo.png" width="32" height="auto" alt="Imhotep"/> © 2021 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
<img src="https://raw.githubusercontent.com/derailed/k9s/master/assets/k9s_small.png" align="right" width="200" height="auto"/>
|
||||||
|
|
||||||
|
# Release v0.25.9
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
Thank you to all that contributed with flushing out issues and enhancements for K9s! I'll try to mark some of these issues as fixed. But if you don't mind grab the latest rev and see if we're happier with some of the fixes! If you've filed an issue please help me verify and close. Your support, kindness and awesome suggestions to make K9s better are as ever very much noted and appreciated!
|
||||||
|
|
||||||
|
If you feel K9s is helping your Kubernetes journey, please consider joining our [sponsorship program](https://github.com/sponsors/derailed) and/or make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
|
||||||
|
|
||||||
|
On Slack? Please join us [K9slackers](https://join.slack.com/t/k9sers/shared_invite/enQtOTA5MDEyNzI5MTU0LWQ1ZGI3MzliYzZhZWEyNzYxYzA3NjE0YTk1YmFmNzViZjIyNzhkZGI0MmJjYzhlNjdlMGJhYzE2ZGU1NjkyNTM)
|
||||||
|
|
||||||
|
### A Word From Our Sponsors...
|
||||||
|
|
||||||
|
I want to recognize the following folks that have been kind enough to join our sponsorship program and opted to `pay it forward`!
|
||||||
|
|
||||||
|
* [Joshua Kapellen](https://github.com/joshuakapellen)
|
||||||
|
* [Qdentity](https://github.com/qdentity)
|
||||||
|
* [Maxim](https://github.com/bsod90)
|
||||||
|
* [Sönke Schau](https://github.com/xgcssch)
|
||||||
|
|
||||||
|
So if you feel K9s is helping with your productivity while administering your Kubernetes clusters, please consider pitching in as it will go a long way in ensuring a thriving environment for this repo and our k9ers community at large.
|
||||||
|
|
||||||
|
Also please take some time and give a huge shoot out to all the good folks below that have spent time plowing thru the code to help improve K9s for all of us!
|
||||||
|
|
||||||
|
Thank you!!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Maintenance Release!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Resolved Issues
|
||||||
|
|
||||||
|
* [Issue #1361](https://github.com/derailed/k9s/issues/1361) Pulses not displaying graphs
|
||||||
|
* [Issue #1358](https://github.com/derailed/k9s/issues/1358) Namespace list is empty
|
||||||
|
* [Issue #1357](https://github.com/derailed/k9s/issues/1357) Benchmarks doesn't work on windows
|
||||||
|
* [Issue #1355](https://github.com/derailed/k9s/issues/1355) Trace log level does not exists
|
||||||
|
* [Issue #1345](https://github.com/derailed/k9s/issues/1345) Access denied after context switch
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## PRs
|
||||||
|
|
||||||
|
* [PR #1363](https://github.com/derailed/k9s/pull/1363) Add rose-pine skin.
|
||||||
|
[Sergio Soria](https://github.com/sasoria)
|
||||||
|
* [PR #1356](https://github.com/derailed/k9s/pull/1356) Add flux trace shortcut to flux plugin.
|
||||||
|
[Guillaume Berche](https://github.com/gberche-orange)
|
||||||
|
* [PR #1321](https://github.com/derailed/k9s/pull/1321) Add customizable dump directory property.
|
||||||
|
[Vlasov Artem](https://github.com/VlasovArtem)
|
||||||
|
|
||||||
|
|
||||||
|
<img src="https://raw.githubusercontent.com/derailed/k9s/master/assets/imhotep_logo.png" width="32" height="auto"/> © 2021 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
|
@ -161,7 +161,7 @@ func initK9sFlags() {
|
||||||
k9sFlags.LogLevel,
|
k9sFlags.LogLevel,
|
||||||
"logLevel", "l",
|
"logLevel", "l",
|
||||||
config.DefaultLogLevel,
|
config.DefaultLogLevel,
|
||||||
"Specify a log level (info, warn, debug, error, fatal, panic, trace)",
|
"Specify a log level (info, warn, debug, error)",
|
||||||
)
|
)
|
||||||
rootCmd.Flags().StringVarP(
|
rootCmd.Flags().StringVarP(
|
||||||
k9sFlags.LogFile,
|
k9sFlags.LogFile,
|
||||||
|
|
@ -221,7 +221,7 @@ func initK9sFlags() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func initK8sFlags() {
|
func initK8sFlags() {
|
||||||
k8sFlags = genericclioptions.NewConfigFlags(false)
|
k8sFlags = genericclioptions.NewConfigFlags(client.UsePersistentConfig)
|
||||||
|
|
||||||
rootCmd.Flags().StringVar(
|
rootCmd.Flags().StringVar(
|
||||||
k8sFlags.KubeConfig,
|
k8sFlags.KubeConfig,
|
||||||
|
|
|
||||||
|
|
@ -15,14 +15,15 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
defaultCallTimeoutDuration time.Duration = 5 * time.Second
|
defaultCallTimeoutDuration time.Duration = 10 * time.Second
|
||||||
|
|
||||||
|
// UsePersistentConfig caches client config to avoid reloads.
|
||||||
|
UsePersistentConfig = true
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config tracks a kubernetes configuration.
|
// Config tracks a kubernetes configuration.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
flags *genericclioptions.ConfigFlags
|
flags *genericclioptions.ConfigFlags
|
||||||
clientCfg clientcmd.ClientConfig
|
|
||||||
rawCfg *clientcmdapi.Config
|
|
||||||
mutex *sync.RWMutex
|
mutex *sync.RWMutex
|
||||||
OverrideNS bool
|
OverrideNS bool
|
||||||
}
|
}
|
||||||
|
|
@ -58,60 +59,35 @@ func (c *Config) Flags() *genericclioptions.ConfigFlags {
|
||||||
return c.flags
|
return c.flags
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) rawConfig() (*clientcmdapi.Config, error) {
|
func (c *Config) RawConfig() (clientcmdapi.Config, error) {
|
||||||
if c.rawCfg != nil {
|
return c.clientConfig().RawConfig()
|
||||||
return c.rawCfg, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg, err := c.clientConfig().RawConfig()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
c.rawCfg = &cfg
|
|
||||||
|
|
||||||
return c.rawCfg, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) clientConfig() clientcmd.ClientConfig {
|
func (c *Config) clientConfig() clientcmd.ClientConfig {
|
||||||
if c.clientCfg != nil {
|
return c.flags.ToRawKubeConfigLoader()
|
||||||
return c.clientCfg
|
|
||||||
}
|
|
||||||
c.clientCfg = c.flags.ToRawKubeConfigLoader()
|
|
||||||
|
|
||||||
return c.clientCfg
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) reset() {
|
func (c *Config) reset() {}
|
||||||
c.clientCfg, c.rawCfg = nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SwitchContext changes the kubeconfig context to a new cluster.
|
// SwitchContext changes the kubeconfig context to a new cluster.
|
||||||
func (c *Config) SwitchContext(name string) error {
|
func (c *Config) SwitchContext(name string) error {
|
||||||
if n, err := c.CurrentContextName(); err == nil && n == name {
|
if _, err := c.GetContext(name); err != nil {
|
||||||
return nil
|
|
||||||
}
|
|
||||||
context, err := c.GetContext(name)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("context %q does not exist", name)
|
return fmt.Errorf("context %q does not exist", name)
|
||||||
}
|
}
|
||||||
c.flags.Namespace = &context.Namespace
|
flags := genericclioptions.NewConfigFlags(UsePersistentConfig)
|
||||||
c.flags.Context = &name
|
flags.Context = &name
|
||||||
c.flags.ClusterName = &(context.Cluster)
|
flags.Timeout = c.flags.Timeout
|
||||||
c.reset()
|
c.flags = flags
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) RawConfig() *clientcmdapi.Config {
|
|
||||||
return c.rawCfg
|
|
||||||
}
|
|
||||||
|
|
||||||
// CurrentContextName returns the currently active config context.
|
// CurrentContextName returns the currently active config context.
|
||||||
func (c *Config) CurrentContextName() (string, error) {
|
func (c *Config) CurrentContextName() (string, error) {
|
||||||
if isSet(c.flags.Context) {
|
if isSet(c.flags.Context) {
|
||||||
return *c.flags.Context, nil
|
return *c.flags.Context, nil
|
||||||
}
|
}
|
||||||
cfg, err := c.rawConfig()
|
cfg, err := c.RawConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
@ -121,7 +97,7 @@ func (c *Config) CurrentContextName() (string, error) {
|
||||||
|
|
||||||
// GetContext fetch a given context or error if it does not exists.
|
// GetContext fetch a given context or error if it does not exists.
|
||||||
func (c *Config) GetContext(n string) (*clientcmdapi.Context, error) {
|
func (c *Config) GetContext(n string) (*clientcmdapi.Context, error) {
|
||||||
cfg, err := c.rawConfig()
|
cfg, err := c.RawConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -134,7 +110,7 @@ func (c *Config) GetContext(n string) (*clientcmdapi.Context, error) {
|
||||||
|
|
||||||
// Contexts fetch all available contexts.
|
// Contexts fetch all available contexts.
|
||||||
func (c *Config) Contexts() (map[string]*clientcmdapi.Context, error) {
|
func (c *Config) Contexts() (map[string]*clientcmdapi.Context, error) {
|
||||||
cfg, err := c.rawConfig()
|
cfg, err := c.RawConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -144,7 +120,7 @@ func (c *Config) Contexts() (map[string]*clientcmdapi.Context, error) {
|
||||||
|
|
||||||
// DelContext remove a given context from the configuration.
|
// DelContext remove a given context from the configuration.
|
||||||
func (c *Config) DelContext(n string) error {
|
func (c *Config) DelContext(n string) error {
|
||||||
cfg, err := c.rawConfig()
|
cfg, err := c.RawConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -155,12 +131,12 @@ func (c *Config) DelContext(n string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return clientcmd.ModifyConfig(acc, *cfg, true)
|
return clientcmd.ModifyConfig(acc, cfg, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContextNames fetch all available contexts.
|
// ContextNames fetch all available contexts.
|
||||||
func (c *Config) ContextNames() ([]string, error) {
|
func (c *Config) ContextNames() ([]string, error) {
|
||||||
cfg, err := c.rawConfig()
|
cfg, err := c.RawConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -174,7 +150,7 @@ func (c *Config) ContextNames() ([]string, error) {
|
||||||
|
|
||||||
// ClusterNameFromContext returns the cluster associated with the given context.
|
// ClusterNameFromContext returns the cluster associated with the given context.
|
||||||
func (c *Config) ClusterNameFromContext(context string) (string, error) {
|
func (c *Config) ClusterNameFromContext(context string) (string, error) {
|
||||||
cfg, err := c.rawConfig()
|
cfg, err := c.RawConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
@ -190,7 +166,7 @@ func (c *Config) CurrentClusterName() (string, error) {
|
||||||
if isSet(c.flags.ClusterName) {
|
if isSet(c.flags.ClusterName) {
|
||||||
return *c.flags.ClusterName, nil
|
return *c.flags.ClusterName, nil
|
||||||
}
|
}
|
||||||
cfg, err := c.rawConfig()
|
cfg, err := c.RawConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
@ -208,7 +184,7 @@ func (c *Config) CurrentClusterName() (string, error) {
|
||||||
|
|
||||||
// ClusterNames fetch all kubeconfig defined clusters.
|
// ClusterNames fetch all kubeconfig defined clusters.
|
||||||
func (c *Config) ClusterNames() ([]string, error) {
|
func (c *Config) ClusterNames() ([]string, error) {
|
||||||
cfg, err := c.rawConfig()
|
cfg, err := c.RawConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -258,7 +234,7 @@ func (c *Config) CurrentUserName() (string, error) {
|
||||||
return *c.flags.AuthInfoName, nil
|
return *c.flags.AuthInfoName, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err := c.rawConfig()
|
cfg, err := c.RawConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
@ -276,8 +252,8 @@ func (c *Config) CurrentUserName() (string, error) {
|
||||||
|
|
||||||
// CurrentNamespaceName retrieves the active namespace.
|
// CurrentNamespaceName retrieves the active namespace.
|
||||||
func (c *Config) CurrentNamespaceName() (string, error) {
|
func (c *Config) CurrentNamespaceName() (string, error) {
|
||||||
ns, _, err := c.clientConfig().Namespace()
|
ns, ov, err := c.clientConfig().Namespace()
|
||||||
|
fmt.Printf("!!!ZOB!!! %q -- %t\n", ns, ov)
|
||||||
return ns, err
|
return ns, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -146,6 +146,14 @@ func (c *Config) ActiveNamespace() string {
|
||||||
cl = NewCluster()
|
cl = NewCluster()
|
||||||
c.K9s.Clusters[c.K9s.CurrentCluster] = cl
|
c.K9s.Clusters[c.K9s.CurrentCluster] = cl
|
||||||
}
|
}
|
||||||
|
if ns, err := c.settings.CurrentNamespaceName(); err == nil && ns != "" {
|
||||||
|
if cl.Namespace == nil {
|
||||||
|
cl.Namespace = NewNamespace()
|
||||||
|
}
|
||||||
|
cl.Namespace.Active = ns
|
||||||
|
return ns
|
||||||
|
}
|
||||||
|
|
||||||
if cl.Namespace != nil {
|
if cl.Namespace != nil {
|
||||||
return cl.Namespace.Active
|
return cl.Namespace.Active
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -60,8 +60,7 @@ func TestConfigRefine(t *testing.T) {
|
||||||
t.Run(k, func(t *testing.T) {
|
t.Run(k, func(t *testing.T) {
|
||||||
mc := NewMockConnection()
|
mc := NewMockConnection()
|
||||||
m.When(mc.ValidNamespaces()).ThenReturn(namespaces(), nil)
|
m.When(mc.ValidNamespaces()).ThenReturn(namespaces(), nil)
|
||||||
mk := NewMockKubeSettings()
|
mk := newMockSettings(u.flags)
|
||||||
m.When(mk.NamespaceNames(namespaces())).ThenReturn([]string{"default"})
|
|
||||||
cfg := config.NewConfig(mk)
|
cfg := config.NewConfig(mk)
|
||||||
|
|
||||||
err := cfg.Refine(u.flags, nil, client.NewConfig(u.flags))
|
err := cfg.Refine(u.flags, nil, client.NewConfig(u.flags))
|
||||||
|
|
@ -256,6 +255,24 @@ func TestSetup(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type mockSettings struct {
|
||||||
|
flags *genericclioptions.ConfigFlags
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ config.KubeSettings = (*mockSettings)(nil)
|
||||||
|
|
||||||
|
func newMockSettings(flags *genericclioptions.ConfigFlags) *mockSettings {
|
||||||
|
return &mockSettings{flags: flags}
|
||||||
|
}
|
||||||
|
func (m *mockSettings) CurrentContextName() (string, error) {
|
||||||
|
return *m.flags.Context, nil
|
||||||
|
}
|
||||||
|
func (m *mockSettings) CurrentClusterName() (string, error) { return "", nil }
|
||||||
|
func (m *mockSettings) CurrentNamespaceName() (string, error) {
|
||||||
|
return *m.flags.Namespace, nil
|
||||||
|
}
|
||||||
|
func (m *mockSettings) ClusterNames() ([]string, error) { return nil, nil }
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Test Data...
|
// Test Data...
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,11 @@ package dao
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/derailed/k9s/internal/client"
|
"github.com/derailed/k9s/internal/client"
|
||||||
"github.com/derailed/k9s/internal/render"
|
"github.com/derailed/k9s/internal/render"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/client-go/tools/clientcmd"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -61,17 +59,3 @@ func (c *Context) MustCurrentContextName() string {
|
||||||
func (c *Context) Switch(ctx string) error {
|
func (c *Context) Switch(ctx string) error {
|
||||||
return c.Factory.Client().SwitchContext(ctx)
|
return c.Factory.Client().SwitchContext(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// KubeUpdate modifies kubeconfig default context.
|
|
||||||
func (c *Context) KubeUpdate(n string) error {
|
|
||||||
cfg := c.config().RawConfig()
|
|
||||||
if cfg == nil {
|
|
||||||
return errors.New("unable to fetch raw config")
|
|
||||||
}
|
|
||||||
if err := c.Switch(n); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return clientcmd.ModifyConfig(
|
|
||||||
clientcmd.NewDefaultPathOptions(), *cfg, true,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/derailed/k9s/internal/health"
|
"github.com/derailed/k9s/internal/health"
|
||||||
"github.com/derailed/k9s/internal/render"
|
"github.com/derailed/k9s/internal/render"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -98,7 +99,11 @@ func (h *PulseHealth) checkMetrics(ctx context.Context) (health.Checks, error) {
|
||||||
func (h *PulseHealth) check(ctx context.Context, ns, gvr string) (*health.Check, error) {
|
func (h *PulseHealth) check(ctx context.Context, ns, gvr string) (*health.Check, error) {
|
||||||
meta, ok := Registry[gvr]
|
meta, ok := Registry[gvr]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("No meta for %q", gvr)
|
meta = ResourceMeta{
|
||||||
|
DAO: &dao.Table{},
|
||||||
|
Renderer: &render.Generic{},
|
||||||
|
}
|
||||||
|
// return nil, fmt.Errorf("No meta for %q", gvr)
|
||||||
}
|
}
|
||||||
if meta.DAO == nil {
|
if meta.DAO == nil {
|
||||||
meta.DAO = &dao.Resource{}
|
meta.DAO = &dao.Resource{}
|
||||||
|
|
@ -109,8 +114,29 @@ func (h *PulseHealth) check(ctx context.Context, ns, gvr string) (*health.Check,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
c := health.NewCheck(gvr)
|
c := health.NewCheck(gvr)
|
||||||
|
|
||||||
|
if _, ok := meta.Renderer.(*render.Generic); ok {
|
||||||
|
table, ok := oo[0].(*metav1beta1.Table)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("expecting a meta table but got %T", oo[0])
|
||||||
|
}
|
||||||
|
rows := make(render.Rows, len(table.Rows))
|
||||||
|
gr, _ := meta.Renderer.(*render.Generic)
|
||||||
|
gr.SetTable(table)
|
||||||
|
for i, row := range table.Rows {
|
||||||
|
if err := gr.Render(row, ns, &rows[i]); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !render.Happy(ns, gr.Header(ns), rows[i]) {
|
||||||
|
c.Inc(health.S2)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
c.Inc(health.S1)
|
||||||
|
}
|
||||||
|
c.Total(int64(len(table.Rows)))
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
c.Total(int64(len(oo)))
|
c.Total(int64(len(oo)))
|
||||||
rr, re := make(render.Rows, len(oo)), meta.Renderer
|
rr, re := make(render.Rows, len(oo)), meta.Renderer
|
||||||
for i, o := range oo {
|
for i, o := range oo {
|
||||||
|
|
@ -119,9 +145,9 @@ func (h *PulseHealth) check(ctx context.Context, ns, gvr string) (*health.Check,
|
||||||
}
|
}
|
||||||
if !render.Happy(ns, re.Header(ns), rr[i]) {
|
if !render.Happy(ns, re.Header(ns), rr[i]) {
|
||||||
c.Inc(health.S2)
|
c.Inc(health.S2)
|
||||||
} else {
|
continue
|
||||||
c.Inc(health.S1)
|
|
||||||
}
|
}
|
||||||
|
c.Inc(health.S1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c, nil
|
return c, nil
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -24,8 +25,13 @@ const (
|
||||||
k9sUA = "k9s/"
|
k9sUA = "k9s/"
|
||||||
)
|
)
|
||||||
|
|
||||||
// K9sBenchDir directory to store K9s Benchmark files.
|
|
||||||
var K9sBenchDir = filepath.Join(os.TempDir(), fmt.Sprintf("k9s-bench-%s", config.MustK9sUser()))
|
var (
|
||||||
|
// K9sBenchDir directory to store K9s Benchmark files.
|
||||||
|
K9sBenchDir = filepath.Join(os.TempDir(), fmt.Sprintf("k9s-bench-%s", config.MustK9sUser()))
|
||||||
|
|
||||||
|
pathRx = regexp.MustCompile(`[:|]+`)
|
||||||
|
)
|
||||||
|
|
||||||
// Benchmark puts a workload under load.
|
// Benchmark puts a workload under load.
|
||||||
type Benchmark struct {
|
type Benchmark struct {
|
||||||
|
|
@ -126,7 +132,7 @@ func (b *Benchmark) save(cluster string, r io.Reader) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
ns, n := client.Namespaced(b.config.Name)
|
ns, n := client.Namespaced(b.config.Name)
|
||||||
file := filepath.Join(dir, fmt.Sprintf(benchFmat, ns, n, time.Now().UnixNano()))
|
file := filepath.Join(dir, fmt.Sprintf(benchFmat, ns, pathRx.ReplaceAllString(n, "_"), time.Now().UnixNano()))
|
||||||
f, err := os.Create(file)
|
f, err := os.Create(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,10 @@ func TestPortForwardRender(t *testing.T) {
|
||||||
|
|
||||||
type fwd struct{}
|
type fwd struct{}
|
||||||
|
|
||||||
|
func (f fwd) ID() string {
|
||||||
|
return "blee/fred"
|
||||||
|
}
|
||||||
|
|
||||||
func (f fwd) Path() string {
|
func (f fwd) Path() string {
|
||||||
return "blee/fred"
|
return "blee/fred"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,10 @@ import (
|
||||||
|
|
||||||
// Forwarder represents a port forwarder.
|
// Forwarder represents a port forwarder.
|
||||||
type Forwarder interface {
|
type Forwarder interface {
|
||||||
// Path returns a resource FQN.
|
// ID returns the PF FQN.
|
||||||
|
ID() string
|
||||||
|
|
||||||
|
// Path returns a resource path.
|
||||||
Path() string
|
Path() string
|
||||||
|
|
||||||
// Container returns a container name.
|
// Container returns a container name.
|
||||||
|
|
@ -61,9 +64,9 @@ func (f PortForward) Render(o interface{}, gvr string, r *Row) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
ports := strings.Split(pf.Port(), ":")
|
ports := strings.Split(pf.Port(), ":")
|
||||||
ns, n := client.Namespaced(pf.Path())
|
ns, n := client.Namespaced(pf.ID())
|
||||||
|
|
||||||
r.ID = pf.Path()
|
r.ID = pf.ID()
|
||||||
r.Fields = Fields{
|
r.Fields = Fields{
|
||||||
ns,
|
ns,
|
||||||
trimContainer(n),
|
trimContainer(n),
|
||||||
|
|
|
||||||
|
|
@ -409,10 +409,11 @@ func (a *App) switchCtx(name string, loadPods bool) error {
|
||||||
v = "pod"
|
v = "pod"
|
||||||
a.Config.SetActiveView(v)
|
a.Config.SetActiveView(v)
|
||||||
}
|
}
|
||||||
|
a.Config.Reset()
|
||||||
|
a.Config.K9s.CurrentContext = name
|
||||||
if err := a.Config.Save(); err != nil {
|
if err := a.Config.Save(); err != nil {
|
||||||
log.Error().Err(err).Msg("Config save failed!")
|
log.Error().Err(err).Msg("Config save failed!")
|
||||||
}
|
}
|
||||||
a.Config.Reset()
|
|
||||||
|
|
||||||
a.Flash().Infof("Switching context to %s", name)
|
a.Flash().Infof("Switching context to %s", name)
|
||||||
a.ReloadStyles(name)
|
a.ReloadStyles(name)
|
||||||
|
|
@ -632,7 +633,7 @@ func (a *App) gotoResource(cmd, path string, clearStack bool) {
|
||||||
func (a *App) inject(c model.Component) error {
|
func (a *App) inject(c model.Component) error {
|
||||||
ctx := context.WithValue(context.Background(), internal.KeyApp, a)
|
ctx := context.WithValue(context.Background(), internal.KeyApp, a)
|
||||||
if err := c.Init(ctx); err != nil {
|
if err := c.Init(ctx); err != nil {
|
||||||
log.Error().Err(err).Msgf("component init failed for %q %v", c.Name(), err)
|
log.Error().Err(err).Msgf("component init failed for %q", c.Name())
|
||||||
dialog.ShowError(a.Styles.Dialog(), a.Content.Pages, err.Error())
|
dialog.ShowError(a.Styles.Dialog(), a.Content.Pages, err.Error())
|
||||||
}
|
}
|
||||||
a.Content.Push(c)
|
a.Content.Push(c)
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,6 @@ func (p *PortForwardExtender) portFwdCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||||
return evt
|
return evt
|
||||||
}
|
}
|
||||||
|
|
||||||
p.fetchPodName(path)
|
|
||||||
pod, err := fetchPod(p.App().factory, path)
|
pod, err := fetchPod(p.App().factory, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.App().Flash().Err(err)
|
p.App().Flash().Err(err)
|
||||||
|
|
|
||||||
|
|
@ -245,7 +245,7 @@ func (f *Factory) AddForwarder(pf Forwarder) {
|
||||||
f.mx.Lock()
|
f.mx.Lock()
|
||||||
defer f.mx.Unlock()
|
defer f.mx.Unlock()
|
||||||
|
|
||||||
f.forwarders[pf.Path()] = pf
|
f.forwarders[pf.ID()] = pf
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteForwarder deletes portforward for a given container.
|
// DeleteForwarder deletes portforward for a given container.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue