add rel notes + cleanup

mine
derailed 2020-07-23 11:35:01 -06:00
parent 6b666b166c
commit 251221c19b
9 changed files with 129 additions and 49 deletions

View File

@ -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.21.2 VERSION ?= v0.21.3
IMG_NAME := derailed/k9s IMG_NAME := derailed/k9s
IMAGE := ${IMG_NAME}:${VERSION} IMAGE := ${IMG_NAME}:${VERSION}

View File

@ -0,0 +1,49 @@
<img src="https://raw.githubusercontent.com/derailed/k9s/master/assets/k9s_small.png" align="right" width="200" height="auto"/>
# Release v0.21.3
## 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 is as ever very much noticed 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)
---
## ♫ The Sound Behind The Release ♭
And now for something a `beat` different?
I figured, why not share one of the tunes I was spinning when powering thru teh bugs? Might as well share the pain/pleasure roaght?
[Funkin' for Jamaica](https://www.youtube.com/watch?v=uuUy2ShGLyo) by the most awesome Tom Browne!
Maintenance Release!
Lots of bugs fix in this drop and perf improvements...
NOTE! You may experience some disturbance in the force in this drop, so please proceed with caution and do land a hand flushing out potential issues.
Thank you!!
## Video Tutorial
[Who Let The Pods Out (v0.21.3)](https://youtu.be/wG8KCwDAhnw)
## Resolved Bugs/Features/PRs
* [Issue #816](https://github.com/derailed/k9s/issues/816)
* [Issue #813](https://github.com/derailed/k9s/issues/813)
* [Issue #812](https://github.com/derailed/k9s/issues/812)
* [Issue #810](https://github.com/derailed/k9s/issues/810)
* [Issue #807](https://github.com/derailed/k9s/issues/807)
* [Issue #806](https://github.com/derailed/k9s/issues/806)
* [Issue #805](https://github.com/derailed/k9s/issues/805)
* [Issue #800](https://github.com/derailed/k9s/issues/800)
* [Issue #799](https://github.com/derailed/k9s/issues/799)
* [Issue #709](https://github.com/derailed/k9s/issues/709) Crossing fingers and toes ;)
---
<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

@ -10,7 +10,6 @@ import (
"github.com/derailed/k9s/internal" "github.com/derailed/k9s/internal"
"github.com/derailed/k9s/internal/render" "github.com/derailed/k9s/internal/render"
"github.com/rs/zerolog/log"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
) )
@ -49,14 +48,11 @@ func (b *Benchmark) List(ctx context.Context, _ string) ([]runtime.Object, error
oo := make([]runtime.Object, 0, len(ff)) oo := make([]runtime.Object, 0, len(ff))
for _, f := range ff { for _, f := range ff {
log.Debug().Msgf("BENCH-LIST %q::%q", strings.Replace(path, "/", "_", 1), f.Name())
if path != "" && !strings.HasPrefix(f.Name(), strings.Replace(path, "/", "_", 1)) { if path != "" && !strings.HasPrefix(f.Name(), strings.Replace(path, "/", "_", 1)) {
log.Debug().Msgf(" SKIP...")
continue continue
} }
oo = append(oo, render.BenchInfo{File: f, Path: filepath.Join(dir, f.Name())}) oo = append(oo, render.BenchInfo{File: f, Path: filepath.Join(dir, f.Name())})
} }
log.Debug().Msgf("BENCH-FILES %#v", oo)
return oo, nil return oo, nil
} }

View File

@ -6,6 +6,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"time"
"github.com/derailed/k9s/internal" "github.com/derailed/k9s/internal"
"github.com/derailed/k9s/internal/client" "github.com/derailed/k9s/internal/client"
@ -28,6 +29,11 @@ var (
_ Controller = (*Pod)(nil) _ Controller = (*Pod)(nil)
) )
const (
logRetryCount = 20
logRetryWait = 1 * time.Second
)
// Pod represents a pod resource. // Pod represents a pod resource.
type Pod struct { type Pod struct {
Resource Resource
@ -321,19 +327,43 @@ func (p *Pod) Scan(ctx context.Context, gvr, fqn string, wait bool) (Refs, error
func tailLogs(ctx context.Context, logger Logger, c LogChan, opts LogOptions) error { func tailLogs(ctx context.Context, logger Logger, c LogChan, opts LogOptions) error {
log.Debug().Msgf("Tailing logs for %q:%q", opts.Path, opts.Container) log.Debug().Msgf("Tailing logs for %q:%q", opts.Path, opts.Container)
req, err := logger.Logs(opts.Path, opts.ToPodLogOptions())
if err != nil { var (
return err err error
req *restclient.Request
stream io.ReadCloser
)
done:
for r := 0; r < logRetryCount; r++ {
log.Debug().Msgf("Retry logs %d", r)
req, err = logger.Logs(opts.Path, opts.ToPodLogOptions())
if err == nil {
// This call will block if nothing is in the stream!!
if stream, err = req.Stream(ctx); err == nil {
log.Debug().Msgf("Reading logs")
go readLogs(stream, c, opts)
break
} else {
log.Error().Err(err).Msg("Streaming logs")
}
} else {
log.Error().Err(err).Msg("Requesting logs")
}
select {
case <-ctx.Done():
err = ctx.Err()
break done
default:
time.Sleep(logRetryWait)
}
} }
// This call will block if nothing is in the stream!!
stream, err := req.Stream(ctx)
if err != nil { if err != nil {
c <- opts.DecorateLog([]byte(err.Error() + "\n"))
log.Error().Err(err).Msgf("Unable to obtain log stream failed for `%s", opts.Path) log.Error().Err(err).Msgf("Unable to obtain log stream failed for `%s", opts.Path)
c <- opts.DecorateLog([]byte("\n" + err.Error() + "\n"))
return err return err
} }
go readLogs(stream, c, opts)
return nil return nil
} }
@ -352,11 +382,11 @@ func readLogs(stream io.ReadCloser, c LogChan, opts LogOptions) {
if err != nil { if err != nil {
if err == io.EOF { if err == io.EOF {
log.Warn().Err(err).Msgf("Stream closed for %s", opts.Info()) log.Warn().Err(err).Msgf("Stream closed for %s", opts.Info())
c <- opts.DecorateLog([]byte("log stream closed\n")) c <- opts.DecorateLog([]byte("\nlog stream closed\n"))
return return
} }
log.Warn().Err(err).Msgf("Stream READ error %s", opts.Info()) log.Warn().Err(err).Msgf("Stream READ error %s", opts.Info())
c <- opts.DecorateLog([]byte(fmt.Sprintf("log stream failed: %#v\n", err))) c <- opts.DecorateLog([]byte(fmt.Sprintf("\nlog stream failed: %#v\n", err)))
return return
} }
c <- opts.DecorateLog(bytes) c <- opts.DecorateLog(bytes)

View File

@ -202,13 +202,15 @@ func (l *Log) load() error {
if !ok { if !ok {
return fmt.Errorf("Resource %s is not Loggable", l.gvr) return fmt.Errorf("Resource %s is not Loggable", l.gvr)
} }
if err := logger.TailLogs(ctx, c, l.logOptions); err != nil {
log.Error().Err(err).Msgf("Tail logs failed") go func() {
if l.cancelFn != nil { if err = logger.TailLogs(ctx, c, l.logOptions); err != nil {
l.cancelFn() log.Error().Err(err).Msgf("Tail logs failed")
if l.cancelFn != nil {
l.cancelFn()
}
} }
return err }()
}
return nil return nil
} }

View File

@ -47,20 +47,18 @@ func NewBenchmark(base, version string, cfg config.BenchConfig) (*Benchmark, err
} }
func (b *Benchmark) init(base, version string) error { func (b *Benchmark) init(base, version string) error {
req, err := http.NewRequest(b.config.HTTP.Method, base, nil) var ctx context.Context
ctx, b.cancelFn = context.WithTimeout(context.Background(), benchTimeout)
req, err := http.NewRequestWithContext(ctx, b.config.HTTP.Method, base, nil)
if err != nil { if err != nil {
return err return err
} }
log.Debug().Msgf("Benchmarking Request %s", req.URL.String())
if b.config.Auth.User != "" || b.config.Auth.Password != "" { if b.config.Auth.User != "" || b.config.Auth.Password != "" {
req.SetBasicAuth(b.config.Auth.User, b.config.Auth.Password) req.SetBasicAuth(b.config.Auth.User, b.config.Auth.Password)
} }
var ctx context.Context
ctx, b.cancelFn = context.WithTimeout(context.Background(), benchTimeout)
req = req.WithContext(ctx)
req.Header = b.config.HTTP.Headers req.Header = b.config.HTTP.Headers
log.Debug().Msgf("Benchmarking Request %s", req.URL.String())
ua := req.UserAgent() ua := req.UserAgent()
if ua == "" { if ua == "" {
ua = k9sUA ua = k9sUA
@ -73,7 +71,7 @@ func (b *Benchmark) init(base, version string) error {
} }
req.Header.Set("User-Agent", ua) req.Header.Set("User-Agent", ua)
log.Debug().Msgf("Benching %d:%d", b.config.N, b.config.C) log.Debug().Msgf("Using bench config N:%d--C:%d", b.config.N, b.config.C)
b.worker = &requester.Work{ b.worker = &requester.Work{
Request: req, Request: req,
@ -81,7 +79,6 @@ func (b *Benchmark) init(base, version string) error {
N: b.config.N, N: b.config.N,
C: b.config.C, C: b.config.C,
H2: b.config.HTTP.HTTP2, H2: b.config.HTTP.HTTP2,
Output: "",
} }
return nil return nil
@ -89,12 +86,12 @@ func (b *Benchmark) init(base, version string) error {
// Cancel kills the benchmark in progress. // Cancel kills the benchmark in progress.
func (b *Benchmark) Cancel() { func (b *Benchmark) Cancel() {
b.mx.Lock()
defer b.mx.Unlock()
if b == nil { if b == nil {
return return
} }
b.mx.Lock()
defer b.mx.Unlock()
b.canceled = true b.canceled = true
if b.cancelFn != nil { if b.cancelFn != nil {
b.cancelFn() b.cancelFn()

View File

@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"path" "path"
"strings"
"github.com/derailed/k9s/internal" "github.com/derailed/k9s/internal"
"github.com/derailed/k9s/internal/client" "github.com/derailed/k9s/internal/client"
@ -141,11 +142,6 @@ func (d *Dir) applyCmd(evt *tcell.EventKey) *tcell.EventKey {
return evt return evt
} }
if !isManifest(sel) {
d.App().Flash().Errf("you must select a manifest")
return nil
}
d.Stop() d.Stop()
defer d.Start() defer d.Start()
{ {
@ -155,9 +151,9 @@ func (d *Dir) applyCmd(evt *tcell.EventKey) *tcell.EventKey {
args = append(args, sel) args = append(args, sel)
res, err := runKu(d.App(), shellOpts{clear: false, args: args}) res, err := runKu(d.App(), shellOpts{clear: false, args: args})
if err != nil { if err != nil {
res = "error:\n " + err.Error() res = "status:\n " + err.Error() + "\nmessage:\n" + fmtResults(res)
} else { } else {
res = "message:\n " + res res = "message:\n" + fmtResults(res)
} }
details := NewDetails(d.App(), "Applied Manifest", sel, true).Update(res) details := NewDetails(d.App(), "Applied Manifest", sel, true).Update(res)
@ -175,11 +171,6 @@ func (d *Dir) delCmd(evt *tcell.EventKey) *tcell.EventKey {
return evt return evt
} }
if !isManifest(sel) {
d.App().Flash().Errf("you must select a manifest")
return nil
}
d.Stop() d.Stop()
defer d.Start() defer d.Start()
msg := fmt.Sprintf("Delete resource(s) in manifest %s", sel) msg := fmt.Sprintf("Delete resource(s) in manifest %s", sel)
@ -190,9 +181,9 @@ func (d *Dir) delCmd(evt *tcell.EventKey) *tcell.EventKey {
args = append(args, sel) args = append(args, sel)
res, err := runKu(d.App(), shellOpts{clear: false, args: args}) res, err := runKu(d.App(), shellOpts{clear: false, args: args})
if err != nil { if err != nil {
res = "error:\n " + err.Error() + "\nmessage:\n " + res res = "status:\n " + err.Error() + "\nmessage:\n" + fmtResults(res)
} else { } else {
res = "message:\n " + res res = "message:\n" + fmtResults(res)
} }
details := NewDetails(d.App(), "Deleted Manifest", sel, true).Update(res) details := NewDetails(d.App(), "Deleted Manifest", sel, true).Update(res)
if err := d.App().inject(details); err != nil { if err := d.App().inject(details); err != nil {
@ -202,3 +193,13 @@ func (d *Dir) delCmd(evt *tcell.EventKey) *tcell.EventKey {
return nil return nil
} }
func fmtResults(res string) string {
res = strings.TrimSpace(res)
lines := strings.Split(res, "\n")
ll := make([]string, 0, len(lines))
for _, l := range lines {
ll = append(ll, " "+l)
}
return strings.Join(ll, "\n")
}

View File

@ -141,6 +141,8 @@ func (n *Node) sshCmd(evt *tcell.EventKey) *tcell.EventKey {
return evt return evt
} }
n.Stop()
defer n.Start()
_, node := client.Namespaced(path) _, node := client.Namespaced(path)
if err := ssh(n.App(), node); err != nil { if err := ssh(n.App(), node); err != nil {
log.Error().Err(err).Msgf("SSH Failed") log.Error().Err(err).Msgf("SSH Failed")
@ -155,6 +157,8 @@ func (n *Node) yamlCmd(evt *tcell.EventKey) *tcell.EventKey {
return evt return evt
} }
n.Stop()
defer n.Start()
ctx, cancel := context.WithTimeout(context.Background(), n.App().Conn().Config().CallTimeout()) ctx, cancel := context.WithTimeout(context.Background(), n.App().Conn().Config().CallTimeout())
defer cancel() defer cancel()

View File

@ -91,9 +91,10 @@ func (p *PortForward) toggleBenchCmd(evt *tcell.EventKey) *tcell.EventKey {
cfg.Name = path cfg.Name = path
r, _ := p.GetTable().GetSelection() r, _ := p.GetTable().GetSelection()
col := 4 log.Debug().Msgf("PF NS %q", p.GetTable().GetModel().GetNamespace())
if client.IsAllNamespace(p.GetTable().GetModel().GetNamespace()) { col := 3
col = 3 if client.IsAllNamespaces(p.GetTable().GetModel().GetNamespace()) {
col = 4
} }
base := ui.TrimCell(p.GetTable().SelectTable, r, col) base := ui.TrimCell(p.GetTable().SelectTable, r, col)
var err error var err error