K9s: rel v0.25.4 (#1322)

* release v0.25.4

* update docs

* update docs
mine
Fernand Galiana 2021-11-20 13:23:26 -07:00 committed by GitHub
parent f4007fa0ce
commit 165ffeab93
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 91 additions and 80 deletions

View File

@ -5,7 +5,7 @@ PACKAGE := github.com/derailed/$(NAME)
GIT_REV ?= $(shell git rev-parse --short HEAD)
SOURCE_DATE_EPOCH ?= $(shell date +%s)
DATE ?= $(shell date -u -d @${SOURCE_DATE_EPOCH} +"%Y-%m-%dT%H:%M:%SZ")
VERSION ?= v0.25.2
VERSION ?= v0.25.4
IMG_NAME := derailed/k9s
IMAGE := ${IMG_NAME}:${VERSION}

View File

@ -278,12 +278,11 @@ K9s uses aliases to navigate most K8s resources.
## K9s Configuration
K9s keeps its configurations inside of a `k9s` directory and the location depends on your operating system. K9s leverages [XDG](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html) to load its various configurations files. For information on the default locations for your OS please see [this link](https://github.com/adrg/xdg/blob/master/README.md). If you are still confused a quick `k9s info` will reveal where k9s is loading its configurations from. if `XDG_CONFIG_HOME` is unset, then K9s will default to look for its configuration in `$HOME/.config/k9s`. Alternatively, you can set `K9SCONFIG` to tell K9s the directory location to pull its configurations from.
K9s keeps its configurations inside of a `k9s` directory and the location depends on your operating system. K9s leverages [XDG](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html) to load its various configurations files. For information on the default locations for your OS please see [this link](https://github.com/adrg/xdg/blob/master/README.md). If you are still confused a quick `k9s info` will reveal where k9s is loading its configurations from. Alternatively, you can set `K9SCONFIG` to tell K9s the directory location to pull its configurations from.
| Unix | macOS | Windows |
|-----------------|-----------------------------|-----------------------|
| `~/.config/k9s` | `~/Library/Preferences/k9s` | `%LOCALAPPDATA%\k9s` |
| Unix | macOS | Windows |
|-----------------|------------------------------------|-----------------------|
| `~/.config/k9s` | `~/Library/Application Support/k9s` | `%LOCALAPPDATA%\k9s` |
> NOTE: This is still in flux and will change while in pre-release stage!

View File

@ -0,0 +1,25 @@
<img src="https://raw.githubusercontent.com/derailed/k9s/master/assets/k9s_small.png" align="right" width="200" height="auto"/>
# Release v0.25.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 [sponsorship 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
* [Issue #1319](https://github.com/derailed/k9s/issues/1319) Namespace filters are no longer applied on startup
* [Issue #1317](https://github.com/derailed/k9s/issues/1317) port forwarding broke with multiple exposed ports
* [Issue #1316](https://github.com/derailed/k9s/issues/1316) Configuration for macOS is using wrong path
---
<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)

View File

@ -4,7 +4,6 @@ import (
"errors"
"fmt"
"os"
"path"
"path/filepath"
"github.com/adrg/xdg"
@ -60,14 +59,6 @@ func K9sHome() string {
if env := os.Getenv(K9sConfig); env != "" {
return env
}
if env := os.Getenv("XDG_CONFIG_HOME"); env == "" {
dir, err := os.UserHomeDir()
if err != nil {
log.Error().Err(err).Msgf("user home dir")
return ""
}
return path.Join(dir, ".config", "k9s")
}
xdgK9sHome, err := xdg.ConfigFile("k9s")
if err != nil {
@ -116,6 +107,8 @@ func (c *Config) Refine(flags *genericclioptions.ConfigFlags, k9sFlags *Flags, c
ns, override = *flags.Namespace, true
} else if context.Namespace != "" {
ns = context.Namespace
} else if cl := c.K9s.ActiveCluster(); cl != nil {
ns = cl.Namespace.Active
}
if ns != "" {

View File

@ -129,12 +129,6 @@ func (f *FishBuff) fireSuggestionChanged(ss []string) {
} else {
suggest = ss[f.suggestionIndex]
}
f.SetText(f.GetText(), suggest)
f.SetText(f.GetText(), suggest)
// BOZO!!
//for _, l := range f.listeners {
// if listener, ok := l.(SuggestionListener); ok {
// listener.SuggestionChanged(text, sug)
// }
//}
}

View File

@ -20,6 +20,17 @@ func (c ContainerPortSpecs) Dump() string {
return strings.Join(ss, "\n")
}
// InSpecs checks if given port matches a spec.
func (c ContainerPortSpecs) MatchSpec(s string) bool {
for _, spec := range c {
if spec.MatchSpec(s) {
return true
}
}
return false
}
// ToTunnels convert port specs to tunnels.
func (c ContainerPortSpecs) ToTunnels(address string) PortTunnels {
tt := make(PortTunnels, 0, len(c))
@ -97,6 +108,15 @@ func NewPortSpec(co, portName string, port int32) ContainerPortSpec {
}
}
func (c ContainerPortSpec) MatchSpec(s string) bool {
tokens := strings.Split(s, "::")
if len(tokens) < 2 {
return false
}
return tokens[0] == c.Container && tokens[1] == c.PortNum
}
func (c ContainerPortSpec) ToTunnel(address string) PortTunnel {
return PortTunnel{
Address: address,

View File

@ -127,14 +127,14 @@ func accessMode(aa []v1.PersistentVolumeAccessMode) string {
dd := accessDedup(aa)
s := make([]string, 0, len(dd))
for _, am := range dd {
switch {
case am == v1.ReadWriteOnce:
switch am {
case v1.ReadWriteOnce:
s = append(s, "RWO")
case am == v1.ReadOnlyMany:
case v1.ReadOnlyMany:
s = append(s, "ROX")
case am == v1.ReadWriteMany:
case v1.ReadWriteMany:
s = append(s, "RWX")
case am == v1.ReadWriteOncePod:
case v1.ReadWriteOncePod:
s = append(s, "RWOP")
}
}

View File

@ -28,7 +28,7 @@ func ShowError(styles config.Dialog, pages *ui.Pages, msg string) {
}
f.SetFocus(0)
modal := tview.NewModalForm("<error>", f)
modal.SetText(cowTalk(f, msg))
modal.SetText(cowTalk(msg))
modal.SetTextColor(tcell.ColorOrangeRed)
modal.SetDoneFunc(func(int, string) {
dismissError(pages)
@ -41,7 +41,7 @@ func dismissError(pages *ui.Pages) {
pages.RemovePage(confirmKey)
}
func cowTalk(f *tview.Form, says string) string {
func cowTalk(says string) string {
msg := fmt.Sprintf("< Ruroh? %s >", says)
buff := make([]string, 0, len(cow)+3)
buff = append(buff, msg)

View File

@ -91,13 +91,7 @@ func (a *App) Init(version string, rate int) error {
if a.Conn() == nil {
return errors.New("No client connection detected")
}
ns, err := a.Conn().Config().CurrentNamespaceName()
log.Debug().Msgf("CURRENT-NS %q -- %v", ns, err)
if err != nil {
log.Info().Msg("No namespace specified using cluster default namespace")
} else if err = a.Config.SetActiveNamespace(ns); err != nil {
log.Error().Err(err).Msgf("Fail to set active namespace to %q", ns)
}
ns := a.Config.ActiveNamespace()
a.factory = watch.NewFactory(a.Conn())
ok, err := a.isValidNS(ns)

View File

@ -127,6 +127,9 @@ func (b *Browser) SetInstance(path string) {
// Start initializes browser updates.
func (b *Browser) Start() {
b.app.Config.ValidateFavorites()
if err := b.app.switchNS(b.GetModel().GetNamespace()); err != nil {
log.Error().Err(err).Msgf("ns switch failed")
}
if err := b.app.Config.Save(); err != nil {
log.Error().Err(err).Msgf("Config Save")
}

View File

@ -155,11 +155,8 @@ func (c *Command) defaultCmd() error {
}
tokens := strings.Split(view, " ")
cmd := view
if len(tokens) == 1 || c.app.Conn().Config().OverrideNS {
ns, err := c.app.Conn().Config().CurrentNamespaceName()
if err == nil && !isContextCmd(tokens[0]) {
cmd = tokens[0] + " " + ns
}
if len(tokens) == 1 {
cmd = tokens[0] + " " + c.app.Config.ActiveNamespace()
}
if err := c.run(cmd, "", true); err != nil {

View File

@ -374,6 +374,7 @@ func pipe(ctx context.Context, opts shellOpts, cmds ...*exec.Cmd) error {
return cmd.Start()
}
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
// BOZO!!
//cmd.SysProcAttr = &syscall.SysProcAttr{
//// //Setpgid: true,
//// //Setctty: true,
@ -385,6 +386,8 @@ func pipe(ctx context.Context, opts shellOpts, cmds ...*exec.Cmd) error {
err := cmd.Run()
log.Debug().Msgf("Running Done")
return err
// BOZO!!
// select {
// case <-ctx.Done():
// return errors.New("canceled by operator")

View File

@ -3,12 +3,9 @@ package view
import (
"fmt"
"math"
"regexp"
"strings"
"github.com/derailed/k9s/internal/client"
"github.com/derailed/k9s/internal/port"
"github.com/derailed/k9s/internal/render"
"github.com/derailed/k9s/internal/ui"
"github.com/derailed/tview"
"github.com/rs/zerolog/log"
@ -47,13 +44,13 @@ func ShowPortForwards(v ResourceViewer, path string, ports port.ContainerPortSpe
coField.SetPlaceholder("Enter a container name/port")
}
f.AddInputField("Local Port:", p2, fieldLen, nil, nil)
poField := f.GetFormItemByLabel("Local Port:").(*tview.InputField)
if poField.GetText() == "" {
poField.SetPlaceholder("Enter a local port")
loField := f.GetFormItemByLabel("Local Port:").(*tview.InputField)
if loField.GetText() == "" {
loField.SetPlaceholder("Enter a local port")
}
coField.SetChangedFunc(func(s string) {
port := extractPort(s)
poField.SetText(port)
loField.SetText(port)
p2 = port
})
f.AddInputField("Address:", address, fieldLen, nil, func(h string) {
@ -69,11 +66,15 @@ func ShowPortForwards(v ResourceViewer, path string, ports port.ContainerPortSpe
}
f.AddButton("OK", func() {
if coField.GetText() == "" || poField.GetText() == "" {
if coField.GetText() == "" || loField.GetText() == "" {
v.App().Flash().Err(fmt.Errorf("container to local port mismatch"))
return
}
tt, err := port.ToTunnels(address, coField.GetText(), poField.GetText())
if !ports.MatchSpec(coField.GetText()) {
v.App().Flash().Err(fmt.Errorf("invalid container port"))
return
}
tt, err := port.ToTunnels(address, coField.GetText(), loField.GetText())
if err != nil {
v.App().Flash().Err(err)
return
@ -121,26 +122,11 @@ func DismissPortForwards(v ResourceViewer, p *ui.Pages) {
// ----------------------------------------------------------------------------
// Helpers...
func extractPort(p string) string {
rx := regexp.MustCompile(`\A([\w|-]+)/?([\w|-]+)?:?(\d+)?(UDP)?\z`)
mm := rx.FindStringSubmatch(p)
if len(mm) != 5 {
return p
}
for i := 3; i > 0; i-- {
if mm[i] != "" {
return mm[i]
}
}
return p
}
func extractContainer(p string) string {
tokens := strings.Split(p, ":")
if len(tokens) != 2 {
return render.NAValue
func extractPort(coPort string) string {
tokens := strings.Split(coPort, "::")
if len(tokens) < 2 {
return ""
}
co, _ := client.Namespaced(tokens[0])
return co
return tokens[1]
}

View File

@ -6,25 +6,23 @@ import (
"github.com/stretchr/testify/assert"
)
func TestExtractContainer(t *testing.T) {
func TestExtractPort(t *testing.T) {
uu := map[string]struct {
port, e string
portSpec, e string
}{
"full": {
"co/port:8000", "co",
portSpec: "co::8000",
e: "8000",
},
"unamed": {
"co/:8000", "co",
},
"protocol": {
"co/dns:53UDP", "co",
"toast": {
portSpec: "co:8000",
},
}
for k := range uu {
u := uu[k]
t.Run(k, func(t *testing.T) {
assert.Equal(t, u.e, extractContainer(u.port))
assert.Equal(t, u.e, extractPort(u.portSpec))
})
}
}

View File

@ -31,7 +31,6 @@ func (r *RestartExtender) bindKeys(aa ui.KeyActions) {
return
}
aa.Add(ui.KeyActions{
// BOZO!!
ui.KeyR: ui.NewKeyAction("Restart", r.restartCmd, true),
})
}