Skip to content

Commit

Permalink
worker: setup handler for resumed task
Browse files Browse the repository at this point in the history
This fixes a bug where the resumed task would have no action step
handler defined, resumed tasks are now planned differently so-as to
ensure the previous plan is not overwritten and the handlers are
available for execution.
  • Loading branch information
joelrebel committed Sep 6, 2024
1 parent 0fb431b commit 8115d21
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 2 deletions.
35 changes: 33 additions & 2 deletions internal/worker/task_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ var (
//
// The handler is instantiated to run a single task
type handler struct {
mode model.RunMode
mode model.RunMode
resumed bool
*runner.TaskHandlerContext
}

Expand All @@ -42,7 +43,8 @@ func newHandler(
logger *logrus.Entry,
) runner.TaskHandler {
return &handler{
mode: mode,
mode: mode,
resumed: task.State == model.StateActive,
TaskHandlerContext: &runner.TaskHandlerContext{
Task: task,
Publisher: publisher,
Expand Down Expand Up @@ -141,6 +143,10 @@ func (t handler) inventoryInband(ctx context.Context) (*common.Device, error) {
}

func (t *handler) PlanActions(ctx context.Context) error {
if t.resumed && len(t.Task.Data.ActionsPlanned) > 0 {
return t.planResumedTask()
}

switch t.Task.Data.FirmwarePlanMethod {
case model.FromFirmwareSet:
return t.planFromFirmwareSet(ctx)
Expand Down Expand Up @@ -195,6 +201,31 @@ func (t *handler) planFromFirmwareSet(ctx context.Context) error {
return nil
}

func (t *handler) planResumedTask() error {
if t.mode == model.RunOutofband {
return errors.Wrap(errTaskPlanActions, "resume task not (yet) supported on out-of-band firmware installs")
}

for _, action := range t.Task.Data.ActionsPlanned {
if rctypes.StateIsComplete(action.State) {
continue
}

actionCtx := &runner.ActionHandlerContext{
TaskHandlerContext: t.TaskHandlerContext,
Firmware: &action.Firmware,
First: action.First,
Last: action.Last,
}

if err := inband.AssignStepHandlers(action, actionCtx); err != nil {
return errors.Wrap(errTaskPlanActions, "failed to assign action step handler: "+err.Error())
}
}

return nil
}

// planInstall sets up the firmware install plan
//
// This returns a list of actions to added to the task and a list of action state machines for those actions.
Expand Down
80 changes: 80 additions & 0 deletions internal/worker/task_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -422,3 +422,83 @@ func TestPlanInstall_Inband(t *testing.T) {
require.Equal(t, "drive", actions[0].Firmware.Component, "expect drive component action")
require.Equal(t, "nic", actions[1].Firmware.Component, "expect nic component action")
}

func TestPlanResumedTask(t *testing.T) {
t.Parallel()

logger := logrus.NewEntry(logrus.New())

serverID := uuid.MustParse("fa125199-e9dd-47d4-8667-ce1d26f58c4a")
taskID := uuid.MustParse("05c3296d-be5d-473a-b90c-4ce66cfdec65")
taskHandlerCtx := &runner.TaskHandlerContext{
Logger: logger,
Task: &model.Task{
ID: taskID,
WorkerID: registry.GetID("test-app").String(),
Data: &model.TaskData{
ActionsPlanned: []*model.Action{
{
Firmware: rctypes.Firmware{Component: "drive", Version: "4.2.1"},
Steps: []*model.Step{
{
Name: "downloadFirmware",
State: model.StateSucceeded,
},
{
Name: "installFirmware",
State: model.StateSucceeded,
},
},
},
{
Firmware: rctypes.Firmware{Component: "nic", Version: "1.2.2"},
Steps: []*model.Step{
{
Name: "installFirmware",
State: model.StateSucceeded,
},
{
Name: "powerCycleServer",
State: model.StateActive,
},
},
},
},
},
Parameters: &rctypes.FirmwareInstallTaskParameters{
AssetID: serverID,
ForceInstall: true,
},
Server: &rtypes.Server{
ID: serverID.String(),
Components: rtypes.Components{
{
Name: "nic",
Model: "0001",
Firmware: &common.Firmware{Installed: "1.2.2"},
},
{
Name: "drive",
Model: "000",
Firmware: &common.Firmware{Installed: "4.2.1"},
},
},
},
},
}

h := handler{mode: model.RunInband, TaskHandlerContext: taskHandlerCtx}
err := h.planResumedTask()
require.NoError(t, err, "no errors returned")

require.Equal(t, 2, len(taskHandlerCtx.Task.Data.ActionsPlanned), "expect 2 actions to be intact")
// expect non-nil handlers for each step
for _, action := range taskHandlerCtx.Task.Data.ActionsPlanned {
require.Equal(t, 2, len(action.Steps), "expect 2 steps in each action")
for _, step := range action.Steps {
if step.State == rctypes.Active {
require.NotNil(t, step.Handler)
}
}
}
}

0 comments on commit 8115d21

Please sign in to comment.