parent
0fc7ea3183
commit
2d2c6b06b6
2
Makefile
2
Makefile
|
|
@ -3,7 +3,7 @@ PACKAGE := github.com/derailed/$(NAME)
|
||||||
GIT := $(shell git rev-parse --short HEAD)
|
GIT := $(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} +%FT%T%Z)
|
DATE := $(shell date -u -d @${SOURCE_DATE_EPOCH} +%FT%T%Z)
|
||||||
VERSION ?= v0.23.3
|
VERSION ?= v0.23.4
|
||||||
IMG_NAME := derailed/k9s
|
IMG_NAME := derailed/k9s
|
||||||
IMAGE := ${IMG_NAME}:${VERSION}
|
IMAGE := ${IMG_NAME}:${VERSION}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
<img src="https://raw.githubusercontent.com/derailed/k9s/master/assets/k9s_small.png" align="right" width="200" height="auto"/>
|
||||||
|
|
||||||
|
# Release v0.23.4
|
||||||
|
|
||||||
|
## 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 [sponsorhip 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)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Maintenance Release!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Resolved Issues/Features
|
||||||
|
|
||||||
|
* [Issue #920](https://github.com/derailed/k9s/issues/920) Timestamp stopped working
|
||||||
|
* [Issue #663](https://github.com/derailed/k9s/issues/663) Perf issues in v0.23.X - Better??
|
||||||
|
|
||||||
|
## Resolved PRs
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<img src="https://raw.githubusercontent.com/derailed/k9s/master/assets/imhotep_logo.png" width="32" height="auto"/> © 2020 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
|
@ -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", "0"); err != nil {
|
if err := flags.Set("v", "-1"); 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 {
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,6 @@ func (n *Namespace) Validate(c client.Connection, ks KubeSettings) {
|
||||||
|
|
||||||
// SetActive set the active namespace.
|
// SetActive set the active namespace.
|
||||||
func (n *Namespace) SetActive(ns string, ks KubeSettings) error {
|
func (n *Namespace) SetActive(ns string, ks KubeSettings) error {
|
||||||
log.Debug().Msgf("Setting active ns %q", ns)
|
|
||||||
n.Active = ns
|
n.Active = ns
|
||||||
if ns != "" {
|
if ns != "" {
|
||||||
n.addFavNS(ns)
|
n.addFavNS(ns)
|
||||||
|
|
|
||||||
|
|
@ -101,23 +101,28 @@ func (f *FishBuff) SetSuggestionFn(fn SuggestionFunc) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify publish suggestions to all listeners.
|
// Notify publish suggestions to all listeners.
|
||||||
func (f *FishBuff) Notify() {
|
func (f *FishBuff) Notify(delete bool) {
|
||||||
if f.suggestionFn == nil {
|
if f.suggestionFn == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
ss := f.suggestionFn(string(f.buff))
|
||||||
|
if len(ss) == 1 && !delete {
|
||||||
|
f.SetText(string(string(f.buff) + ss[0]))
|
||||||
|
return
|
||||||
|
}
|
||||||
f.fireSuggestionChanged(f.suggestionFn(string(f.buff)))
|
f.fireSuggestionChanged(f.suggestionFn(string(f.buff)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add adds a new charater to the buffer.
|
// Add adds a new character to the buffer.
|
||||||
func (f *FishBuff) Add(r rune) {
|
func (f *FishBuff) Add(r rune) {
|
||||||
f.CmdBuff.Add(r)
|
f.CmdBuff.Add(r)
|
||||||
f.Notify()
|
f.Notify(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete removes the last character from the buffer.
|
// Delete removes the last character from the buffer.
|
||||||
func (f *FishBuff) Delete() {
|
func (f *FishBuff) Delete() {
|
||||||
f.CmdBuff.Delete()
|
f.CmdBuff.Delete()
|
||||||
f.Notify()
|
f.Notify(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FishBuff) fireSuggestionChanged(ss []string) {
|
func (f *FishBuff) fireSuggestionChanged(ss []string) {
|
||||||
|
|
@ -127,9 +132,10 @@ func (f *FishBuff) fireSuggestionChanged(ss []string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
text, sug := f.GetText(), ss[f.suggestionIndex]
|
||||||
for _, l := range f.listeners {
|
for _, l := range f.listeners {
|
||||||
if listener, ok := l.(SuggestionListener); ok {
|
if listener, ok := l.(SuggestionListener); ok {
|
||||||
listener.SuggestionChanged(f.GetText(), ss[f.suggestionIndex])
|
listener.SuggestionChanged(text, sug)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,20 +8,37 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestFishExact(t *testing.T) {
|
||||||
|
m := mockSuggestionListener{}
|
||||||
|
|
||||||
|
f := model.NewFishBuff(' ', model.FilterBuffer)
|
||||||
|
f.AddListener(&m)
|
||||||
|
f.SetSuggestionFn(func(text string) sort.StringSlice {
|
||||||
|
return sort.StringSlice{"lee"}
|
||||||
|
})
|
||||||
|
f.Add('b')
|
||||||
|
f.SetActive(true)
|
||||||
|
|
||||||
|
assert.True(t, m.active)
|
||||||
|
assert.Equal(t, 1, m.buff)
|
||||||
|
assert.Equal(t, 0, m.sugg)
|
||||||
|
assert.Equal(t, "blee", m.text)
|
||||||
|
}
|
||||||
|
|
||||||
func TestFishAdd(t *testing.T) {
|
func TestFishAdd(t *testing.T) {
|
||||||
m := mockSuggestionListener{}
|
m := mockSuggestionListener{}
|
||||||
|
|
||||||
f := model.NewFishBuff(' ', model.FilterBuffer)
|
f := model.NewFishBuff(' ', model.FilterBuffer)
|
||||||
f.AddListener(&m)
|
f.AddListener(&m)
|
||||||
f.SetSuggestionFn(func(text string) sort.StringSlice {
|
f.SetSuggestionFn(func(text string) sort.StringSlice {
|
||||||
return sort.StringSlice{"blee", "duh"}
|
return sort.StringSlice{"blee", "brew"}
|
||||||
})
|
})
|
||||||
f.Add('a')
|
f.Add('b')
|
||||||
f.SetActive(true)
|
f.SetActive(true)
|
||||||
|
|
||||||
|
assert.True(t, m.active)
|
||||||
assert.Equal(t, 1, m.buff)
|
assert.Equal(t, 1, m.buff)
|
||||||
assert.Equal(t, 1, m.sugg)
|
assert.Equal(t, 1, m.sugg)
|
||||||
assert.True(t, m.active)
|
|
||||||
assert.Equal(t, "blee", m.suggestion)
|
assert.Equal(t, "blee", m.suggestion)
|
||||||
|
|
||||||
c, ok := f.CurrentSuggestion()
|
c, ok := f.CurrentSuggestion()
|
||||||
|
|
@ -30,7 +47,7 @@ func TestFishAdd(t *testing.T) {
|
||||||
|
|
||||||
c, ok = f.NextSuggestion()
|
c, ok = f.NextSuggestion()
|
||||||
assert.True(t, ok)
|
assert.True(t, ok)
|
||||||
assert.Equal(t, "duh", c)
|
assert.Equal(t, "brew", c)
|
||||||
|
|
||||||
c, ok = f.PrevSuggestion()
|
c, ok = f.PrevSuggestion()
|
||||||
assert.True(t, ok)
|
assert.True(t, ok)
|
||||||
|
|
@ -70,9 +87,9 @@ func TestFishDelete(t *testing.T) {
|
||||||
// Helpers...
|
// Helpers...
|
||||||
|
|
||||||
type mockSuggestionListener struct {
|
type mockSuggestionListener struct {
|
||||||
buff, sugg int
|
buff, sugg int
|
||||||
suggestion string
|
suggestion, text string
|
||||||
active bool
|
active bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockSuggestionListener) BufferChanged(s string) {
|
func (m *mockSuggestionListener) BufferChanged(s string) {
|
||||||
|
|
@ -80,6 +97,7 @@ func (m *mockSuggestionListener) BufferChanged(s string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockSuggestionListener) BufferCompleted(s string) {
|
func (m *mockSuggestionListener) BufferCompleted(s string) {
|
||||||
|
m.text = s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockSuggestionListener) BufferActive(state bool, kind model.BufferKind) {
|
func (m *mockSuggestionListener) BufferActive(state bool, kind model.BufferKind) {
|
||||||
|
|
|
||||||
|
|
@ -50,14 +50,6 @@ func NewLog(gvr client.GVR, opts dao.LogOptions, flushTimeout time.Duration) *Lo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// LogOptions returns the current log options.
|
|
||||||
func (l *Log) LogOptions() dao.LogOptions {
|
|
||||||
l.mx.RLock()
|
|
||||||
defer l.mx.RUnlock()
|
|
||||||
|
|
||||||
return l.logOptions
|
|
||||||
}
|
|
||||||
|
|
||||||
// SinceSeconds returns since seconds option.
|
// SinceSeconds returns since seconds option.
|
||||||
func (l *Log) SinceSeconds() int64 {
|
func (l *Log) SinceSeconds() int64 {
|
||||||
l.mx.RLock()
|
l.mx.RLock()
|
||||||
|
|
@ -66,14 +58,15 @@ func (l *Log) SinceSeconds() int64 {
|
||||||
return l.logOptions.SinceSeconds
|
return l.logOptions.SinceSeconds
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetLogOptions updates logger options.
|
// ToggleShowTimestamp toggles to logs timestamps.
|
||||||
func (l *Log) SetLogOptions(opts dao.LogOptions) {
|
func (l *Log) ToggleShowTimestamp(b bool) {
|
||||||
l.mx.Lock()
|
l.logOptions.ShowTimestamp = b
|
||||||
{
|
l.Refresh()
|
||||||
l.logOptions = opts
|
}
|
||||||
}
|
|
||||||
l.mx.Unlock()
|
|
||||||
|
|
||||||
|
// SetSinceSeconds sets the logs retrieval time.
|
||||||
|
func (l *Log) SetSinceSeconds(i int64) {
|
||||||
|
l.logOptions.SinceSeconds = i
|
||||||
l.Restart()
|
l.Restart()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -154,15 +154,14 @@ func gatherMetrics(co *v1.Container, mx *mv1beta1.ContainerMetrics) (resources,
|
||||||
if rList.Cpu() != nil {
|
if rList.Cpu() != nil {
|
||||||
p[requestCPU] = percentMc(c.rCPU(), rList.Cpu())
|
p[requestCPU] = percentMc(c.rCPU(), rList.Cpu())
|
||||||
}
|
}
|
||||||
|
if lList.Cpu() != nil {
|
||||||
|
p[limitCPU] = percentMc(c.rCPU(), lList.Cpu())
|
||||||
|
}
|
||||||
if rList.Memory() != nil {
|
if rList.Memory() != nil {
|
||||||
p[requestMEM] = percentMi(c.rMEM(), rList.Memory())
|
p[requestMEM] = percentMi(c.rMEM(), rList.Memory())
|
||||||
}
|
}
|
||||||
|
if lList.Memory() != nil {
|
||||||
if lList.Cpu() != nil {
|
p[limitMEM] = percentMi(c.rMEM(), lList.Memory())
|
||||||
p[limitCPU] = percentMc(c.lCPU(), lList.Cpu())
|
|
||||||
}
|
|
||||||
if rList.Memory() != nil {
|
|
||||||
p[limitMEM] = percentMi(c.lMEM(), lList.Memory())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return c, p, r
|
return c, p, r
|
||||||
|
|
|
||||||
|
|
@ -40,9 +40,9 @@ func TestContainer(t *testing.T) {
|
||||||
"20:20",
|
"20:20",
|
||||||
"100:100",
|
"100:100",
|
||||||
"50",
|
"50",
|
||||||
"0",
|
"50",
|
||||||
|
"20",
|
||||||
"20",
|
"20",
|
||||||
"0",
|
|
||||||
"",
|
"",
|
||||||
"container is not ready",
|
"container is not ready",
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package render
|
package render
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
@ -120,7 +119,7 @@ func join(a []string, sep string) string {
|
||||||
return a[0]
|
return a[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
var b []string
|
b := make([]string, 0, len(a))
|
||||||
for _, s := range a {
|
for _, s := range a {
|
||||||
if s != "" {
|
if s != "" {
|
||||||
b = append(b, s)
|
b = append(b, s)
|
||||||
|
|
@ -258,28 +257,26 @@ func mapToIfc(m interface{}) (s string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func toMcPerc(v1, v2 *resource.Quantity) string {
|
func toMcPerc(v1, v2 int64) string {
|
||||||
m := v1.MilliValue()
|
return toMc(v1) + " (" + strconv.Itoa(client.ToPercentage(v1, v2)) + "%)"
|
||||||
return fmt.Sprintf("%s (%d%%)", toMc(m), client.ToPercentage(m, v2.MilliValue()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func toMiPerc(v1, v2 *resource.Quantity) string {
|
func toMiPerc(v1, v2 int64) string {
|
||||||
m := v1.Value()
|
return toMi(v1) + " (" + strconv.Itoa(client.ToPercentage(v1, v2)) + "%)"
|
||||||
return fmt.Sprintf("%s (%d%%)", toMi(m), client.ToPercentage(m, v2.Value()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func toMc(v int64) string {
|
func toMc(v int64) string {
|
||||||
if v == 0 {
|
if v == 0 {
|
||||||
return ZeroValue
|
return ZeroValue
|
||||||
}
|
}
|
||||||
return AsThousands(v)
|
return strconv.Itoa(int(v))
|
||||||
}
|
}
|
||||||
|
|
||||||
func toMi(v int64) string {
|
func toMi(v int64) string {
|
||||||
if v == 0 {
|
if v == 0 {
|
||||||
return ZeroValue
|
return ZeroValue
|
||||||
}
|
}
|
||||||
return AsThousands(client.ToMB(v))
|
return strconv.Itoa(int(client.ToMB(v)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func boolPtrToStr(b *bool) string {
|
func boolPtrToStr(b *bool) string {
|
||||||
|
|
|
||||||
|
|
@ -368,7 +368,7 @@ func TestToMc(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{0, "0"},
|
{0, "0"},
|
||||||
{2, "2"},
|
{2, "2"},
|
||||||
{1_000, "1,000"},
|
{1_000, "1000"},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, u := range uu {
|
for _, u := range uu {
|
||||||
|
|
@ -383,7 +383,7 @@ func TestToMi(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{0, "0"},
|
{0, "0"},
|
||||||
{2 * client.MegaByte, "2"},
|
{2 * client.MegaByte, "2"},
|
||||||
{1_000 * client.MegaByte, "1,000"},
|
{1_000 * client.MegaByte, "1000"},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, u := range uu {
|
for _, u := range uu {
|
||||||
|
|
|
||||||
|
|
@ -41,10 +41,10 @@ func (Node) Header(_ string) Header {
|
||||||
HeaderColumn{Name: "INTERNAL-IP", Wide: true},
|
HeaderColumn{Name: "INTERNAL-IP", Wide: true},
|
||||||
HeaderColumn{Name: "EXTERNAL-IP", Wide: true},
|
HeaderColumn{Name: "EXTERNAL-IP", Wide: true},
|
||||||
HeaderColumn{Name: "PODS", Align: tview.AlignRight},
|
HeaderColumn{Name: "PODS", Align: tview.AlignRight},
|
||||||
HeaderColumn{Name: "%CPU", Align: tview.AlignRight, MX: true},
|
|
||||||
HeaderColumn{Name: "%MEM", Align: tview.AlignRight, MX: true},
|
|
||||||
HeaderColumn{Name: "CPU", Align: tview.AlignRight, MX: true},
|
HeaderColumn{Name: "CPU", Align: tview.AlignRight, MX: true},
|
||||||
HeaderColumn{Name: "MEM", Align: tview.AlignRight, MX: true},
|
HeaderColumn{Name: "MEM", Align: tview.AlignRight, MX: true},
|
||||||
|
HeaderColumn{Name: "%CPU", Align: tview.AlignRight, MX: true},
|
||||||
|
HeaderColumn{Name: "%MEM", Align: tview.AlignRight, MX: true},
|
||||||
HeaderColumn{Name: "CPU/R", Align: tview.AlignRight, MX: true},
|
HeaderColumn{Name: "CPU/R", Align: tview.AlignRight, MX: true},
|
||||||
HeaderColumn{Name: "CPU/L", Align: tview.AlignRight, MX: true},
|
HeaderColumn{Name: "CPU/L", Align: tview.AlignRight, MX: true},
|
||||||
HeaderColumn{Name: "MEM/R", Align: tview.AlignRight, MX: true},
|
HeaderColumn{Name: "MEM/R", Align: tview.AlignRight, MX: true},
|
||||||
|
|
@ -63,7 +63,6 @@ func (n Node) Render(o interface{}, ns string, r *Row) error {
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("Expected *NodeAndMetrics, but got %T", o)
|
return fmt.Errorf("Expected *NodeAndMetrics, but got %T", o)
|
||||||
}
|
}
|
||||||
|
|
||||||
meta, ok := oo.Raw.Object["metadata"].(map[string]interface{})
|
meta, ok := oo.Raw.Object["metadata"].(map[string]interface{})
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("Unable to extract meta")
|
return fmt.Errorf("Unable to extract meta")
|
||||||
|
|
@ -96,9 +95,8 @@ func (n Node) Render(o interface{}, ns string, r *Row) error {
|
||||||
tlm.Add(*lList.Memory())
|
tlm.Add(*lList.Memory())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
res := newResources(newResourceList(trc, trm), newResourceList(tlc, tlm))
|
|
||||||
statuses := make(sort.StringSlice, 10)
|
statuses := make(sort.StringSlice, 10)
|
||||||
status(no.Status, no.Spec.Unschedulable, statuses)
|
status(no.Status.Conditions, no.Spec.Unschedulable, statuses)
|
||||||
sort.Sort(statuses)
|
sort.Sort(statuses)
|
||||||
roles := make(sort.StringSlice, 10)
|
roles := make(sort.StringSlice, 10)
|
||||||
nodeRoles(&no, roles)
|
nodeRoles(&no, roles)
|
||||||
|
|
@ -114,16 +112,16 @@ func (n Node) Render(o interface{}, ns string, r *Row) error {
|
||||||
iIP,
|
iIP,
|
||||||
eIP,
|
eIP,
|
||||||
strconv.Itoa(len(oo.Pods)),
|
strconv.Itoa(len(oo.Pods)),
|
||||||
|
toMc(c.cpu),
|
||||||
|
toMi(c.mem),
|
||||||
strconv.Itoa(p.rCPU()),
|
strconv.Itoa(p.rCPU()),
|
||||||
strconv.Itoa(p.rMEM()),
|
strconv.Itoa(p.rMEM()),
|
||||||
toMc(c.rCPU().MilliValue()),
|
toMcPerc(trc.MilliValue(), a.cpu),
|
||||||
toMi(c.rMEM().Value()),
|
toMcPerc(tlc.MilliValue(), a.cpu),
|
||||||
toMcPerc(res.rCPU(), a.rCPU()),
|
toMiPerc(trm.Value(), a.mem),
|
||||||
toMcPerc(res.lCPU(), a.rCPU()),
|
toMiPerc(tlm.Value(), a.mem),
|
||||||
toMiPerc(res.rMEM(), a.rMEM()),
|
toMc(a.cpu),
|
||||||
toMiPerc(res.lMEM(), a.rMEM()),
|
toMi(a.mem),
|
||||||
toMc(a.rCPU().MilliValue()),
|
|
||||||
toMi(a.rMEM().Value()),
|
|
||||||
mapToStr(no.Labels),
|
mapToStr(no.Labels),
|
||||||
asStatus(n.diagnose(statuses)),
|
asStatus(n.diagnose(statuses)),
|
||||||
toAge(no.ObjectMeta.CreationTimestamp),
|
toAge(no.ObjectMeta.CreationTimestamp),
|
||||||
|
|
@ -177,19 +175,24 @@ func (n *NodeWithMetrics) DeepCopyObject() runtime.Object {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
func gatherNodeMX(no *v1.Node, mx *mv1beta1.NodeMetrics) (resources, percentages, resources) {
|
type metric struct {
|
||||||
c, p, a := newResources(nil, nil), newPercentages(), newResources(no.Status.Allocatable, nil)
|
cpu, mem int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func gatherNodeMX(no *v1.Node, mx *mv1beta1.NodeMetrics) (metric, percentages, metric) {
|
||||||
|
c := metric{cpu: 0, mem: 0}
|
||||||
|
p := newPercentages()
|
||||||
|
a := metric{
|
||||||
|
cpu: no.Status.Allocatable.Cpu().MilliValue(),
|
||||||
|
mem: no.Status.Allocatable.Memory().Value(),
|
||||||
|
}
|
||||||
if mx == nil {
|
if mx == nil {
|
||||||
return c, p, a
|
return c, p, a
|
||||||
}
|
}
|
||||||
|
|
||||||
c[requestCPU], c[requestMEM] = mx.Usage.Cpu(), mx.Usage.Memory()
|
c.cpu, c.mem = mx.Usage.Cpu().MilliValue(), mx.Usage.Memory().Value()
|
||||||
if a.rCPU() != nil {
|
p[requestCPU] = client.ToPercentage(c.cpu, a.cpu)
|
||||||
p[requestCPU] = percentMc(c.rCPU(), a.rCPU())
|
p[requestMEM] = client.ToPercentage(c.mem, a.mem)
|
||||||
}
|
|
||||||
if a.rMEM() != nil {
|
|
||||||
p[requestMEM] = percentMi(c.rMEM(), a.rMEM())
|
|
||||||
}
|
|
||||||
|
|
||||||
return c, p, a
|
return c, p, a
|
||||||
}
|
}
|
||||||
|
|
@ -230,11 +233,11 @@ func getIPs(addrs []v1.NodeAddress) (iIP, eIP string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func status(status v1.NodeStatus, exempt bool, res []string) {
|
func status(conds []v1.NodeCondition, exempt bool, res []string) {
|
||||||
var index int
|
var index int
|
||||||
conditions := make(map[v1.NodeConditionType]*v1.NodeCondition)
|
conditions := make(map[v1.NodeConditionType]*v1.NodeCondition, len(conds))
|
||||||
for n := range status.Conditions {
|
for n := range conds {
|
||||||
cond := status.Conditions[n]
|
cond := conds[n]
|
||||||
conditions[cond.Type] = &cond
|
conditions[cond.Type] = &cond
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ import (
|
||||||
func TestNodeRender(t *testing.T) {
|
func TestNodeRender(t *testing.T) {
|
||||||
pom := render.NodeWithMetrics{
|
pom := render.NodeWithMetrics{
|
||||||
Raw: load(t, "no"),
|
Raw: load(t, "no"),
|
||||||
MX: makeNodeMX("n1", "10m", "10Mi"),
|
MX: makeNodeMX("n1", "10m", "20Mi"),
|
||||||
}
|
}
|
||||||
|
|
||||||
var no render.Node
|
var no render.Node
|
||||||
|
|
@ -21,7 +21,7 @@ func TestNodeRender(t *testing.T) {
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, "minikube", r.ID)
|
assert.Equal(t, "minikube", r.ID)
|
||||||
e := render.Fields{"minikube", "Ready", "master", "v1.15.2", "4.15.0", "192.168.64.107", "<none>", "0", "0", "0", "10", "10", "0 (0%)", "0 (0%)", "0 (0%)", "0 (0%)", "4,000", "7,874"}
|
e := render.Fields{"minikube", "Ready", "master", "v1.15.2", "4.15.0", "192.168.64.107", "<none>", "0", "10", "20", "0", "0", "0 (0%)", "0 (0%)", "0 (0%)", "0 (0%)", "4000", "7874"}
|
||||||
assert.Equal(t, e, r.Fields[:18])
|
assert.Equal(t, e, r.Fields[:18])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -218,13 +218,12 @@ func (*Pod) gatherPodMX(pod *v1.Pod, mx *mv1beta1.PodMetrics) (resources, percen
|
||||||
if rList.Cpu() != nil {
|
if rList.Cpu() != nil {
|
||||||
p[requestCPU] = percentMc(c.rCPU(), rList.Cpu())
|
p[requestCPU] = percentMc(c.rCPU(), rList.Cpu())
|
||||||
}
|
}
|
||||||
if rList.Memory() != nil {
|
|
||||||
p[requestMEM] = percentMi(c.rMEM(), rList.Memory())
|
|
||||||
}
|
|
||||||
|
|
||||||
if lList.Cpu() != nil {
|
if lList.Cpu() != nil {
|
||||||
p[limitCPU] = percentMc(c.rCPU(), lList.Cpu())
|
p[limitCPU] = percentMc(c.rCPU(), lList.Cpu())
|
||||||
}
|
}
|
||||||
|
if rList.Memory() != nil {
|
||||||
|
p[requestMEM] = percentMi(c.rMEM(), rList.Memory())
|
||||||
|
}
|
||||||
if lList.Memory() != nil {
|
if lList.Memory() != nil {
|
||||||
p[limitMEM] = percentMi(c.rMEM(), lList.Memory())
|
p[limitMEM] = percentMi(c.rMEM(), lList.Memory())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ type PromptModel interface {
|
||||||
ClearText(fire bool)
|
ClearText(fire bool)
|
||||||
|
|
||||||
// Notify notifies all listener of current suggestions.
|
// Notify notifies all listener of current suggestions.
|
||||||
Notify()
|
Notify(bool)
|
||||||
|
|
||||||
// AddListener registers a command listener.
|
// AddListener registers a command listener.
|
||||||
AddListener(model.BuffWatcher)
|
AddListener(model.BuffWatcher)
|
||||||
|
|
@ -178,7 +178,7 @@ func (p *Prompt) InCmdMode() bool {
|
||||||
func (p *Prompt) activate() {
|
func (p *Prompt) activate() {
|
||||||
p.SetCursorIndex(len(p.model.GetText()))
|
p.SetCursorIndex(len(p.model.GetText()))
|
||||||
p.write(p.model.GetText(), "")
|
p.write(p.model.GetText(), "")
|
||||||
p.model.Notify()
|
p.model.Notify(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Prompt) update(s string) {
|
func (p *Prompt) update(s string) {
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,8 @@ func (l *Log) Init(ctx context.Context) (err error) {
|
||||||
l.model.AddListener(l)
|
l.model.AddListener(l)
|
||||||
l.updateTitle()
|
l.updateTitle()
|
||||||
|
|
||||||
|
l.model.ToggleShowTimestamp(l.app.Config.K9s.Logger.ShowTime)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -130,12 +132,12 @@ func (l *Log) LogChanged(lines [][]byte) {
|
||||||
|
|
||||||
// BufferCompleted indicates input was accepted.
|
// BufferCompleted indicates input was accepted.
|
||||||
func (l *Log) BufferCompleted(s string) {
|
func (l *Log) BufferCompleted(s string) {
|
||||||
l.model.Filter(l.logs.cmdBuff.GetText())
|
l.model.Filter(s)
|
||||||
l.updateTitle()
|
l.updateTitle()
|
||||||
}
|
}
|
||||||
|
|
||||||
// BufferChanged indicates the buffer was changed.
|
// BufferChanged indicates the buffer was changed.
|
||||||
func (l *Log) BufferChanged(s string) {}
|
func (l *Log) BufferChanged(string) {}
|
||||||
|
|
||||||
// BufferActive indicates the buff activity changed.
|
// BufferActive indicates the buff activity changed.
|
||||||
func (l *Log) BufferActive(state bool, k model.BufferKind) {
|
func (l *Log) BufferActive(state bool, k model.BufferKind) {
|
||||||
|
|
@ -284,9 +286,7 @@ func (l *Log) Flush(lines [][]byte) {
|
||||||
|
|
||||||
func (l *Log) sinceCmd(a int) func(evt *tcell.EventKey) *tcell.EventKey {
|
func (l *Log) sinceCmd(a int) func(evt *tcell.EventKey) *tcell.EventKey {
|
||||||
return func(evt *tcell.EventKey) *tcell.EventKey {
|
return func(evt *tcell.EventKey) *tcell.EventKey {
|
||||||
opts := l.model.LogOptions()
|
l.model.SetSinceSeconds(int64(a))
|
||||||
opts.SinceSeconds = int64(a)
|
|
||||||
l.model.SetLogOptions(opts)
|
|
||||||
l.updateTitle()
|
l.updateTitle()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -305,7 +305,7 @@ func (l *Log) filterCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveCmd dumps the logs to file.
|
// SaveCmd dumps the logs to file.
|
||||||
func (l *Log) SaveCmd(evt *tcell.EventKey) *tcell.EventKey {
|
func (l *Log) SaveCmd(*tcell.EventKey) *tcell.EventKey {
|
||||||
if path, err := saveData(l.app.Config.K9s.CurrentCluster, l.model.GetPath(), l.logs.GetText(true)); err != nil {
|
if path, err := saveData(l.app.Config.K9s.CurrentCluster, l.model.GetPath(), l.logs.GetText(true)); err != nil {
|
||||||
l.app.Flash().Err(err)
|
l.app.Flash().Err(err)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -314,7 +314,7 @@ func (l *Log) SaveCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Log) cpCmd(evt *tcell.EventKey) *tcell.EventKey {
|
func (l *Log) cpCmd(*tcell.EventKey) *tcell.EventKey {
|
||||||
l.app.Flash().Info("Content copied to clipboard...")
|
l.app.Flash().Info("Content copied to clipboard...")
|
||||||
if err := clipboard.WriteAll(l.logs.GetText(true)); err != nil {
|
if err := clipboard.WriteAll(l.logs.GetText(true)); err != nil {
|
||||||
l.app.Flash().Err(err)
|
l.app.Flash().Err(err)
|
||||||
|
|
@ -378,7 +378,7 @@ func (l *Log) toggleTimestampCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
l.indicator.ToggleTimestamp()
|
l.indicator.ToggleTimestamp()
|
||||||
l.model.Refresh()
|
l.model.ToggleShowTimestamp(l.indicator.showTime)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue