fixed ns + klog stderr

mine
derailed 2019-05-06 10:33:11 -06:00
parent 5db91d79a6
commit a52cf37ff1
20 changed files with 248 additions and 31 deletions

View File

@ -154,7 +154,6 @@ This initial drop is brittle. K9s will most likely blow up...
1. You're running older versions of Kubernetes. K9s works best Kubernetes 1.12+. 1. You're running older versions of Kubernetes. K9s works best Kubernetes 1.12+.
1. You don't have enough RBAC fu to manage your cluster (see RBAC section below). 1. You don't have enough RBAC fu to manage your cluster (see RBAC section below).
1. Your cluster does not run a metric server.
--- ---
@ -182,15 +181,15 @@ rules:
# Grants RO access to cluster resources node and namespace # Grants RO access to cluster resources node and namespace
- apiGroups: [""] - apiGroups: [""]
resources: ["nodes", "namespaces"] resources: ["nodes", "namespaces"]
verbs: ["get", "list"] verbs: ["get", "list", "watch"]
# Grants RO access to RBAC resources # Grants RO access to RBAC resources
- apiGroups: ["rbac.authorization.k8s.io"] - apiGroups: ["rbac.authorization.k8s.io"]
resources: ["clusterroles", "roles", "clusterrolebindings", "rolebindings"] resources: ["clusterroles", "roles", "clusterrolebindings", "rolebindings"]
verbs: ["get", "list"] verbs: ["get", "list", "watch"]
# Grants RO access to CRD resources # Grants RO access to CRD resources
- apiGroups: ["apiextensions.k8s.io"] - apiGroups: ["apiextensions.k8s.io"]
resources: ["customresourcedefinitions"] resources: ["customresourcedefinitions"]
verbs: ["get", "list"] verbs: ["get", "list", "watch"]
# Grants RO access to netric server # Grants RO access to netric server
- apiGroups: ["metrics.k8s.io"] - apiGroups: ["metrics.k8s.io"]
resources: ["nodes", "pods"] resources: ["nodes", "pods"]
@ -228,7 +227,7 @@ rules:
# Grants RO access to most namespaced resources # Grants RO access to most namespaced resources
- apiGroups: ["", "apps", "autoscaling", "batch", "extensions"] - apiGroups: ["", "apps", "autoscaling", "batch", "extensions"]
resources: ["*"] resources: ["*"]
verbs: ["get", "list"] verbs: ["get", "list", "watch"]
--- ---
# Sample K9s user RoleBinding # Sample K9s user RoleBinding

View File

@ -23,14 +23,14 @@ func infoCmd() *cobra.Command {
func printInfo() { func printInfo() {
const secFmt = "%-15s " const secFmt = "%-15s "
printLogo() printLogo(printer.ColorCyan)
printTuple(secFmt, "Configuration", config.K9sConfigFile) printTuple(secFmt, "Configuration", config.K9sConfigFile)
printTuple(secFmt, "Logs", config.K9sLogs) printTuple(secFmt, "Logs", config.K9sLogs)
} }
func printLogo() { func printLogo(color int) {
for _, l := range views.LogoSmall { for _, l := range views.LogoSmall {
fmt.Println(printer.Colorize(l, printer.ColorCyan)) fmt.Println(printer.Colorize(l, color))
} }
fmt.Println() fmt.Println()
} }

View File

@ -56,6 +56,7 @@ func run(cmd *cobra.Command, args []string) {
if err := recover(); err != nil { if err := recover(); err != nil {
log.Error().Msgf("Boom! %v", err) log.Error().Msgf("Boom! %v", err)
log.Error().Msg(string(debug.Stack())) log.Error().Msg(string(debug.Stack()))
printLogo(printer.ColorRed)
fmt.Printf(printer.Colorize("Boom!! ", printer.ColorRed)) fmt.Printf(printer.Colorize("Boom!! ", printer.ColorRed))
fmt.Println(printer.Colorize(fmt.Sprintf("%v.", err), printer.ColorDarkGray)) fmt.Println(printer.Colorize(fmt.Sprintf("%v.", err), printer.ColorDarkGray))
} }

View File

@ -21,7 +21,7 @@ func versionCmd() *cobra.Command {
func printVersion() { func printVersion() {
const secFmt = "%-10s " const secFmt = "%-10s "
printLogo() printLogo(printer.ColorCyan)
printTuple(secFmt, "Version", version) printTuple(secFmt, "Version", version)
printTuple(secFmt, "Commit", commit) printTuple(secFmt, "Commit", commit)
printTuple(secFmt, "Date", date) printTuple(secFmt, "Date", date)

1
go.mod
View File

@ -53,6 +53,7 @@ require (
k8s.io/apiserver v0.0.0-20190426133039-accf7b6d6716 // indirect k8s.io/apiserver v0.0.0-20190426133039-accf7b6d6716 // indirect
k8s.io/cli-runtime v0.0.0-20190325194458-f2b4781c3ae1 k8s.io/cli-runtime v0.0.0-20190325194458-f2b4781c3ae1
k8s.io/client-go v10.0.0+incompatible k8s.io/client-go v10.0.0+incompatible
k8s.io/klog v0.3.0
k8s.io/kube-openapi v0.0.0-20190426233423-c5d3b0f4bee0 // indirect k8s.io/kube-openapi v0.0.0-20190426233423-c5d3b0f4bee0 // indirect
k8s.io/kubernetes v1.13.5 k8s.io/kubernetes v1.13.5
k8s.io/metrics v0.0.0-20190325194013-29123f6a4aa6 k8s.io/metrics v0.0.0-20190325194013-29123f6a4aa6

View File

@ -19,13 +19,15 @@ func init() {
func TestConfigValidate(t *testing.T) { func TestConfigValidate(t *testing.T) {
mc := NewMockConnection() mc := NewMockConnection()
m.When(mc.ValidNamespaces()).ThenReturn(namespaces(), nil) m.When(mc.ValidNamespaces()).ThenReturn(namespaces(), nil)
mk := NewMockKubeSettings() mk := NewMockKubeSettings()
m.When(mk.ClusterNames()).ThenReturn([]string{"c1", "c2"}, nil) m.When(mk.NamespaceNames(namespaces())).ThenReturn([]string{"default"})
cfg := config.NewConfig(mk) cfg := config.NewConfig(mk)
cfg.SetConnection(mc) cfg.SetConnection(mc)
assert.Nil(t, cfg.Load("test_assets/k9s.yml")) assert.Nil(t, cfg.Load("test_assets/k9s.yml"))
cfg.Validate() cfg.Validate()
// mc.VerifyWasCalledOnce().ValidNamespaces()
} }
func TestConfigLoad(t *testing.T) { func TestConfigLoad(t *testing.T) {

View File

@ -10,10 +10,13 @@ import (
func TestK9sValidate(t *testing.T) { func TestK9sValidate(t *testing.T) {
mc := NewMockConnection() mc := NewMockConnection()
m.When(mc.ValidNamespaces()).ThenReturn(namespaces(), nil)
mk := NewMockKubeSettings() mk := NewMockKubeSettings()
m.When(mk.CurrentContextName()).ThenReturn("ctx1", nil) m.When(mk.CurrentContextName()).ThenReturn("ctx1", nil)
m.When(mk.CurrentClusterName()).ThenReturn("c1", nil) m.When(mk.CurrentClusterName()).ThenReturn("c1", nil)
m.When(mk.ClusterNames()).ThenReturn([]string{"c1", "c2"}, nil) m.When(mk.ClusterNames()).ThenReturn([]string{"c1", "c2"}, nil)
m.When(mk.NamespaceNames(namespaces())).ThenReturn([]string{"default"})
c := config.NewK9s() c := config.NewK9s()
c.Validate(mc, mk) c.Validate(mc, mk)
@ -30,10 +33,13 @@ func TestK9sValidate(t *testing.T) {
func TestK9sValidateBlank(t *testing.T) { func TestK9sValidateBlank(t *testing.T) {
mc := NewMockConnection() mc := NewMockConnection()
m.When(mc.ValidNamespaces()).ThenReturn(namespaces(), nil)
mk := NewMockKubeSettings() mk := NewMockKubeSettings()
m.When(mk.CurrentContextName()).ThenReturn("ctx1", nil) m.When(mk.CurrentContextName()).ThenReturn("ctx1", nil)
m.When(mk.CurrentClusterName()).ThenReturn("c1", nil) m.When(mk.CurrentClusterName()).ThenReturn("c1", nil)
m.When(mk.ClusterNames()).ThenReturn([]string{"c1", "c2"}, nil) m.When(mk.ClusterNames()).ThenReturn([]string{"c1", "c2"}, nil)
m.When(mk.NamespaceNames(namespaces())).ThenReturn([]string{"default"})
var c config.K9s var c config.K9s
c.Validate(mc, mk) c.Validate(mc, mk)

View File

@ -39,6 +39,25 @@ func (mock *MockConnection) Config() *k8s.Config {
return ret0 return ret0
} }
func (mock *MockConnection) CurrentNamespaceName() (string, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockConnection().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("CurrentNamespaceName", 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 *MockConnection) DialOrDie() kubernetes.Interface { func (mock *MockConnection) DialOrDie() kubernetes.Interface {
if mock == nil { if mock == nil {
panic("mock must not be nil. Use myMock := NewMockConnection().") panic("mock must not be nil. Use myMock := NewMockConnection().")
@ -320,6 +339,23 @@ func (c *Connection_Config_OngoingVerification) GetCapturedArguments() {
func (c *Connection_Config_OngoingVerification) GetAllCapturedArguments() { func (c *Connection_Config_OngoingVerification) GetAllCapturedArguments() {
} }
func (verifier *VerifierConnection) CurrentNamespaceName() *Connection_CurrentNamespaceName_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "CurrentNamespaceName", params, verifier.timeout)
return &Connection_CurrentNamespaceName_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type Connection_CurrentNamespaceName_OngoingVerification struct {
mock *MockConnection
methodInvocations []pegomock.MethodInvocation
}
func (c *Connection_CurrentNamespaceName_OngoingVerification) GetCapturedArguments() {
}
func (c *Connection_CurrentNamespaceName_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierConnection) DialOrDie() *Connection_DialOrDie_OngoingVerification { func (verifier *VerifierConnection) DialOrDie() *Connection_DialOrDie_OngoingVerification {
params := []pegomock.Param{} params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "DialOrDie", params, verifier.timeout) methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "DialOrDie", params, verifier.timeout)

View File

@ -1,6 +1,8 @@
package config package config
import ( import (
"fmt"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
) )
@ -31,11 +33,10 @@ func (n *Namespace) Validate(c Connection, ks KubeSettings) {
if err != nil { if err != nil {
return return
} }
nn := ks.NamespaceNames(nns) nn := ks.NamespaceNames(nns)
if !n.isAllNamespace() && !InList(nn, n.Active) { if !n.isAllNamespace() && !InList(nn, n.Active) {
log.Debug().Msg("[Config] Validation error active namespace resetting to `default") log.Error().Msgf("[Config] Validation error active namespace `%s does not exists", n.Active)
n.Active = defaultNS panic(fmt.Errorf("Invalid namespace. The provided namespace `%s does not exists", n.Active))
} }
for _, ns := range n.Favorites { for _, ns := range n.Favorites {

View File

@ -24,6 +24,12 @@ func TestNSValidate(t *testing.T) {
} }
func TestNSValidateMissing(t *testing.T) { func TestNSValidateMissing(t *testing.T) {
defer func() {
if err := recover(); err == nil {
t.Fatalf("Expected panic on non existing namespace")
}
}()
mc := NewMockConnection() mc := NewMockConnection()
m.When(mc.ValidNamespaces()).ThenReturn(namespaces(), nil) m.When(mc.ValidNamespaces()).ThenReturn(namespaces(), nil)
mk := NewMockKubeSettings() mk := NewMockKubeSettings()
@ -81,6 +87,8 @@ func TestNSValidateRmFavs(t *testing.T) {
allNS := []string{"default", "kube-system"} allNS := []string{"default", "kube-system"}
mc := NewMockConnection() mc := NewMockConnection()
m.When(mc.ValidNamespaces()).ThenReturn(namespaces(), nil)
mk := NewMockKubeSettings() mk := NewMockKubeSettings()
m.When(mk.NamespaceNames(namespaces())).ThenReturn(allNS) m.When(mk.NamespaceNames(namespaces())).ThenReturn(allNS)
@ -88,5 +96,5 @@ func TestNSValidateRmFavs(t *testing.T) {
ns.Favorites = []string{"default", "fred", "blee"} ns.Favorites = []string{"default", "fred", "blee"}
ns.Validate(mc, mk) ns.Validate(mc, mk)
assert.Equal(t, []string{"fred"}, ns.Favorites) assert.Equal(t, []string{"default"}, ns.Favorites)
} }

View File

@ -60,6 +60,7 @@ type (
SupportsRes(grp string, versions []string) (string, bool) SupportsRes(grp string, versions []string) (string, bool)
ServerVersion() (*version.Info, error) ServerVersion() (*version.Info, error)
FetchNodes() (*v1.NodeList, error) FetchNodes() (*v1.NodeList, error)
CurrentNamespaceName() (string, error)
} }
// APIClient represents a Kubernetes api client. // APIClient represents a Kubernetes api client.
@ -83,6 +84,11 @@ func InitConnectionOrDie(config *Config, logger zerolog.Logger) *APIClient {
return &conn return &conn
} }
// CurrentNamespaceName return namespace name set via either cli arg or cluster config.
func (a *APIClient) CurrentNamespaceName() (string, error) {
return a.config.CurrentNamespaceName()
}
// ServerVersion returns the current server version info. // ServerVersion returns the current server version info.
func (a *APIClient) ServerVersion() (*version.Info, error) { func (a *APIClient) ServerVersion() (*version.Info, error) {
return a.DialOrDie().Discovery().ServerVersion() return a.DialOrDie().Discovery().ServerVersion()

View File

@ -265,7 +265,7 @@ func (l *list) fetchFromStore(m *wa.Meta, ns string) (Columnars, error) {
res = l.resource.New(r) res = l.resource.New(r)
pmx, err := m.Get(wa.PodMXIndex, fqn, opts) pmx, err := m.Get(wa.PodMXIndex, fqn, opts)
if err != nil { if err != nil {
log.Warn().Err(err).Msg("PodMetrics") log.Warn().Err(err).Msgf("PodMetrics %s", fqn)
} }
if mx, ok := pmx.(*mv1beta1.PodMetrics); ok { if mx, ok := pmx.(*mv1beta1.PodMetrics); ok {
res.SetPodMetrics(mx) res.SetPodMetrics(mx)
@ -275,7 +275,7 @@ func (l *list) fetchFromStore(m *wa.Meta, ns string) (Columnars, error) {
res = l.resource.New(r) res = l.resource.New(r)
pmx, err := m.Get(wa.PodMXIndex, fqn, opts) pmx, err := m.Get(wa.PodMXIndex, fqn, opts)
if err != nil { if err != nil {
log.Warn().Err(err).Msg("PodMetrics") log.Warn().Err(err).Msgf("PodMetrics<container> %s", fqn)
} }
if mx, ok := pmx.(*mv1beta1.PodMetrics); ok { if mx, ok := pmx.(*mv1beta1.PodMetrics); ok {
res.SetPodMetrics(mx) res.SetPodMetrics(mx)

View File

@ -69,6 +69,25 @@ func (mock *MockClusterMeta) ContextName() string {
return ret0 return ret0
} }
func (mock *MockClusterMeta) CurrentNamespaceName() (string, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClusterMeta().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("CurrentNamespaceName", 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) DialOrDie() kubernetes.Interface { func (mock *MockClusterMeta) DialOrDie() kubernetes.Interface {
if mock == nil { if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClusterMeta().") panic("mock must not be nil. Use myMock := NewMockClusterMeta().")
@ -437,6 +456,23 @@ func (c *ClusterMeta_ContextName_OngoingVerification) GetCapturedArguments() {
func (c *ClusterMeta_ContextName_OngoingVerification) GetAllCapturedArguments() { func (c *ClusterMeta_ContextName_OngoingVerification) GetAllCapturedArguments() {
} }
func (verifier *VerifierClusterMeta) CurrentNamespaceName() *ClusterMeta_CurrentNamespaceName_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "CurrentNamespaceName", params, verifier.timeout)
return &ClusterMeta_CurrentNamespaceName_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type ClusterMeta_CurrentNamespaceName_OngoingVerification struct {
mock *MockClusterMeta
methodInvocations []pegomock.MethodInvocation
}
func (c *ClusterMeta_CurrentNamespaceName_OngoingVerification) GetCapturedArguments() {
}
func (c *ClusterMeta_CurrentNamespaceName_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierClusterMeta) DialOrDie() *ClusterMeta_DialOrDie_OngoingVerification { func (verifier *VerifierClusterMeta) DialOrDie() *ClusterMeta_DialOrDie_OngoingVerification {
params := []pegomock.Param{} params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "DialOrDie", params, verifier.timeout) methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "DialOrDie", params, verifier.timeout)

View File

@ -39,6 +39,25 @@ func (mock *MockConnection) Config() *k8s.Config {
return ret0 return ret0
} }
func (mock *MockConnection) CurrentNamespaceName() (string, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockConnection().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("CurrentNamespaceName", 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 *MockConnection) DialOrDie() kubernetes.Interface { func (mock *MockConnection) DialOrDie() kubernetes.Interface {
if mock == nil { if mock == nil {
panic("mock must not be nil. Use myMock := NewMockConnection().") panic("mock must not be nil. Use myMock := NewMockConnection().")
@ -320,6 +339,23 @@ func (c *Connection_Config_OngoingVerification) GetCapturedArguments() {
func (c *Connection_Config_OngoingVerification) GetAllCapturedArguments() { func (c *Connection_Config_OngoingVerification) GetAllCapturedArguments() {
} }
func (verifier *VerifierConnection) CurrentNamespaceName() *Connection_CurrentNamespaceName_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "CurrentNamespaceName", params, verifier.timeout)
return &Connection_CurrentNamespaceName_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type Connection_CurrentNamespaceName_OngoingVerification struct {
mock *MockConnection
methodInvocations []pegomock.MethodInvocation
}
func (c *Connection_CurrentNamespaceName_OngoingVerification) GetCapturedArguments() {
}
func (c *Connection_CurrentNamespaceName_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierConnection) DialOrDie() *Connection_DialOrDie_OngoingVerification { func (verifier *VerifierConnection) DialOrDie() *Connection_DialOrDie_OngoingVerification {
params := []pegomock.Param{} params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "DialOrDie", params, verifier.timeout) methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "DialOrDie", params, verifier.timeout)

View File

@ -104,19 +104,25 @@ func (v *clusterInfoView) refresh() {
v.GetCell(row, 1).SetText(cluster.Version()) v.GetCell(row, 1).SetText(cluster.Version())
row++ row++
c := v.GetCell(row, 1)
c.SetText(resource.NAValue)
c = v.GetCell(row+1, 1)
c.SetText(resource.NAValue)
nos, err := v.app.informer.List(watch.NodeIndex, "", metav1.ListOptions{}) nos, err := v.app.informer.List(watch.NodeIndex, "", metav1.ListOptions{})
if err != nil { if err != nil {
log.Warn().Err(err).Msg("List nodes") log.Warn().Err(err).Msg("ListNodes")
return return
} }
nmx, err := v.app.informer.List(watch.NodeMXIndex, "", metav1.ListOptions{}) nmx, err := v.app.informer.List(watch.NodeMXIndex, "", metav1.ListOptions{})
if err != nil { if err != nil {
log.Warn().Err(err).Msg("List node metrics") log.Warn().Err(err).Msg("ListNodeMetrics")
return return
} }
var cmx k8s.ClusterMetrics var cmx k8s.ClusterMetrics
cluster.Metrics(nos, nmx, &cmx) cluster.Metrics(nos, nmx, &cmx)
c := v.GetCell(row, 1) c = v.GetCell(row, 1)
cpu := resource.AsPerc(cmx.PercCPU) cpu := resource.AsPerc(cmx.PercCPU)
c.SetText(cpu + deltas(strip(c.Text), cpu)) c.SetText(cpu + deltas(strip(c.Text), cpu))
row++ row++

View File

@ -69,6 +69,25 @@ func (mock *MockClusterMeta) ContextName() string {
return ret0 return ret0
} }
func (mock *MockClusterMeta) CurrentNamespaceName() (string, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClusterMeta().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("CurrentNamespaceName", 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) DialOrDie() kubernetes.Interface { func (mock *MockClusterMeta) DialOrDie() kubernetes.Interface {
if mock == nil { if mock == nil {
panic("mock must not be nil. Use myMock := NewMockClusterMeta().") panic("mock must not be nil. Use myMock := NewMockClusterMeta().")
@ -437,6 +456,23 @@ func (c *ClusterMeta_ContextName_OngoingVerification) GetCapturedArguments() {
func (c *ClusterMeta_ContextName_OngoingVerification) GetAllCapturedArguments() { func (c *ClusterMeta_ContextName_OngoingVerification) GetAllCapturedArguments() {
} }
func (verifier *VerifierClusterMeta) CurrentNamespaceName() *ClusterMeta_CurrentNamespaceName_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "CurrentNamespaceName", params, verifier.timeout)
return &ClusterMeta_CurrentNamespaceName_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type ClusterMeta_CurrentNamespaceName_OngoingVerification struct {
mock *MockClusterMeta
methodInvocations []pegomock.MethodInvocation
}
func (c *ClusterMeta_CurrentNamespaceName_OngoingVerification) GetCapturedArguments() {
}
func (c *ClusterMeta_CurrentNamespaceName_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierClusterMeta) DialOrDie() *ClusterMeta_DialOrDie_OngoingVerification { func (verifier *VerifierClusterMeta) DialOrDie() *ClusterMeta_DialOrDie_OngoingVerification {
params := []pegomock.Param{} params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "DialOrDie", params, verifier.timeout) methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "DialOrDie", params, verifier.timeout)

View File

@ -459,6 +459,7 @@ func namespaced(n string) (string, string) {
func (v *resourceView) refreshActions() { func (v *resourceView) refreshActions() {
if v.list.Access(resource.NamespaceAccess) { if v.list.Access(resource.NamespaceAccess) {
if ns, err := v.app.conn().CurrentNamespaceName(); err != nil || ns == "" {
v.namespaces = make(map[int]string, config.MaxFavoritesNS) v.namespaces = make(map[int]string, config.MaxFavoritesNS)
v.actions[tcell.Key(numKeys[0])] = newKeyAction(resource.AllNamespace, v.switchNamespaceCmd, true) v.actions[tcell.Key(numKeys[0])] = newKeyAction(resource.AllNamespace, v.switchNamespaceCmd, true)
v.namespaces[0] = resource.AllNamespace v.namespaces[0] = resource.AllNamespace
@ -472,6 +473,7 @@ func (v *resourceView) refreshActions() {
index++ index++
} }
} }
}
v.actions[tcell.KeyEnter] = newKeyAction("Enter", v.enterCmd, false) v.actions[tcell.KeyEnter] = newKeyAction("Enter", v.enterCmd, false)
v.actions[tcell.KeyCtrlR] = newKeyAction("Refresh", v.refreshCmd, false) v.actions[tcell.KeyCtrlR] = newKeyAction("Refresh", v.refreshCmd, false)

View File

@ -81,7 +81,7 @@ func (m *Meta) List(res, ns string, opts metav1.ListOptions) (k8s.Collection, er
return i.List(ns, opts), nil return i.List(ns, opts), nil
} }
return nil, fmt.Errorf("No informer found for resource %s", res) return nil, fmt.Errorf("No informer found for resource %s:%q", res, ns)
} }
// Get a resource by name. // Get a resource by name.
@ -90,7 +90,7 @@ func (m Meta) Get(res, fqn string, opts metav1.GetOptions) (interface{}, error)
return informer.Get(fqn, opts) return informer.Get(fqn, opts)
} }
return nil, fmt.Errorf("No informer found for resource %s", res) return nil, fmt.Errorf("No informer found for resource %s:%q", res, fqn)
} }
// Run starts watching cluster resources. // Run starts watching cluster resources.

View File

@ -39,6 +39,25 @@ func (mock *MockConnection) Config() *k8s.Config {
return ret0 return ret0
} }
func (mock *MockConnection) CurrentNamespaceName() (string, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockConnection().")
}
params := []pegomock.Param{}
result := pegomock.GetGenericMockFrom(mock).Invoke("CurrentNamespaceName", 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 *MockConnection) DialOrDie() kubernetes.Interface { func (mock *MockConnection) DialOrDie() kubernetes.Interface {
if mock == nil { if mock == nil {
panic("mock must not be nil. Use myMock := NewMockConnection().") panic("mock must not be nil. Use myMock := NewMockConnection().")
@ -320,6 +339,23 @@ func (c *Connection_Config_OngoingVerification) GetCapturedArguments() {
func (c *Connection_Config_OngoingVerification) GetAllCapturedArguments() { func (c *Connection_Config_OngoingVerification) GetAllCapturedArguments() {
} }
func (verifier *VerifierConnection) CurrentNamespaceName() *Connection_CurrentNamespaceName_OngoingVerification {
params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "CurrentNamespaceName", params, verifier.timeout)
return &Connection_CurrentNamespaceName_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
type Connection_CurrentNamespaceName_OngoingVerification struct {
mock *MockConnection
methodInvocations []pegomock.MethodInvocation
}
func (c *Connection_CurrentNamespaceName_OngoingVerification) GetCapturedArguments() {
}
func (c *Connection_CurrentNamespaceName_OngoingVerification) GetAllCapturedArguments() {
}
func (verifier *VerifierConnection) DialOrDie() *Connection_DialOrDie_OngoingVerification { func (verifier *VerifierConnection) DialOrDie() *Connection_DialOrDie_OngoingVerification {
params := []pegomock.Param{} params := []pegomock.Param{}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "DialOrDie", params, verifier.timeout) methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "DialOrDie", params, verifier.timeout)

View File

@ -2,12 +2,14 @@ package main
import ( import (
"os" "os"
"syscall"
"github.com/derailed/k9s/cmd" "github.com/derailed/k9s/cmd"
"github.com/derailed/k9s/internal/config" "github.com/derailed/k9s/internal/config"
"github.com/rs/zerolog" "github.com/rs/zerolog"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
_ "k8s.io/client-go/plugin/pkg/client/auth" _ "k8s.io/client-go/plugin/pkg/client/auth"
"k8s.io/klog"
) )
func init() { func init() {
@ -16,6 +18,9 @@ func init() {
mod := os.O_CREATE | os.O_APPEND | os.O_WRONLY mod := os.O_CREATE | os.O_APPEND | os.O_WRONLY
if file, err := os.OpenFile(config.K9sLogs, mod, config.DefaultFileMod); err == nil { if file, err := os.OpenFile(config.K9sLogs, mod, config.DefaultFileMod); err == nil {
log.Logger = log.Output(zerolog.ConsoleWriter{Out: file}) log.Logger = log.Output(zerolog.ConsoleWriter{Out: file})
// Klogs (of course) want to print stuff to the screen ;(
klog.SetOutput(file)
syscall.Dup2(int(file.Fd()), 2)
} else { } else {
panic(err) panic(err)
} }