Skip to content

Commit

Permalink
Add help for Admin actions
Browse files Browse the repository at this point in the history
Add toast for failures in admin actions
  • Loading branch information
cshintov committed Jan 29, 2024
1 parent 6fdb98f commit bcf1cfd
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 43 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
An efficient terminal application/TUI for interacting with your [HashiCorp Nomad](https://www.nomadproject.io/) cluster.

- Browse jobs, allocations, and tasks
- Restart tasks
- Live tail logs
- Tail global or targeted events
- Exec to interact with running tasks
Expand Down
1 change: 0 additions & 1 deletion internal/dev/dev.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,3 @@ func createDebug(path string) func(string) {
}

var Debug = createDebug("wander.log")
var MyDebug = createDebug("/tmp/mydebug.log")
52 changes: 26 additions & 26 deletions internal/tui/components/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package app

import (
"fmt"
"github.com/robinovitch61/wander/internal/tui/components/toast"
"os"
"os/exec"
"path"
Expand All @@ -14,6 +13,7 @@ import (
"github.com/hashicorp/nomad/api"
"github.com/itchyny/gojq"
"github.com/robinovitch61/wander/internal/dev"
"github.com/robinovitch61/wander/internal/tui/components/toast"
"github.com/robinovitch61/wander/internal/tui/components/header"
"github.com/robinovitch61/wander/internal/tui/components/page"
"github.com/robinovitch61/wander/internal/tui/constants"
Expand Down Expand Up @@ -63,14 +63,12 @@ type Config struct {
}

type Model struct {
confirmed bool
config Config
client api.Client

header header.Model
compact bool
currentPage nomad.Page
previousPage nomad.Page
pageModels map[nomad.Page]*page.Model

inJobsMode bool
Expand Down Expand Up @@ -171,7 +169,6 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}

case nomad.PageLoadedMsg:
dev.Debug(fmt.Sprintf("page loaded: %v", msg.Page))
if msg.Page == m.currentPage {
m.getCurrentPageModel().SetHeader(msg.TableHeader)
m.getCurrentPageModel().SetAllPageRows(msg.AllPageRows)
Expand All @@ -188,8 +185,8 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
// but returns empty results when one provides an empty token
m.getCurrentPageModel().SetHeader([]string{"Error"})
m.getCurrentPageModel().SetAllPageRows([]page.Row{
{"", "No results. Is the cluster empty or was no nomad token provided?"},
{"", "Press q or ctrl+c to quit."},
{Key: "", Row: "No results. Is the cluster empty or was no nomad token provided?"},
{Key: "", Row: "Press q or ctrl+c to quit."},
})
m.getCurrentPageModel().SetViewportSelectionEnabled(false)
}
Expand Down Expand Up @@ -308,10 +305,24 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case nomad.TaskAdminActionCompleteMsg:
m.getCurrentPageModel().SetToast(
toast.New(
fmt.Sprintf("%s completed successfully", nomad.GetTaskAdminText(m.adminAction, msg.TaskName, msg.AllocName, msg.AllocID)),
),
fmt.Sprintf(
"%s completed successfully",
nomad.GetTaskAdminText(
m.adminAction, msg.TaskName, msg.AllocName, msg.AllocID))),
style.SuccessToast,
)

case nomad.TaskAdminActionFailedMsg:
m.getCurrentPageModel().SetToast(
toast.New(
fmt.Sprintf(
"%s failed with error: %s",
nomad.GetTaskAdminText(
m.adminAction, msg.TaskName, msg.AllocName, msg.AllocID),
msg.Error())),
style.ErrorToast,
)

}

currentPageModel = m.getCurrentPageModel()
Expand Down Expand Up @@ -409,7 +420,8 @@ func (m *Model) handleKeyMsg(msg tea.KeyMsg) tea.Cmd {
m.adminAction = nomad.KeyToAdminAction(selectedPageRow.Key)
case nomad.TaskAdminConfirmPage:
if selectedPageRow.Key == constants.ConfirmationKey {
cmds = append(cmds, nomad.GetCmdForTaskAdminAction(m.client, m.adminAction, m.taskName, m.alloc.Name, m.alloc.ID))
cmds = append(cmds, nomad.GetCmdForTaskAdminAction(
m.client, m.adminAction, m.taskName, m.alloc.Name, m.alloc.ID))
} else {
backPage := m.currentPage.Backward(m.inJobsMode)
m.setPage(backPage)
Expand Down Expand Up @@ -609,7 +621,6 @@ func (m *Model) setPage(page nomad.Page) {
m.getCurrentPageModel().HideToast()
m.currentPage = page
m.getCurrentPageModel().SetFilterPrefix(m.getFilterPrefix(page))

if page.DoesLoad() {
m.getCurrentPageModel().SetLoading(true)
} else {
Expand Down Expand Up @@ -691,17 +702,12 @@ func (m Model) getCurrentPageCmd() tea.Cmd {
}
allPageRows = append(allPageRows, page.Row{Row: formatter.StripOSCommandSequences(formatter.StripANSI(row))})
}
return nomad.PageLoadedMsg{
Page: nomad.ExecCompletePage,
TableHeader: []string{"Exec Session Output"},
AllPageRows: allPageRows,
}
return nomad.PageLoadedMsg{Page: nomad.ExecCompletePage, TableHeader: []string{"Exec Session Output"}, AllPageRows: allPageRows}
}
case nomad.AllocSpecPage:
return nomad.FetchAllocSpec(m.client, m.alloc.ID)
case nomad.LogsPage:
return nomad.FetchLogs(
m.client, m.alloc, m.taskName, m.logType, m.config.Log.Offset, m.config.Log.Tail)
return nomad.FetchLogs(m.client, m.alloc, m.taskName, m.logType, m.config.Log.Offset, m.config.Log.Tail)
case nomad.LoglinePage:
return nomad.PrettifyLine(m.logline, nomad.LoglinePage)
case nomad.StatsPage:
Expand All @@ -722,6 +728,7 @@ func (m Model) getCurrentPageCmd() tea.Cmd {
AllPageRows: rows,
}
}

case nomad.TaskAdminConfirmPage:
return func() tea.Msg {
// this does no async work, just constructs the confirmation page
Expand All @@ -736,6 +743,7 @@ func (m Model) getCurrentPageCmd() tea.Cmd {
},
}
}

default:
panic(fmt.Sprintf("Load command for page:%s not found", m.currentPage))
}
Expand All @@ -762,13 +770,5 @@ func (m Model) currentPageViewportSaving() bool {
}

func (m Model) getFilterPrefix(page nomad.Page) string {
return page.GetFilterPrefix(
m.config.Namespace,
m.jobID,
m.taskName,
m.alloc.Name,
m.alloc.ID,
m.config.Event.Topics,
m.config.Event.Namespace,
)
return page.GetFilterPrefix(m.config.Namespace, m.jobID, m.taskName, m.alloc.Name, m.alloc.ID, m.config.Event.Topics, m.config.Event.Namespace)
}
6 changes: 2 additions & 4 deletions internal/tui/components/page/page.go
Original file line number Diff line number Diff line change
Expand Up @@ -399,12 +399,10 @@ func (m *Model) updateFilter() {
m.filter.SetSuffix(" (no matches) ")
} else if m.filter.Focused() {
m.filter.SetSuffix(
fmt.Sprintf(
" (%d/%d, %s to apply) ",
fmt.Sprintf(" (%d/%d, %s to apply) ",
m.pageData.FilteredSelectionNum+1,
len(m.pageData.FilteredContentIdxs),
keymap.KeyMap.Forward.Help().Key,
),
keymap.KeyMap.Forward.Help().Key),
)
} else {
m.filter.SetSuffix(
Expand Down
8 changes: 7 additions & 1 deletion internal/tui/nomad/pages.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ func (p Page) String() string {
case TaskAdminPage:
return "task admin menu"
case TaskAdminConfirmPage:
return "confirm task admin action"
return "confirm"
}
return "unknown"
}
Expand Down Expand Up @@ -415,6 +415,7 @@ type UpdatePageDataMsg struct {
Page Page
}

// Update page data with a delay. This is useful for pages that update.
func UpdatePageDataWithDelay(id int, p Page, d time.Duration) tea.Cmd {
if p.doesUpdate() && d > 0 {
return tea.Tick(d, func(t time.Time) tea.Msg { return UpdatePageDataMsg{id, p} })
Expand Down Expand Up @@ -465,6 +466,11 @@ func GetPageKeyHelp(

viewportKeyMap := viewport.GetKeyMap()
secondRow := []key.Binding{viewportKeyMap.Save, keymap.KeyMap.Wrap}

if currentPage.HasAdminMenu() {
secondRow = append(secondRow, keymap.KeyMap.AdminMenu)
}

thirdRow := []key.Binding{viewportKeyMap.Down, viewportKeyMap.Up, viewportKeyMap.PageDown, viewportKeyMap.PageUp, viewportKeyMap.Bottom, viewportKeyMap.Top}

var fourthRow []key.Binding
Expand Down
41 changes: 32 additions & 9 deletions internal/tui/nomad/taskadmin.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
/* Admin Actions for tasks
Restart, Stop, etc.
*/
package nomad

import (
"fmt"
tea "github.com/charmbracelet/bubbletea"
"github.com/hashicorp/nomad/api"
"github.com/robinovitch61/wander/internal/tui/formatter"
"github.com/robinovitch61/wander/internal/tui/message"
)

var (
Expand All @@ -20,11 +22,28 @@ type TaskAdminActionCompleteMsg struct {
TaskName, AllocName, AllocID string
}

func GetTaskAdminText(adminAction AdminAction, taskName, allocName, allocID string) string {
return fmt.Sprintf("%s task %s in %s (%s)", TaskAdminActions[adminAction], taskName, allocName, formatter.ShortAllocID(allocID))
type TaskAdminActionFailedMsg struct {
Err error
TaskName, AllocName, AllocID string
}

func GetCmdForTaskAdminAction(client api.Client, adminAction AdminAction, taskName, allocName, allocID string) tea.Cmd {
func (e TaskAdminActionFailedMsg) Error() string { return e.Err.Error() }

func GetTaskAdminText(
adminAction AdminAction, taskName, allocName, allocID string) string {
return fmt.Sprintf(
"%s task %s in %s (%s)",
TaskAdminActions[adminAction],
taskName, allocName, formatter.ShortAllocID(allocID))
}

func GetCmdForTaskAdminAction(
client api.Client,
adminAction AdminAction,
taskName,
allocName,
allocID string,
) tea.Cmd {
switch adminAction {
case RestartTaskAction:
return RestartTask(client, taskName, allocName, allocID)
Expand All @@ -38,17 +57,21 @@ func GetCmdForTaskAdminAction(client api.Client, adminAction AdminAction, taskNa
func RestartTask(client api.Client, taskName, allocName, allocID string) tea.Cmd {
return func() tea.Msg {
alloc, _, err := client.Allocations().Info(allocID, nil)

if err != nil {
// TODO LEO: we could return a TaskAdminActionFailedMsg here and display it in the toast
return message.ErrMsg{Err: err}
return TaskAdminActionFailedMsg{
Err: err,
TaskName: taskName, AllocName: allocName, AllocID: allocID}
}

err = client.Allocations().Restart(alloc, taskName, nil)
if err != nil {
// TODO LEO: we could return a TaskAdminActionFailedMsg here and display it in the toast
return message.ErrMsg{Err: err}
return TaskAdminActionFailedMsg{
Err: err,
TaskName: taskName, AllocName: allocName, AllocID: allocID}
}

return TaskAdminActionCompleteMsg{TaskName: taskName, AllocName: allocName, AllocID: allocID}
return TaskAdminActionCompleteMsg{
TaskName: taskName, AllocName: allocName, AllocID: allocID}
}
}
1 change: 1 addition & 0 deletions internal/tui/nomad/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const (
StopJobAction
)

// AdminActionToKey and KeyToAdminAction are used to render the TaskAdminPage
func AdminActionToKey(adminAction AdminAction) string {
switch adminAction {
case RestartTaskAction:
Expand Down
2 changes: 0 additions & 2 deletions internal/tui/style/style.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,4 @@ var (
StdErr = Regular.Copy().Foreground(red)
SuccessToast = Bold.Copy().PaddingLeft(1).Foreground(black).Background(darkgreen)
ErrorToast = Bold.Copy().PaddingLeft(1).Foreground(black).Background(darkred)
Red = Regular.Copy().Foreground(red)
Green = Regular.Copy().Foreground(darkgreen)
)

0 comments on commit bcf1cfd

Please sign in to comment.