Skip to content

Commit

Permalink
address code review requests
Browse files Browse the repository at this point in the history
  • Loading branch information
lgfa29 committed Aug 22, 2022
1 parent e666258 commit 8b813fd
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 26 deletions.
2 changes: 1 addition & 1 deletion .changelog/14127.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
```release-note:improvement
client: add option to restart all tasks of an allocation, even if the task already run, such as non-sidecar prestart and poststart tasks.
client: add option to restart all tasks of an allocation, regardless of lifecycle type or state.
```

```release-note:improvement
Expand Down
5 changes: 5 additions & 0 deletions api/allocations.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ func (a *Allocations) GC(alloc *Allocation, q *QueryOptions) error {
return err
}

// Restart restarts the tasks that are currently running or a specific task if
// taskName is provided. An error is returned if the task to be restarted is
// not running.
func (a *Allocations) Restart(alloc *Allocation, taskName string, q *QueryOptions) error {
req := AllocationRestartRequest{
TaskName: taskName,
Expand All @@ -127,6 +130,8 @@ func (a *Allocations) Restart(alloc *Allocation, taskName string, q *QueryOption
return err
}

// RestartAllTasks restarts all tasks in the allocation, regardless of
// lifecycle type or state. Tasks will restart following their lifecycle order.
func (a *Allocations) RestartAllTasks(alloc *Allocation, q *QueryOptions) error {
req := AllocationRestartRequest{
AllTasks: true,
Expand Down
35 changes: 21 additions & 14 deletions client/allocrunner/alloc_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,8 @@ func (ar *allocRunner) handleTaskStateUpdates() {

if len(liveRunners) > 0 {
// if all live runners are sidecars - kill alloc
if killEvent == nil && hasSidecars && !hasNonSidecarTasks(liveRunners) {
hasLiveSidecars := hasSidecars && !hasNonSidecarTasks(liveRunners)
if killEvent == nil && hasLiveSidecars {
killEvent = structs.NewTaskEvent(structs.TaskMainDead)
}

Expand All @@ -573,11 +574,11 @@ func (ar *allocRunner) handleTaskStateUpdates() {
// Kill 'em all
states = ar.killTasks()

// Wait for TaskRunners to exit before continuing to
// prevent looping before TaskRunners have transitioned
// to Dead.
// Wait for TaskRunners to exit before continuing. This will
// prevent looping before TaskRunners have transitioned to
// Dead.
for _, tr := range liveRunners {
ar.logger.Info("killing task", "task", tr.Task().Name)
ar.logger.Info("waiting for task to exit", "task", tr.Task().Name)
select {
case <-tr.WaitCh():
case <-ar.waitCh:
Expand Down Expand Up @@ -1228,20 +1229,24 @@ func (ar *allocRunner) GetTaskEventHandler(taskName string) drivermanager.EventH
}

// Restart satisfies the WorkloadRestarter interface and restarts all tasks
// that are currently running. Only the TaskRestartRunningSignal event type may
// be used.
// that are currently running.
//
// The event type will be set to TaskRestartRunningSignal to comply with
// internal restart logic requirements.
func (ar *allocRunner) Restart(ctx context.Context, event *structs.TaskEvent, failure bool) error {
if event.Type != structs.TaskRestartRunningSignal {
return fmt.Errorf("Invalid event %s for alloc restart request", event.Type)
event.Type = structs.TaskRestartRunningSignal
}
return ar.restartTasks(ctx, event, failure)
}

// RestartTask restarts the provided task. Only TaskRestartSignal event type
// may be used.
// RestartTask restarts the provided task.
//
// The event type will be set to TaskRestartSignal to comply with internal
// restart logic requirements.
func (ar *allocRunner) RestartTask(taskName string, event *structs.TaskEvent) error {
if event.Type != structs.TaskRestartSignal {
return fmt.Errorf("Invalid event %s for task restart request", event.Type)
event.Type = structs.TaskRestartSignal
}

tr, ok := ar.tasks[taskName]
Expand All @@ -1252,11 +1257,13 @@ func (ar *allocRunner) RestartTask(taskName string, event *structs.TaskEvent) er
return tr.Restart(context.TODO(), event, false)
}

// RestartRunning restarts all tasks that are currently running. Only the
// TaskRestartRunningSignal event type may be used.
// RestartRunning restarts all tasks that are currently running.
//
// The event type will be set to TaskRestartRunningSignal to comply with
// internal restart logic requirements.
func (ar *allocRunner) RestartRunning(event *structs.TaskEvent) error {
if event.Type != structs.TaskRestartRunningSignal {
return fmt.Errorf("Invalid event %s for running tasks restart request", event.Type)
event.Type = structs.TaskRestartRunningSignal
}
return ar.restartTasks(context.TODO(), event, false)
}
Expand Down
12 changes: 2 additions & 10 deletions client/allocrunner/alloc_runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1676,11 +1676,7 @@ func TestAllocRunner_MoveAllocDir(t *testing.T) {
ar.Run()
defer destroy(ar)

testutil.WaitForResult(func() (bool, error) {
return ar.AllocState().ClientStatus == structs.AllocClientStatusComplete, nil
}, func(_ error) {
t.Fatalf("expected alloc to be complete")
})
WaitForClientState(t, ar, structs.AllocClientStatusComplete)

// Step 2. Modify its directory
task := alloc.Job.TaskGroups[0].Tasks[0]
Expand Down Expand Up @@ -1708,11 +1704,7 @@ func TestAllocRunner_MoveAllocDir(t *testing.T) {
ar2.Run()
defer destroy(ar2)

testutil.WaitForResult(func() (bool, error) {
return ar.AllocState().ClientStatus == structs.AllocClientStatusComplete, nil
}, func(_ error) {
t.Fatalf("expected alloc to be complete")
})
WaitForClientState(t, ar, structs.AllocClientStatusComplete)

// Ensure that data from ar was moved to ar2
dataFile = filepath.Join(ar2.allocDir.SharedDir, "data", "data_file")
Expand Down
12 changes: 12 additions & 0 deletions client/allocrunner/testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package allocrunner

import (
"fmt"
"sync"
"testing"

Expand All @@ -20,6 +21,7 @@ import (
"github.com/hashicorp/nomad/client/state"
"github.com/hashicorp/nomad/client/vaultclient"
"github.com/hashicorp/nomad/nomad/structs"
"github.com/hashicorp/nomad/testutil"
"github.com/stretchr/testify/require"
)

Expand Down Expand Up @@ -104,3 +106,13 @@ func TestAllocRunnerFromAlloc(t *testing.T, alloc *structs.Allocation) (*allocRu

return ar, cleanup
}

func WaitForClientState(t *testing.T, ar *allocRunner, state string) {
testutil.WaitForResult(func() (bool, error) {
got := ar.AllocState().ClientStatus
return got == state,
fmt.Errorf("expected alloc runner to be in state %s, got %s", state, got)
}, func(err error) {
require.NoError(t, err)
})
}
3 changes: 2 additions & 1 deletion command/alloc_restart.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ Restart Specific Options:
-all-tasks
If set, all tasks in the allocation will be restarted, even the ones that
already ran. This option cannot be used if a task is defined.
already ran. This option cannot be used with '-task' or the '<task>'
argument.
-task <task-name>
Specify the individual task to restart. If task name is given with both an
Expand Down

0 comments on commit 8b813fd

Please sign in to comment.