diff --git a/internal/view/container.go b/internal/view/container.go index 073f22fb..749051a7 100644 --- a/internal/view/container.go +++ b/internal/view/container.go @@ -103,7 +103,7 @@ func (c *Container) attachCmd(evt *tcell.EventKey) *tcell.EventKey { c.Stop() defer c.Start() - attachIn(c.App(), c.GetTable().Path) + attachIn(c.App(), c.GetTable().Path, sel) return nil } diff --git a/internal/view/help_test.go b/internal/view/help_test.go index 970f519e..68b13aee 100644 --- a/internal/view/help_test.go +++ b/internal/view/help_test.go @@ -21,7 +21,7 @@ func TestHelp(t *testing.T) { v := view.NewHelp() assert.Nil(t, v.Init(ctx)) - assert.Equal(t, 20, v.GetRowCount()) + assert.Equal(t, 21, v.GetRowCount()) assert.Equal(t, 8, v.GetColumnCount()) assert.Equal(t, "", strings.TrimSpace(v.GetCell(1, 0).Text)) assert.Equal(t, "Attach", strings.TrimSpace(v.GetCell(1, 1).Text)) diff --git a/internal/view/pod.go b/internal/view/pod.go index 7d5e3e8b..f425c1a1 100644 --- a/internal/view/pod.go +++ b/internal/view/pod.go @@ -132,32 +132,19 @@ func (p *Pod) shellCmd(evt *tcell.EventKey) *tcell.EventKey { } func (p *Pod) attachCmd(evt *tcell.EventKey) *tcell.EventKey { - sel := p.GetTable().GetSelectedItem() - if sel == "" { + path := p.GetTable().GetSelectedItem() + if path == "" { return evt } row := p.GetTable().GetSelectedRowIndex() status := ui.TrimCell(p.GetTable().SelectTable, row, p.GetTable().NameColIndex()+2) if status != render.Running { - p.App().Flash().Errf("%s is not in a running state", sel) + p.App().Flash().Errf("%s is not in a running state", path) return nil } - cc, err := fetchContainers(p.App().factory, sel, false) - if err != nil { - p.App().Flash().Errf("Unable to retrieve containers %s", err) - return evt - } - if len(cc) == 1 { - p.attachIn(sel) - return nil - } - picker := NewPicker() - picker.populate(cc) - picker.SetSelectedFunc(func(i int, t, d string, r rune) { - p.attachIn(sel) - }) - if err := p.App().inject(picker); err != nil { + + if err := containerAttachIn(p.App(), p, path, ""); err != nil { p.App().Flash().Err(err) } @@ -170,9 +157,9 @@ func (p *Pod) shellIn(path, co string) { p.Start() } -func (p *Pod) attachIn(path string) { +func (p *Pod) attachIn(path, co string) { p.Stop() - attachIn(p.App(), path) + attachIn(p.App(), path, co) p.Start() } @@ -221,12 +208,47 @@ func shellIn(a *App, path, co string) { } } -func attachIn(a *App, path string) { - args := computeAttachArgs(path, a.Config.K9s.CurrentContext, a.Conn().Config().Flags().KubeConfig) - log.Debug().Msgf("Attach args %v", args) - if !runK(true, a, args...) { +func containerAttachIn(a *App, comp model.Component, path, co string) error { + if co != "" { + resumeAttachIn(a, comp, path, co) + return nil + } + + cc, err := fetchContainers(a.factory, path, false) + if err != nil { + return err + } + if len(cc) == 1 { + resumeAttachIn(a, comp, path, cc[0]) + return nil + } + picker := NewPicker() + picker.populate(cc) + picker.SetSelectedFunc(func(_ int, co, _ string, _ rune) { + resumeAttachIn(a, comp, path, co) + }) + if err := a.inject(picker); err != nil { + return err + } + + return nil +} + +func resumeAttachIn(a *App, c model.Component, path, co string) { + c.Stop() + defer c.Start() + + attachIn(a, path, co) +} + +func attachIn(a *App, path, co string) { + args := computeAttachArgs(path, co, a.Config.K9s.CurrentContext, a.Conn().Config().Flags().KubeConfig) + + c := color.New(color.BgGreen).Add(color.FgBlack).Add(color.Bold) + if !runK(a, shellOpts{clear: true, banner: c.Sprintf(bannerFmt, path, co), args: args}) { a.Flash().Err(errors.New("Attach exec failed")) } + } func computeShellArgs(path, co, context string, kcfg *string) []string { @@ -246,7 +268,7 @@ func computeShellArgs(path, co, context string, kcfg *string) []string { return append(args, "--", "sh", "-c", shellCheck) } -func computeAttachArgs(path, context string, kcfg *string) []string { +func computeAttachArgs(path, co, context string, kcfg *string) []string { args := make([]string, 0, 15) args = append(args, "attach", "-it") args = append(args, "--context", context) @@ -256,6 +278,10 @@ func computeAttachArgs(path, context string, kcfg *string) []string { if kcfg != nil && *kcfg != "" { args = append(args, "--kubeconfig", *kcfg) } + if co != "" { + args = append(args, "-c", co) + } + return args } diff --git a/internal/view/pod_test.go b/internal/view/pod_test.go index 8588155c..1636f88d 100644 --- a/internal/view/pod_test.go +++ b/internal/view/pod_test.go @@ -16,7 +16,7 @@ func TestPodNew(t *testing.T) { assert.Nil(t, po.Init(makeCtx())) assert.Equal(t, "Pods", po.Name()) - assert.Equal(t, 19, len(po.Hints())) + assert.Equal(t, 20, len(po.Hints())) } // Helpers... diff --git a/internal/view/xray.go b/internal/view/xray.go index e944aac6..928f2436 100644 --- a/internal/view/xray.go +++ b/internal/view/xray.go @@ -296,28 +296,32 @@ func (x *Xray) shellCmd(evt *tcell.EventKey) *tcell.EventKey { } func (x *Xray) attachCmd(evt *tcell.EventKey) *tcell.EventKey { - ref := x.selectedSpec() - if ref == nil { + + spec := x.selectedSpec() + if spec == nil { return nil } - if ref.Status != "" { - x.app.Flash().Errf("%s is not in a running state", ref.Path) + if spec.Status() != "ok" { + x.app.Flash().Errf("%s is not in a running state", spec.Path()) return nil } - if ref.Parent != nil { - x.attachIn(ref.Parent.Path) - } else { - log.Error().Msgf("No parent found on container node %q", ref.Path) + path, co := spec.Path(), "" + if spec.GVR() == "containers" { + path = *spec.ParentPath() + } + + if err := containerAttachIn(x.app, x, path, co); err != nil { + x.app.Flash().Err(err) } return nil } -func (x *Xray) attachIn(path string) { +func (x *Xray) attachIn(path, co string) { x.Stop() - attachIn(x.app, path) + attachIn(x.app, path, co) x.Start() }