add rel notes + cleanup
parent
6b666b166c
commit
251221c19b
2
Makefile
2
Makefile
|
|
@ -3,7 +3,7 @@ PACKAGE := github.com/derailed/$(NAME)
|
|||
GIT := $(shell git rev-parse --short HEAD)
|
||||
SOURCE_DATE_EPOCH ?= $(shell date +%s)
|
||||
DATE := $(shell date -u -d @${SOURCE_DATE_EPOCH} +%FT%T%Z)
|
||||
VERSION ?= v0.21.2
|
||||
VERSION ?= v0.21.3
|
||||
IMG_NAME := derailed/k9s
|
||||
IMAGE := ${IMG_NAME}:${VERSION}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -10,7 +10,6 @@ import (
|
|||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/render"
|
||||
"github.com/rs/zerolog/log"
|
||||
"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))
|
||||
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)) {
|
||||
log.Debug().Msgf(" SKIP...")
|
||||
continue
|
||||
}
|
||||
oo = append(oo, render.BenchInfo{File: f, Path: filepath.Join(dir, f.Name())})
|
||||
}
|
||||
log.Debug().Msgf("BENCH-FILES %#v", oo)
|
||||
|
||||
return oo, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
|
|
@ -28,6 +29,11 @@ var (
|
|||
_ Controller = (*Pod)(nil)
|
||||
)
|
||||
|
||||
const (
|
||||
logRetryCount = 20
|
||||
logRetryWait = 1 * time.Second
|
||||
)
|
||||
|
||||
// Pod represents a pod resource.
|
||||
type Pod struct {
|
||||
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 {
|
||||
log.Debug().Msgf("Tailing logs for %q:%q", opts.Path, opts.Container)
|
||||
req, err := logger.Logs(opts.Path, opts.ToPodLogOptions())
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
var (
|
||||
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 {
|
||||
c <- opts.DecorateLog([]byte(err.Error() + "\n"))
|
||||
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
|
||||
}
|
||||
go readLogs(stream, c, opts)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -352,11 +382,11 @@ func readLogs(stream io.ReadCloser, c LogChan, opts LogOptions) {
|
|||
if err != nil {
|
||||
if err == io.EOF {
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
c <- opts.DecorateLog(bytes)
|
||||
|
|
|
|||
|
|
@ -202,13 +202,15 @@ func (l *Log) load() error {
|
|||
if !ok {
|
||||
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")
|
||||
if l.cancelFn != nil {
|
||||
l.cancelFn()
|
||||
|
||||
go func() {
|
||||
if err = logger.TailLogs(ctx, c, l.logOptions); err != nil {
|
||||
log.Error().Err(err).Msgf("Tail logs failed")
|
||||
if l.cancelFn != nil {
|
||||
l.cancelFn()
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,20 +47,18 @@ func NewBenchmark(base, version string, cfg config.BenchConfig) (*Benchmark, err
|
|||
}
|
||||
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
log.Debug().Msgf("Benchmarking Request %s", req.URL.String())
|
||||
|
||||
if 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
|
||||
log.Debug().Msgf("Benchmarking Request %s", req.URL.String())
|
||||
|
||||
ua := req.UserAgent()
|
||||
if ua == "" {
|
||||
ua = k9sUA
|
||||
|
|
@ -73,7 +71,7 @@ func (b *Benchmark) init(base, version string) error {
|
|||
}
|
||||
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{
|
||||
Request: req,
|
||||
|
|
@ -81,7 +79,6 @@ func (b *Benchmark) init(base, version string) error {
|
|||
N: b.config.N,
|
||||
C: b.config.C,
|
||||
H2: b.config.HTTP.HTTP2,
|
||||
Output: "",
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
@ -89,12 +86,12 @@ func (b *Benchmark) init(base, version string) error {
|
|||
|
||||
// Cancel kills the benchmark in progress.
|
||||
func (b *Benchmark) Cancel() {
|
||||
b.mx.Lock()
|
||||
defer b.mx.Unlock()
|
||||
|
||||
if b == nil {
|
||||
return
|
||||
}
|
||||
|
||||
b.mx.Lock()
|
||||
defer b.mx.Unlock()
|
||||
b.canceled = true
|
||||
if b.cancelFn != nil {
|
||||
b.cancelFn()
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"fmt"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/derailed/k9s/internal"
|
||||
"github.com/derailed/k9s/internal/client"
|
||||
|
|
@ -141,11 +142,6 @@ func (d *Dir) applyCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
return evt
|
||||
}
|
||||
|
||||
if !isManifest(sel) {
|
||||
d.App().Flash().Errf("you must select a manifest")
|
||||
return nil
|
||||
}
|
||||
|
||||
d.Stop()
|
||||
defer d.Start()
|
||||
{
|
||||
|
|
@ -155,9 +151,9 @@ func (d *Dir) applyCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
args = append(args, sel)
|
||||
res, err := runKu(d.App(), shellOpts{clear: false, args: args})
|
||||
if err != nil {
|
||||
res = "error:\n " + err.Error()
|
||||
res = "status:\n " + err.Error() + "\nmessage:\n" + fmtResults(res)
|
||||
} else {
|
||||
res = "message:\n " + res
|
||||
res = "message:\n" + fmtResults(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
|
||||
}
|
||||
|
||||
if !isManifest(sel) {
|
||||
d.App().Flash().Errf("you must select a manifest")
|
||||
return nil
|
||||
}
|
||||
|
||||
d.Stop()
|
||||
defer d.Start()
|
||||
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)
|
||||
res, err := runKu(d.App(), shellOpts{clear: false, args: args})
|
||||
if err != nil {
|
||||
res = "error:\n " + err.Error() + "\nmessage:\n " + res
|
||||
res = "status:\n " + err.Error() + "\nmessage:\n" + fmtResults(res)
|
||||
} else {
|
||||
res = "message:\n " + res
|
||||
res = "message:\n" + fmtResults(res)
|
||||
}
|
||||
details := NewDetails(d.App(), "Deleted Manifest", sel, true).Update(res)
|
||||
if err := d.App().inject(details); err != nil {
|
||||
|
|
@ -202,3 +193,13 @@ func (d *Dir) delCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
|
||||
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")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,6 +141,8 @@ func (n *Node) sshCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
return evt
|
||||
}
|
||||
|
||||
n.Stop()
|
||||
defer n.Start()
|
||||
_, node := client.Namespaced(path)
|
||||
if err := ssh(n.App(), node); err != nil {
|
||||
log.Error().Err(err).Msgf("SSH Failed")
|
||||
|
|
@ -155,6 +157,8 @@ func (n *Node) yamlCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
return evt
|
||||
}
|
||||
|
||||
n.Stop()
|
||||
defer n.Start()
|
||||
ctx, cancel := context.WithTimeout(context.Background(), n.App().Conn().Config().CallTimeout())
|
||||
defer cancel()
|
||||
|
||||
|
|
|
|||
|
|
@ -91,9 +91,10 @@ func (p *PortForward) toggleBenchCmd(evt *tcell.EventKey) *tcell.EventKey {
|
|||
cfg.Name = path
|
||||
|
||||
r, _ := p.GetTable().GetSelection()
|
||||
col := 4
|
||||
if client.IsAllNamespace(p.GetTable().GetModel().GetNamespace()) {
|
||||
col = 3
|
||||
log.Debug().Msgf("PF NS %q", p.GetTable().GetModel().GetNamespace())
|
||||
col := 3
|
||||
if client.IsAllNamespaces(p.GetTable().GetModel().GetNamespace()) {
|
||||
col = 4
|
||||
}
|
||||
base := ui.TrimCell(p.GetTable().SelectTable, r, col)
|
||||
var err error
|
||||
|
|
|
|||
Loading…
Reference in New Issue