resolve conflicts
commit
874226a1b3
|
|
@ -29,6 +29,7 @@ func NewContainer(gvr client.GVR) ResourceViewer {
|
||||||
c.SetEnvFn(c.k9sEnv)
|
c.SetEnvFn(c.k9sEnv)
|
||||||
c.GetTable().SetEnterFn(c.viewLogs)
|
c.GetTable().SetEnterFn(c.viewLogs)
|
||||||
c.GetTable().SetColorerFn(render.Container{}.ColorerFunc())
|
c.GetTable().SetColorerFn(render.Container{}.ColorerFunc())
|
||||||
|
c.GetTable().SetDecorateFn(c.decorateRows)
|
||||||
c.SetBindKeysFn(c.bindKeys)
|
c.SetBindKeysFn(c.bindKeys)
|
||||||
c.GetTable().SetDecorateFn(c.portForwardIndicator)
|
c.GetTable().SetDecorateFn(c.portForwardIndicator)
|
||||||
|
|
||||||
|
|
@ -48,6 +49,10 @@ func (c *Container) portForwardIndicator(data render.TableData) render.TableData
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Container) decorateRows(data render.TableData) render.TableData {
|
||||||
|
return decorateCpuMemHeaderRows(c.App(), data)
|
||||||
|
}
|
||||||
|
|
||||||
// Name returns the component name.
|
// Name returns the component name.
|
||||||
func (c *Container) Name() string { return containerTitle }
|
func (c *Container) Name() string { return containerTitle }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/derailed/k9s/internal"
|
"github.com/derailed/k9s/internal"
|
||||||
|
|
@ -177,3 +178,40 @@ func fqn(ns, n string) string {
|
||||||
}
|
}
|
||||||
return ns + "/" + n
|
return ns + "/" + n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func decorateCpuMemHeaderRows(app *App, data render.TableData) render.TableData {
|
||||||
|
for colIndex, header := range data.Header {
|
||||||
|
check := ""
|
||||||
|
if header.Name == "%CPU/L" {
|
||||||
|
check = "cpu"
|
||||||
|
}
|
||||||
|
if header.Name == "%MEM/L" {
|
||||||
|
check = "memory"
|
||||||
|
}
|
||||||
|
if len(check) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, re := range data.RowEvents {
|
||||||
|
if re.Row.Fields[colIndex] == render.NAValue {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
n, err := strconv.Atoi(re.Row.Fields[colIndex])
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if n > 100 {
|
||||||
|
n = 100
|
||||||
|
}
|
||||||
|
severity := app.Config.K9s.Thresholds.LevelFor(check, n)
|
||||||
|
if severity == config.SeverityLow {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
color := app.Config.K9s.Thresholds.SeverityColor(check, n)
|
||||||
|
if len(color) > 0 {
|
||||||
|
re.Row.Fields[colIndex] = "[" + color + "::b]" + re.Row.Fields[colIndex]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,11 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/atotto/clipboard"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -29,6 +31,9 @@ const (
|
||||||
flushTimeout = 50 * time.Millisecond
|
flushTimeout = 50 * time.Millisecond
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// InvalidCharsRX contains invalid filename characters.
|
||||||
|
var invalidPathCharsRX = regexp.MustCompile(`[:/\\]+`)
|
||||||
|
|
||||||
// Log represents a generic log viewer.
|
// Log represents a generic log viewer.
|
||||||
type Log struct {
|
type Log struct {
|
||||||
*tview.Flex
|
*tview.Flex
|
||||||
|
|
@ -180,13 +185,14 @@ func (l *Log) bindKeys() {
|
||||||
ui.Key4: ui.NewKeyAction("30m", l.sinceCmd(30*60), true),
|
ui.Key4: ui.NewKeyAction("30m", l.sinceCmd(30*60), true),
|
||||||
ui.Key5: ui.NewKeyAction("1h", l.sinceCmd(60*60), true),
|
ui.Key5: ui.NewKeyAction("1h", l.sinceCmd(60*60), true),
|
||||||
tcell.KeyEnter: ui.NewSharedKeyAction("Filter", l.filterCmd, false),
|
tcell.KeyEnter: ui.NewSharedKeyAction("Filter", l.filterCmd, false),
|
||||||
ui.KeyC: ui.NewKeyAction("Clear", l.clearCmd, true),
|
tcell.KeyCtrlK: ui.NewKeyAction("Clear", l.clearCmd, true),
|
||||||
ui.KeyM: ui.NewKeyAction("Mark", l.markCmd, true),
|
ui.KeyM: ui.NewKeyAction("Mark", l.markCmd, true),
|
||||||
ui.KeyS: ui.NewKeyAction("Toggle AutoScroll", l.toggleAutoScrollCmd, true),
|
ui.KeyS: ui.NewKeyAction("Toggle AutoScroll", l.toggleAutoScrollCmd, true),
|
||||||
ui.KeyF: ui.NewKeyAction("Toggle FullScreen", l.toggleFullScreenCmd, true),
|
ui.KeyF: ui.NewKeyAction("Toggle FullScreen", l.toggleFullScreenCmd, true),
|
||||||
ui.KeyT: ui.NewKeyAction("Toggle Timestamp", l.toggleTimestampCmd, true),
|
ui.KeyT: ui.NewKeyAction("Toggle Timestamp", l.toggleTimestampCmd, true),
|
||||||
ui.KeyW: ui.NewKeyAction("Toggle Wrap", l.toggleTextWrapCmd, true),
|
ui.KeyW: ui.NewKeyAction("Toggle Wrap", l.toggleTextWrapCmd, true),
|
||||||
tcell.KeyCtrlS: ui.NewKeyAction("Save", l.SaveCmd, true),
|
tcell.KeyCtrlS: ui.NewKeyAction("Save", l.SaveCmd, true),
|
||||||
|
ui.KeyC: ui.NewKeyAction("Copy", l.cpCmd, true),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -284,18 +290,32 @@ func (l *Log) SaveCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *Log) cpCmd(evt *tcell.EventKey) *tcell.EventKey {
|
||||||
|
l.app.Flash().Info("Content copied to clipboard...")
|
||||||
|
if err := clipboard.WriteAll(l.logs.GetText(true)); err != nil {
|
||||||
|
l.app.Flash().Err(err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func sanitizeFilename(name string) string {
|
||||||
|
processedString := invalidPathCharsRX.ReplaceAllString(name, "-")
|
||||||
|
|
||||||
|
return processedString
|
||||||
|
}
|
||||||
|
|
||||||
func ensureDir(dir string) error {
|
func ensureDir(dir string) error {
|
||||||
return os.MkdirAll(dir, 0744)
|
return os.MkdirAll(dir, 0744)
|
||||||
}
|
}
|
||||||
|
|
||||||
func saveData(cluster, name, data string) (string, error) {
|
func saveData(cluster, name, data string) (string, error) {
|
||||||
dir := filepath.Join(config.K9sDumpDir, cluster)
|
dir := filepath.Join(config.K9sDumpDir, sanitizeFilename(cluster))
|
||||||
if err := ensureDir(dir); err != nil {
|
if err := ensureDir(dir); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
now := time.Now().UnixNano()
|
now := time.Now().UnixNano()
|
||||||
fName := fmt.Sprintf("%s-%d.log", strings.Replace(name, "/", "-", -1), now)
|
fName := fmt.Sprintf("%s-%d.log", sanitizeFilename(name), now)
|
||||||
|
|
||||||
path := filepath.Join(dir, fName)
|
path := filepath.Join(dir, fName)
|
||||||
mod := os.O_CREATE | os.O_WRONLY
|
mod := os.O_CREATE | os.O_WRONLY
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ func TestLogAutoScroll(t *testing.T) {
|
||||||
v.GetModel().Set(dao.LogItems{dao.NewLogItemFromString("blee"), dao.NewLogItemFromString("bozo")})
|
v.GetModel().Set(dao.LogItems{dao.NewLogItemFromString("blee"), dao.NewLogItemFromString("bozo")})
|
||||||
v.GetModel().Notify()
|
v.GetModel().Notify()
|
||||||
|
|
||||||
assert.Equal(t, 14, len(v.Hints()))
|
assert.Equal(t, 15, len(v.Hints()))
|
||||||
|
|
||||||
v.toggleAutoScrollCmd(nil)
|
v.toggleAutoScrollCmd(nil)
|
||||||
assert.Equal(t, "Autoscroll: Off FullScreen: Off Timestamps: Off Wrap: Off", v.Indicator().GetText(true))
|
assert.Equal(t, "Autoscroll: Off FullScreen: Off Timestamps: Off Wrap: Off", v.Indicator().GetText(true))
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ func (p *Pod) portForwardIndicator(data render.TableData) render.TableData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return data
|
return decorateCpuMemHeaderRows(p.App(), data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Pod) bindDangerousKeys(aa ui.KeyActions) {
|
func (p *Pod) bindDangerousKeys(aa ui.KeyActions) {
|
||||||
|
|
|
||||||
|
|
@ -18,12 +18,12 @@ import (
|
||||||
func computeFilename(cluster, ns, title, path string) (string, error) {
|
func computeFilename(cluster, ns, title, path string) (string, error) {
|
||||||
now := time.Now().UnixNano()
|
now := time.Now().UnixNano()
|
||||||
|
|
||||||
dir := filepath.Join(config.K9sDumpDir, cluster)
|
dir := filepath.Join(config.K9sDumpDir, sanitizeFilename(cluster))
|
||||||
if err := ensureDir(dir); err != nil {
|
if err := ensureDir(dir); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
name := title + "-" + strings.Replace(path, "/", "-", -1)
|
name := title + "-" + sanitizeFilename(path)
|
||||||
if path == "" {
|
if path == "" {
|
||||||
name = title
|
name = title
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,13 +61,13 @@ func enableRegion(str string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func saveYAML(cluster, name, data string) (string, error) {
|
func saveYAML(cluster, name, data string) (string, error) {
|
||||||
dir := filepath.Join(config.K9sDumpDir, cluster)
|
dir := filepath.Join(config.K9sDumpDir, sanitizeFilename(cluster))
|
||||||
if err := ensureDir(dir); err != nil {
|
if err := ensureDir(dir); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
now := time.Now().UnixNano()
|
now := time.Now().UnixNano()
|
||||||
fName := fmt.Sprintf("%s-%d.yml", strings.Replace(name, "/", "-", -1), now)
|
fName := fmt.Sprintf("%s-%d.yml", sanitizeFilename(name), now)
|
||||||
|
|
||||||
path := filepath.Join(dir, fName)
|
path := filepath.Join(dir, fName)
|
||||||
mod := os.O_CREATE | os.O_WRONLY
|
mod := os.O_CREATE | os.O_WRONLY
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,9 @@
|
||||||
K9s plugins extend the tool to provide additonal functionality via actions to further help you observe or administer your Kubernetes clusters.
|
K9s plugins extend the tool to provide additonal functionality via actions to further help you observe or administer your Kubernetes clusters.
|
||||||
|
|
||||||
| Plugin-Name | Description | Available on Views | Shortcut | Kubectl plugin, external dependencies |
|
| Plugin-Name | Description | Available on Views | Shortcut | Kubectl plugin, external dependencies |
|
||||||
|-----------------|--------------------------------|--------------------|----------|-------------------------------------------|
|
|-----------------|----------------------------------|--------------------|----------|---------------------------------------------------------------------------------------|
|
||||||
| log_stern.yml | View resource logs using stern | pods | Ctrl-l | |
|
| log_stern.yml | View resource logs using stern | pods | Ctrl-l | |
|
||||||
| log_jq.yml | View resource logs using jq | pods | Ctrl-j | kubetcl-plugins/kubectl-jq |
|
| log_jq.yml | View resource logs using jq | pods | Ctrl-j | kubetcl-plugins/kubectl-jq |
|
||||||
| job_suspend.yml | Suspends a running cronjob | cronjobs | Ctrl-s | |
|
| job_suspend.yml | Suspends a running cronjob | cronjobs | Ctrl-s | |
|
||||||
| dive.yml | Dive image layers | containers | d | [Dive](https://github.com/wagoodman/dive) |
|
| dive.yml | Dive image layers | containers | d | [Dive](https://github.com/wagoodman/dive) |
|
||||||
|
| get-all.yml | get all resources in a namespace | all | g | [Krew](https://krew.sigs.k8s.io/), [ketall](https://github.com/corneliusweig/ketall/) |
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
plugin:
|
||||||
|
#get all resources in a namespace using the krew get-all plugin
|
||||||
|
get-all:
|
||||||
|
shortCut: g
|
||||||
|
confirm: false
|
||||||
|
description: get-all
|
||||||
|
scopes:
|
||||||
|
- all
|
||||||
|
command: sh
|
||||||
|
background: false
|
||||||
|
args:
|
||||||
|
- -c
|
||||||
|
- "kubectl get-all -n $NAMESPACE | less"
|
||||||
Loading…
Reference in New Issue