fix #929
parent
98082eefab
commit
b6c61600a4
|
|
@ -53,7 +53,7 @@ func init() {
|
||||||
if err := flags.Set("stderrthreshold", "fatal"); err != nil {
|
if err := flags.Set("stderrthreshold", "fatal"); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
if err := flags.Set("v", "-1"); err != nil {
|
if err := flags.Set("v", "0"); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
if err := flags.Set("log_file", config.K9sLogs); err != nil {
|
if err := flags.Set("log_file", config.K9sLogs); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ const (
|
||||||
cacheSize = 100
|
cacheSize = 100
|
||||||
cacheExpiry = 5 * time.Minute
|
cacheExpiry = 5 * time.Minute
|
||||||
cacheMXAPIKey = "metricsAPI"
|
cacheMXAPIKey = "metricsAPI"
|
||||||
|
serverVersion = "serverVersion"
|
||||||
)
|
)
|
||||||
|
|
||||||
var supportedMetricsAPIVersions = []string{"v1beta1"}
|
var supportedMetricsAPIVersions = []string{"v1beta1"}
|
||||||
|
|
@ -58,14 +59,18 @@ func InitConnection(config *Config) (*APIClient, error) {
|
||||||
a := APIClient{
|
a := APIClient{
|
||||||
config: config,
|
config: config,
|
||||||
cache: cache.NewLRUExpireCache(cacheSize),
|
cache: cache.NewLRUExpireCache(cacheSize),
|
||||||
|
connOK: true,
|
||||||
}
|
}
|
||||||
a.connOK = true
|
err := a.supportsMetricsResources()
|
||||||
if err := a.supportsMetricsResources(); err != nil {
|
if err != nil {
|
||||||
a.connOK = false
|
log.Error().Err(err).Msgf("Checking metrics-server")
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
if errors.Is(err, noMetricServerErr) || errors.Is(err, metricsUnsupportedErr) {
|
||||||
|
return &a, nil
|
||||||
|
}
|
||||||
|
a.connOK = false
|
||||||
|
|
||||||
return &a, nil
|
return &a, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConnectionOK returns connection status.
|
// ConnectionOK returns connection status.
|
||||||
|
|
@ -178,8 +183,6 @@ func (a *APIClient) CurrentNamespaceName() (string, error) {
|
||||||
return a.config.CurrentNamespaceName()
|
return a.config.CurrentNamespaceName()
|
||||||
}
|
}
|
||||||
|
|
||||||
const serverVersion = "serverVersion"
|
|
||||||
|
|
||||||
// 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) {
|
||||||
if v, ok := a.cache.Get(serverVersion); ok {
|
if v, ok := a.cache.Get(serverVersion); ok {
|
||||||
|
|
@ -273,10 +276,8 @@ func (a *APIClient) Config() *Config {
|
||||||
|
|
||||||
// HasMetrics checks if the cluster supports metrics.
|
// HasMetrics checks if the cluster supports metrics.
|
||||||
func (a *APIClient) HasMetrics() bool {
|
func (a *APIClient) HasMetrics() bool {
|
||||||
if err := a.supportsMetricsResources(); err != nil {
|
err := a.supportsMetricsResources()
|
||||||
return false
|
return err == nil
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dial returns a handle to api server or die.
|
// Dial returns a handle to api server or die.
|
||||||
|
|
@ -416,7 +417,7 @@ func (a *APIClient) supportsMetricsResources() error {
|
||||||
if supported {
|
if supported {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return errors.New("No metrics-server detected")
|
return noMetricServerErr
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
|
|
@ -430,7 +431,7 @@ func (a *APIClient) supportsMetricsResources() error {
|
||||||
}
|
}
|
||||||
apiGroups, err := dial.ServerGroups()
|
apiGroups, err := dial.ServerGroups()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn().Err(err).Msgf("Unable to retrieve server groups")
|
log.Warn().Err(err).Msgf("Unable to fetch APIGroups")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, grp := range apiGroups.Groups {
|
for _, grp := range apiGroups.Groups {
|
||||||
|
|
@ -443,7 +444,7 @@ func (a *APIClient) supportsMetricsResources() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return errors.New("No metrics-server detected")
|
return metricsUnsupportedErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkMetricsVersion(grp metav1.APIGroup) bool {
|
func checkMetricsVersion(grp metav1.APIGroup) bool {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
package client
|
||||||
|
|
||||||
|
import metricsapi "k8s.io/metrics/pkg/apis/metrics"
|
||||||
|
|
||||||
|
type Error string
|
||||||
|
|
||||||
|
func (e Error) Error() string {
|
||||||
|
return string(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
noMetricServerErr = Error("No metrics-server detected")
|
||||||
|
metricsUnsupportedErr = Error("No metrics api group " + metricsapi.GroupName + " found on cluster")
|
||||||
|
)
|
||||||
|
|
@ -87,9 +87,7 @@ func (p *Pod) List(ctx context.Context, ns string) ([]runtime.Object, error) {
|
||||||
|
|
||||||
var pmx *mv1beta1.PodMetricsList
|
var pmx *mv1beta1.PodMetricsList
|
||||||
if withMx, ok := ctx.Value(internal.KeyWithMetrics).(bool); withMx || !ok {
|
if withMx, ok := ctx.Value(internal.KeyWithMetrics).(bool); withMx || !ok {
|
||||||
if pmx, err = client.DialMetrics(p.Client()).FetchPodsMetrics(ctx, ns); err != nil {
|
pmx, _ = client.DialMetrics(p.Client()).FetchPodsMetrics(ctx, ns)
|
||||||
log.Debug().Err(err).Msgf("No pods metrics")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
res := make([]runtime.Object, 0, len(oo))
|
res := make([]runtime.Object, 0, len(oo))
|
||||||
|
|
|
||||||
|
|
@ -71,11 +71,6 @@ func (t *Table) Init(ctx context.Context) {
|
||||||
t.SetSelectionChangedFunc(t.selectionChanged)
|
t.SetSelectionChangedFunc(t.selectionChanged)
|
||||||
t.SetBackgroundColor(tcell.ColorDefault)
|
t.SetBackgroundColor(tcell.ColorDefault)
|
||||||
t.Select(1, 0)
|
t.Select(1, 0)
|
||||||
t.hasMetrics = false
|
|
||||||
if mx, ok := ctx.Value(internal.KeyHasMetrics).(bool); ok {
|
|
||||||
t.hasMetrics = mx
|
|
||||||
}
|
|
||||||
|
|
||||||
if cfg, ok := ctx.Value(internal.KeyViewConfig).(*config.CustomView); ok && cfg != nil {
|
if cfg, ok := ctx.Value(internal.KeyViewConfig).(*config.CustomView); ok && cfg != nil {
|
||||||
cfg.AddListener(t.GVR().String(), t)
|
cfg.AddListener(t.GVR().String(), t)
|
||||||
}
|
}
|
||||||
|
|
@ -187,11 +182,12 @@ func (t *Table) SetSortCol(name string, asc bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update table content.
|
// Update table content.
|
||||||
func (t *Table) Update(data render.TableData) {
|
func (t *Table) Update(data render.TableData, hasMetrics bool) {
|
||||||
t.header = data.Header
|
t.header = data.Header
|
||||||
if t.decorateFn != nil {
|
if t.decorateFn != nil {
|
||||||
data = t.decorateFn(data)
|
data = t.decorateFn(data)
|
||||||
}
|
}
|
||||||
|
t.hasMetrics = hasMetrics
|
||||||
t.doUpdate(t.filtered(data))
|
t.doUpdate(t.filtered(data))
|
||||||
t.UpdateTitle()
|
t.UpdateTitle()
|
||||||
}
|
}
|
||||||
|
|
@ -334,7 +330,7 @@ func (t *Table) Refresh() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// BOZO!! Really want to tell model reload now. Refactor!
|
// BOZO!! Really want to tell model reload now. Refactor!
|
||||||
t.Update(data)
|
t.Update(data, t.hasMetrics)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSelectedRow returns the entire selected row.
|
// GetSelectedRow returns the entire selected row.
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ func TestTableUpdate(t *testing.T) {
|
||||||
v.Init(makeContext())
|
v.Init(makeContext())
|
||||||
|
|
||||||
data := makeTableData()
|
data := makeTableData()
|
||||||
v.Update(data)
|
v.Update(data, false)
|
||||||
|
|
||||||
assert.Equal(t, len(data.RowEvents)+1, v.GetRowCount())
|
assert.Equal(t, len(data.RowEvents)+1, v.GetRowCount())
|
||||||
assert.Equal(t, len(data.Header), v.GetColumnCount())
|
assert.Equal(t, len(data.Header), v.GetColumnCount())
|
||||||
|
|
@ -38,7 +38,7 @@ func TestTableSelection(t *testing.T) {
|
||||||
v.Init(makeContext())
|
v.Init(makeContext())
|
||||||
m := &mockModel{}
|
m := &mockModel{}
|
||||||
v.SetModel(m)
|
v.SetModel(m)
|
||||||
v.Update(m.Peek())
|
v.Update(m.Peek(), false)
|
||||||
v.SelectRow(1, true)
|
v.SelectRow(1, true)
|
||||||
|
|
||||||
r, ok := v.GetSelectedRow("r1")
|
r, ok := v.GetSelectedRow("r1")
|
||||||
|
|
|
||||||
|
|
@ -164,7 +164,7 @@ func (b *Browser) BufferActive(state bool, k model.BufferKind) {
|
||||||
log.Error().Err(err).Msgf("Refresh failed for %s", b.GVR())
|
log.Error().Err(err).Msgf("Refresh failed for %s", b.GVR())
|
||||||
}
|
}
|
||||||
b.app.QueueUpdateDraw(func() {
|
b.app.QueueUpdateDraw(func() {
|
||||||
b.Update(b.GetModel().Peek())
|
b.Update(b.GetModel().Peek(), b.App().Conn().HasMetrics())
|
||||||
if b.GetRowCount() > 1 {
|
if b.GetRowCount() > 1 {
|
||||||
b.App().filterHistory.Push(b.CmdBuff().GetText())
|
b.App().filterHistory.Push(b.CmdBuff().GetText())
|
||||||
}
|
}
|
||||||
|
|
@ -213,7 +213,7 @@ func (b *Browser) TableDataChanged(data render.TableData) {
|
||||||
|
|
||||||
b.app.QueueUpdateDraw(func() {
|
b.app.QueueUpdateDraw(func() {
|
||||||
b.refreshActions()
|
b.refreshActions()
|
||||||
b.Update(data)
|
b.Update(data, b.app.Conn().HasMetrics())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -336,6 +336,9 @@ func (b *Browser) editCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||||
if client.IsClusterScoped(ns) {
|
if client.IsClusterScoped(ns) {
|
||||||
ns = client.AllNamespaces
|
ns = client.AllNamespaces
|
||||||
}
|
}
|
||||||
|
if b.GVR().String() == "v1/namespaces" {
|
||||||
|
ns = n
|
||||||
|
}
|
||||||
if ok, err := b.app.Conn().CanI(ns, b.GVR().String(), []string{"patch"}); !ok || err != nil {
|
if ok, err := b.app.Conn().CanI(ns, b.GVR().String(), []string{"patch"}); !ok || err != nil {
|
||||||
b.App().Flash().Err(fmt.Errorf("Current user can't edit resource %s", b.GVR()))
|
b.App().Flash().Err(fmt.Errorf("Current user can't edit resource %s", b.GVR()))
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ func TestTableNew(t *testing.T) {
|
||||||
}
|
}
|
||||||
data.Namespace = ""
|
data.Namespace = ""
|
||||||
|
|
||||||
v.Update(*data)
|
v.Update(*data, false)
|
||||||
assert.Equal(t, 3, v.GetRowCount())
|
assert.Equal(t, 3, v.GetRowCount())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue