diff --git a/.changelog/26131.txt b/.changelog/26131.txt new file mode 100644 index 000000000..c36c8fb79 --- /dev/null +++ b/.changelog/26131.txt @@ -0,0 +1,3 @@ +```release-note:bug +cli: Fix panic when restarting stopped job with no scaling policies +``` diff --git a/command/job_start.go b/command/job_start.go index bded5ec4b..06d1d0fb9 100644 --- a/command/job_start.go +++ b/command/job_start.go @@ -159,7 +159,13 @@ func (c *JobStartCommand) Run(args []string) int { sps := lastJob.GetScalingPoliciesPerTaskGroup() for _, tg := range job.TaskGroups { - tg.Scaling.Enabled = sps[*tg.Name].Enabled + // guard for nil values in case the tg doesn't have any scaling policy + if sps[*tg.Name] != nil { + if tg.Scaling == nil { + tg.Scaling = &api.ScalingPolicy{} + } + tg.Scaling.Enabled = sps[*tg.Name].Enabled + } } } } diff --git a/command/job_start_test.go b/command/job_start_test.go index fd8d9822b..c684d7457 100644 --- a/command/job_start_test.go +++ b/command/job_start_test.go @@ -24,20 +24,24 @@ var _ cli.Command = (*JobStartCommand)(nil) func TestStartCommand(t *testing.T) { ci.Parallel(t) - srv, _, addr := testServer(t, true, func(c *agent.Config) { - c.DevMode = true - }) - defer srv.Shutdown() - - ui := cli.NewMockUi() - cmd := &JobStartCommand{ - Meta: Meta{ - Ui: ui, - flagAddress: addr, - }, + testSetup := func() (*agent.TestAgent, *JobStartCommand, string) { + srv, _, addr := testServer(t, true, func(c *agent.Config) { + c.DevMode = true + }) + ui := cli.NewMockUi() + cmd := &JobStartCommand{ + Meta: Meta{ + Ui: ui, + flagAddress: addr, + }, + } + return srv, cmd, addr } t.Run("succeeds when starting a stopped job", func(t *testing.T) { + srv, cmd, addr := testSetup() + defer srv.Shutdown() + job := testJob(uuid.Generate()) client, err := cmd.Meta.Client() @@ -72,6 +76,9 @@ func TestStartCommand(t *testing.T) { }) t.Run("succeeds when starting a stopped job with disabled scaling policies and no submissions", func(t *testing.T) { + srv, cmd, addr := testSetup() + defer srv.Shutdown() + job := testJob(uuid.Generate()) client, err := cmd.Meta.Client() @@ -100,6 +107,9 @@ func TestStartCommand(t *testing.T) { }) t.Run("succeeds when starting a stopped job with enabled scaling policies", func(t *testing.T) { + srv, cmd, addr := testSetup() + defer srv.Shutdown() + job := testJob(uuid.Generate()) client, err := cmd.Meta.Client() @@ -135,7 +145,47 @@ func TestStartCommand(t *testing.T) { }) + t.Run("succeeds when starting a stopped job with no scaling policies", func(t *testing.T) { + srv, cmd, addr := testSetup() + defer srv.Shutdown() + + job := testJob(uuid.Generate()) + + client, err := cmd.Meta.Client() + must.NoError(t, err) + + job.TaskGroups[0].Scaling = nil + + jsonBytes, err := json.Marshal(job) + must.NoError(t, err) + + _, _, err = client.Jobs().RegisterOpts(job, &api.RegisterOptions{ + Submission: &api.JobSubmission{ + Source: string(jsonBytes), + Format: "json", + }, + }, nil) + must.NoError(t, err) + + waitForJobAllocsStatus(t, client, *job.ID, api.AllocClientStatusRunning, "") + + _, _, err = client.Jobs().Deregister(*job.ID, false, nil) + must.Nil(t, err) + + waitForJobAllocsStatus(t, client, *job.ID, api.AllocClientStatusComplete, "") + + res := cmd.Run([]string{"-address", addr, *job.ID}) + must.Zero(t, res) + + pol, _, err := client.Scaling().ListPolicies(nil) + must.NoError(t, err) + must.Zero(t, len(pol)) + }) + t.Run("fails to start a job not previously stopped", func(t *testing.T) { + srv, cmd, addr := testSetup() + defer srv.Shutdown() + job := testJob(uuid.Generate()) client, err := cmd.Meta.Client() @@ -151,6 +201,9 @@ func TestStartCommand(t *testing.T) { }) t.Run("fails to start a non-existant job", func(t *testing.T) { + srv, cmd, addr := testSetup() + defer srv.Shutdown() + res := cmd.Run([]string{"-address", addr, "non-existant"}) must.Eq(t, 1, res) })