Skip to content

Commit

Permalink
[feat] Add stop job action
Browse files Browse the repository at this point in the history
Also can purge

Issue #120
  • Loading branch information
cshintov committed Feb 9, 2024
1 parent 4db9f8c commit c4f4bf5
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 12 deletions.
91 changes: 82 additions & 9 deletions internal/tui/components/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}
case nomad.ExecPage:
m.getCurrentPageModel().SetInputPrefix("Enter command: ")
case nomad.AllocAdminConfirmPage:
case nomad.AllocAdminConfirmPage, nomad.JobAdminConfirmPage:
// always make user go down one to confirm
m.getCurrentPageModel().SetViewportSelectionToTop()
}
Expand Down Expand Up @@ -337,6 +337,24 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
newToast := toast.New(toastMsg)
m.getCurrentPageModel().SetToast(newToast, toastStyle)
cmds = append(cmds, tea.Tick(newToast.Timeout, func(t time.Time) tea.Msg { return toast.TimeoutMsg{ID: newToast.ID} }))

case nomad.JobAdminActionCompleteMsg:
toastMsg := fmt.Sprintf(
"%s completed successfully",
nomad.GetJobAdminText(m.adminAction, msg.JobID),
)
toastStyle := style.SuccessToast
if msg.Err != nil {
toastMsg = fmt.Sprintf(
"%s failed with error: %s",
nomad.GetJobAdminText(m.adminAction, msg.JobID),
msg.Err.Error(),
)
toastStyle = style.ErrorToast
}
newToast := toast.New(toastMsg)
m.getCurrentPageModel().SetToast(newToast, toastStyle)
cmds = append(cmds, tea.Tick(newToast.Timeout, func(t time.Time) tea.Msg { return toast.TimeoutMsg{ID: newToast.ID} }))
}

currentPageModel = m.getCurrentPageModel()
Expand Down Expand Up @@ -444,6 +462,21 @@ func (m *Model) handleKeyMsg(msg tea.KeyMsg) tea.Cmd {
cmds = append(cmds, m.getCurrentPageCmd())
return tea.Batch(cmds...)
}
case nomad.JobAdminPage:
m.adminAction = nomad.KeyToAdminAction(selectedPageRow.Key)
case nomad.JobAdminConfirmPage:
if selectedPageRow.Key == constants.ConfirmationKey {
cmds = append(
cmds,
nomad.GetCmdForJobAdminAction(
m.client, m.adminAction, m.jobID),
)
} else {
backPage := m.currentPage.Backward(m.inJobsMode)
m.setPage(backPage)
cmds = append(cmds, m.getCurrentPageCmd())
return tea.Batch(cmds...)
}
default:
if m.currentPage.ShowsTasks() {
taskInfo, err := nomad.TaskInfoFromKey(selectedPageRow.Key)
Expand Down Expand Up @@ -595,16 +628,26 @@ func (m *Model) handleKeyMsg(msg tea.KeyMsg) tea.Cmd {
if key.Matches(msg, keymap.KeyMap.AdminMenu) && m.currentPage.HasAdminMenu() {
if selectedPageRow, err := m.getCurrentPageModel().GetSelectedPageRow(); err == nil {
// Get task info from the currently selected row
taskInfo, err := nomad.TaskInfoFromKey(selectedPageRow.Key)
if err != nil {
m.err = err
return nil
}
if taskInfo.Running {
m.alloc, m.taskName = taskInfo.Alloc, taskInfo.TaskName
m.setPage(nomad.AllocAdminPage)

if m.currentPage == nomad.JobsPage {
m.jobID, m.jobNamespace = nomad.JobIDAndNamespaceFromKey(selectedPageRow.Key)
m.setPage(nomad.JobAdminPage)
return m.getCurrentPageCmd()
}

if m.currentPage == nomad.JobTasksPage {

taskInfo, err := nomad.TaskInfoFromKey(selectedPageRow.Key)
if err != nil {
m.err = err
return nil
}
if taskInfo.Running {
m.alloc, m.taskName = taskInfo.Alloc, taskInfo.TaskName
m.setPage(nomad.AllocAdminPage)
return m.getCurrentPageCmd()
}
}
}
}

Expand Down Expand Up @@ -758,6 +801,36 @@ func (m Model) getCurrentPageCmd() tea.Cmd {
},
}
}
case nomad.JobAdminPage:
return func() tea.Msg {
// this does no async work, just constructs the job admin menu
var rows []page.Row
for action := range nomad.JobAdminActions {
rows = append(rows, page.Row{
Key: nomad.AdminActionToKey(action),
Row: nomad.GetJobAdminText(action, m.jobID),
})
}
return nomad.PageLoadedMsg{
Page: nomad.JobAdminPage,
TableHeader: []string{"Available Admin Actions"},
AllPageRows: rows,
}
}
case nomad.JobAdminConfirmPage:
return func() tea.Msg {
// this does no async work, just constructs the confirmation page
confirmationText := nomad.GetJobAdminText(m.adminAction, m.jobID)
confirmationText = strings.ToLower(confirmationText[:1]) + confirmationText[1:]
return nomad.PageLoadedMsg{
Page: nomad.JobAdminConfirmPage,
TableHeader: []string{"Are you sure?"},
AllPageRows: []page.Row{
{Key: "Cancel", Row: "Cancel"},
{Key: constants.ConfirmationKey, Row: fmt.Sprintf("Yes, %s", confirmationText)},
},
}
}
default:
panic(fmt.Sprintf("Load command for page:%s not found", m.currentPage))
}
Expand Down
64 changes: 64 additions & 0 deletions internal/tui/nomad/jobadmin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package nomad

import (
"fmt"

tea "github.com/charmbracelet/bubbletea"
"github.com/hashicorp/nomad/api"

"github.com/robinovitch61/wander/internal/tui/style"
)

var (
JobAdminActions = map[AdminAction]string{
StopJobAction: "Stop",
StopAndPurgeJobAction: "Stop and purge",
}
)

type JobAdminActionCompleteMsg struct {
Err error
JobID string
}

func GetJobAdminText(adminAction AdminAction, jobID string) string {
switch adminAction {
case StopJobAction, StopAndPurgeJobAction:
return fmt.Sprintf(
"%s job %s",
JobAdminActions[adminAction],
style.Bold.Render(jobID))
default:
return ""
}
}

func GetCmdForJobAdminAction(
client api.Client,
adminAction AdminAction,
jobID string,
) tea.Cmd {
switch adminAction {
case StopJobAction:
return StopJob(client, jobID, false)
case StopAndPurgeJobAction:
return StopJob(client, jobID, true)
default:
return nil
}
}

func StopJob(client api.Client, jobID string, purge bool) tea.Cmd {
return func() tea.Msg {

_, _, err := client.Jobs().Deregister(jobID, purge, nil)
if err != nil {
return JobAdminActionCompleteMsg{
Err: err,
JobID: jobID,
}
}

return JobAdminActionCompleteMsg{JobID: jobID}
}
}
34 changes: 32 additions & 2 deletions internal/tui/nomad/pages.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ const (
StatsPage
AllocAdminPage
AllocAdminConfirmPage
JobAdminPage
JobAdminConfirmPage
)

func GetAllPageConfigs(width, height int, compactTables bool) map[Page]page.Config {
Expand Down Expand Up @@ -144,6 +146,16 @@ func GetAllPageConfigs(width, height int, compactTables bool) map[Page]page.Conf
LoadingString: AllocAdminConfirmPage.LoadingString(),
SelectionEnabled: true, WrapText: false, RequestInput: false,
},
JobAdminPage: {
Width: width, Height: height,
LoadingString: JobAdminPage.LoadingString(),
SelectionEnabled: true, WrapText: false, RequestInput: false,
},
JobAdminConfirmPage: {
Width: width, Height: height,
LoadingString: JobAdminConfirmPage.LoadingString(),
SelectionEnabled: true, WrapText: false, RequestInput: false,
},
}
}

Expand All @@ -170,6 +182,8 @@ func (p Page) DoesReload() bool {
ExecCompletePage,
AllocAdminPage,
AllocAdminConfirmPage,
JobAdminPage,
JobAdminConfirmPage,
}
for _, noReloadPage := range noReloadPages {
if noReloadPage == p {
Expand All @@ -190,7 +204,7 @@ func (p Page) ShowsTasks() bool {
}

func (p Page) HasAdminMenu() bool {
adminMenuPages := []Page{AllTasksPage, JobTasksPage}
adminMenuPages := []Page{AllTasksPage, JobTasksPage, JobsPage}
for _, adminMenuPage := range adminMenuPages {
if adminMenuPage == p {
return true
Expand Down Expand Up @@ -219,6 +233,8 @@ func (p Page) doesUpdate() bool {
AllEventPage, // doesn't load
AllocAdminPage, // doesn't load
AllocAdminConfirmPage, // doesn't load
JobAdminPage, // doesn't load
JobAdminConfirmPage, // doesn't load
}
for _, noUpdatePage := range noUpdatePages {
if noUpdatePage == p {
Expand Down Expand Up @@ -264,7 +280,9 @@ func (p Page) String() string {
return "stats"
case AllocAdminPage:
return "task admin menu"
case AllocAdminConfirmPage:
case JobAdminPage:
return "job admin menu"
case AllocAdminConfirmPage, JobAdminConfirmPage:
return "execute"
}
return "unknown"
Expand Down Expand Up @@ -294,6 +312,10 @@ func (p Page) Forward(inJobsMode bool) Page {
return AllocAdminConfirmPage
case AllocAdminConfirmPage:
return returnToTasksPage(inJobsMode)
case JobAdminPage:
return JobAdminConfirmPage
case JobAdminConfirmPage:
return JobsPage
}
return p
}
Expand Down Expand Up @@ -341,6 +363,10 @@ func (p Page) Backward(inJobsMode bool) Page {
return returnToTasksPage(inJobsMode)
case AllocAdminConfirmPage:
return AllocAdminPage
case JobAdminPage:
return JobsPage
case JobAdminConfirmPage:
return JobAdminPage
}
return p
}
Expand Down Expand Up @@ -400,6 +426,10 @@ func (p Page) GetFilterPrefix(namespace, jobID, taskName, allocName, allocID str
return fmt.Sprintf("Admin Actions for Allocation %s %s", style.Bold.Render(allocName), formatter.ShortAllocID(allocID))
case AllocAdminConfirmPage:
return fmt.Sprintf("Confirm Admin Action for Allocation %s %s", style.Bold.Render(allocName), formatter.ShortAllocID(allocID))
case JobAdminPage:
return fmt.Sprintf("Admin Actions for Job %s", style.Bold.Render(jobID))
case JobAdminConfirmPage:
return fmt.Sprintf("Confirm Admin Action for Job %s", style.Bold.Render(jobID))
default:
panic("page not found")
}
Expand Down
7 changes: 6 additions & 1 deletion internal/tui/nomad/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ const (
StopAllocAction
RestartJobAction
StopJobAction
StopAndPurgeJobAction
)

// AdminActionToKey and KeyToAdminAction are used to render the AllocAdminPage
// AdminActionToKey and KeyToAdminAction are used for admin menu serialization/deserialization
func AdminActionToKey(adminAction AdminAction) string {
switch adminAction {
case RestartTaskAction:
Expand All @@ -37,6 +38,8 @@ func AdminActionToKey(adminAction AdminAction) string {
return "restart-job"
case StopJobAction:
return "stop-job"
case StopAndPurgeJobAction:
return "stop-and-purge-job"
default:
return ""
}
Expand All @@ -54,6 +57,8 @@ func KeyToAdminAction(adminAction string) AdminAction {
return RestartJobAction
case "stop-job":
return StopJobAction
case "stop-and-purge-job":
return StopAndPurgeJobAction
default:
return -1
}
Expand Down

0 comments on commit c4f4bf5

Please sign in to comment.