resolve conflicts

mine
derailed 2020-07-02 18:05:26 -06:00
commit 874226a1b3
9 changed files with 92 additions and 15 deletions

View File

@ -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 }

View File

@ -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
}

View File

@ -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

View File

@ -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))

View File

@ -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) {

View File

@ -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
} }

View File

@ -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

View File

@ -2,9 +2,10 @@
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/) |

13
plugins/get-all.yml Normal file
View File

@ -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"