diff --git a/FEATURES.md b/FEATURES.md
index 2b3b51e6..a3dc8f71 100644
--- a/FEATURES.md
+++ b/FEATURES.md
@@ -11,6 +11,7 @@ rediscovered.
- [x] Task Scheduler
- [x] Unify command definition (type/parameters in persistence layer, name/settings in API layer)
- [ ] Job status change handling
+- [ ] Port the old 'fail-requested' task status handling code to the new Manager
- [ ] Task timeout monitoring
- [ ] Worker Blacklisting & failed task requeueing
- [ ] Worker timeout monitoring
diff --git a/internal/manager/api_impl/api_impl.go b/internal/manager/api_impl/api_impl.go
index a8969491..7cb99777 100644
--- a/internal/manager/api_impl/api_impl.go
+++ b/internal/manager/api_impl/api_impl.go
@@ -59,6 +59,12 @@ type PersistenceService interface {
ScheduleTask(w *persistence.Worker) (*persistence.Task, error)
}
+// TaskStateMachine interfaces task_state_machine.StateMachine.
+type TaskStateMachine interface {
+ IsTaskStatusChangeValid(task *persistence.Task, newStatus api.TaskStatus) bool
+ TaskStatusChange(ctx context.Context, task *persistence.Task, newStatus api.TaskStatus) error
+}
+
type JobCompiler interface {
ListJobTypes() api.AvailableJobTypes
Compile(ctx context.Context, job api.SubmittedJob) (*job_compilers.AuthoredJob, error)
diff --git a/internal/manager/task_state_machine/mocks/interfaces_mock.gen.go b/internal/manager/task_state_machine/mocks/interfaces_mock.gen.go
new file mode 100644
index 00000000..94eca89d
--- /dev/null
+++ b/internal/manager/task_state_machine/mocks/interfaces_mock.gen.go
@@ -0,0 +1,96 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: gitlab.com/blender/flamenco-ng-poc/internal/manager/task_state_machine (interfaces: PersistenceService)
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+ context "context"
+ reflect "reflect"
+
+ gomock "github.com/golang/mock/gomock"
+ persistence "gitlab.com/blender/flamenco-ng-poc/internal/manager/persistence"
+ api "gitlab.com/blender/flamenco-ng-poc/pkg/api"
+)
+
+// MockPersistenceService is a mock of PersistenceService interface.
+type MockPersistenceService struct {
+ ctrl *gomock.Controller
+ recorder *MockPersistenceServiceMockRecorder
+}
+
+// MockPersistenceServiceMockRecorder is the mock recorder for MockPersistenceService.
+type MockPersistenceServiceMockRecorder struct {
+ mock *MockPersistenceService
+}
+
+// NewMockPersistenceService creates a new mock instance.
+func NewMockPersistenceService(ctrl *gomock.Controller) *MockPersistenceService {
+ mock := &MockPersistenceService{ctrl: ctrl}
+ mock.recorder = &MockPersistenceServiceMockRecorder{mock}
+ return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockPersistenceService) EXPECT() *MockPersistenceServiceMockRecorder {
+ return m.recorder
+}
+
+// CountTasksOfJobInStatus mocks base method.
+func (m *MockPersistenceService) CountTasksOfJobInStatus(arg0 context.Context, arg1 *persistence.Job, arg2 api.TaskStatus) (int, int, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "CountTasksOfJobInStatus", arg0, arg1, arg2)
+ ret0, _ := ret[0].(int)
+ ret1, _ := ret[1].(int)
+ ret2, _ := ret[2].(error)
+ return ret0, ret1, ret2
+}
+
+// CountTasksOfJobInStatus indicates an expected call of CountTasksOfJobInStatus.
+func (mr *MockPersistenceServiceMockRecorder) CountTasksOfJobInStatus(arg0, arg1, arg2 interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CountTasksOfJobInStatus", reflect.TypeOf((*MockPersistenceService)(nil).CountTasksOfJobInStatus), arg0, arg1, arg2)
+}
+
+// JobHasTasksInStatus mocks base method.
+func (m *MockPersistenceService) JobHasTasksInStatus(arg0 context.Context, arg1 *persistence.Job, arg2 api.TaskStatus) (bool, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "JobHasTasksInStatus", arg0, arg1, arg2)
+ ret0, _ := ret[0].(bool)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// JobHasTasksInStatus indicates an expected call of JobHasTasksInStatus.
+func (mr *MockPersistenceServiceMockRecorder) JobHasTasksInStatus(arg0, arg1, arg2 interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "JobHasTasksInStatus", reflect.TypeOf((*MockPersistenceService)(nil).JobHasTasksInStatus), arg0, arg1, arg2)
+}
+
+// SaveJobStatus mocks base method.
+func (m *MockPersistenceService) SaveJobStatus(arg0 context.Context, arg1 *persistence.Job) error {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "SaveJobStatus", arg0, arg1)
+ ret0, _ := ret[0].(error)
+ return ret0
+}
+
+// SaveJobStatus indicates an expected call of SaveJobStatus.
+func (mr *MockPersistenceServiceMockRecorder) SaveJobStatus(arg0, arg1 interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SaveJobStatus", reflect.TypeOf((*MockPersistenceService)(nil).SaveJobStatus), arg0, arg1)
+}
+
+// SaveTask mocks base method.
+func (m *MockPersistenceService) SaveTask(arg0 context.Context, arg1 *persistence.Task) error {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "SaveTask", arg0, arg1)
+ ret0, _ := ret[0].(error)
+ return ret0
+}
+
+// SaveTask indicates an expected call of SaveTask.
+func (mr *MockPersistenceServiceMockRecorder) SaveTask(arg0, arg1 interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SaveTask", reflect.TypeOf((*MockPersistenceService)(nil).SaveTask), arg0, arg1)
+}
diff --git a/internal/manager/task_state_machine/task_state_machine.go b/internal/manager/task_state_machine/task_state_machine.go
new file mode 100644
index 00000000..1e028cce
--- /dev/null
+++ b/internal/manager/task_state_machine/task_state_machine.go
@@ -0,0 +1,210 @@
+package task_state_machine
+
+/* ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * Original Code Copyright (C) 2022 Blender Foundation.
+ *
+ * This file is part of Flamenco.
+ *
+ * Flamenco is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * Flamenco is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * Flamenco. If not, see .
+ *
+ * ***** END GPL LICENSE BLOCK ***** */
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/rs/zerolog/log"
+ "gitlab.com/blender/flamenco-ng-poc/internal/manager/persistence"
+ "gitlab.com/blender/flamenco-ng-poc/pkg/api"
+)
+
+// taskFailJobPercentage is the percentage of a job's tasks that need to fail to
+// trigger failure of the entire job.
+const taskFailJobPercentage = 10 // Integer from 0 to 100.
+
+// StateMachine handles task and job status changes.
+type StateMachine struct {
+ persist PersistenceService
+}
+
+// Generate mock implementations of these interfaces.
+//go:generate go run github.com/golang/mock/mockgen -destination mocks/interfaces_mock.gen.go -package mocks gitlab.com/blender/flamenco-ng-poc/internal/manager/task_state_machine PersistenceService
+
+type PersistenceService interface { // Subset of persistence.DB
+ SaveTask(ctx context.Context, task *persistence.Task) error
+ SaveJobStatus(ctx context.Context, j *persistence.Job) error
+
+ JobHasTasksInStatus(ctx context.Context, job *persistence.Job, taskStatus api.TaskStatus) (bool, error)
+ CountTasksOfJobInStatus(ctx context.Context, job *persistence.Job, taskStatus api.TaskStatus) (numInStatus, numTotal int, err error)
+}
+
+func NewStateMachine(persist PersistenceService) *StateMachine {
+ return &StateMachine{
+ persist: persist,
+ }
+}
+
+// TaskStatusChange updates the task's status to the new one.
+// `task` is expected to still have its original status, and have a filled `Job` pointer.
+func (sm *StateMachine) TaskStatusChange(ctx context.Context, task *persistence.Task, newTaskStatus api.TaskStatus) error {
+ job := task.Job
+ if job == nil {
+ log.Panic().Str("task", task.UUID).Msg("task without job, cannot handle this")
+ return nil // Will not run because of the panic.
+ }
+
+ logger := log.With().
+ Str("task", task.UUID).
+ Str("job", job.UUID).
+ Str("taskStatusOld", string(task.Status)).
+ Str("taskStatusNew", string(newTaskStatus)).
+ Logger()
+ logger.Debug().Msg("task state changed")
+
+ task.Status = newTaskStatus
+ if err := sm.persist.SaveTask(ctx, task); err != nil {
+ return fmt.Errorf("error saving task to database: %w", err)
+ }
+ if err := sm.updateJobAfterTaskStatusChange(ctx, task, newTaskStatus); err != nil {
+ return fmt.Errorf("error updating job after task status change: %w", err)
+ }
+ return nil
+}
+
+// updateJobAfterTaskStatusChange updates the job status based on the status of
+// this task and other tasks in the job.
+func (sm *StateMachine) updateJobAfterTaskStatusChange(
+ ctx context.Context, task *persistence.Task, newTaskStatus api.TaskStatus,
+) error {
+
+ job := task.Job
+
+ logger := log.With().
+ Str("job", job.UUID).
+ Str("task", task.UUID).
+ Str("taskStatusOld", string(task.Status)).
+ Str("taskStatusNew", string(newTaskStatus)).
+ Logger()
+
+ // If the job has status 'ifStatus', move it to status 'thenStatus'.
+ jobStatusIfAThenB := func(ifStatus, thenStatus api.JobStatus) error {
+ if job.Status != ifStatus {
+ return nil
+ }
+ logger.Info().
+ Str("jobStatusOld", string(ifStatus)).
+ Str("jobStatusNew", string(thenStatus)).
+ Msg("Job changed status because one of its task changed status")
+ return sm.JobStatusChange(ctx, job, thenStatus)
+ }
+
+ // Every 'case' in this switch MUST return. Just for sanity's sake.
+ switch newTaskStatus {
+ case api.TaskStatusQueued:
+ // Re-queueing a task on a completed job should re-queue the job too.
+ return jobStatusIfAThenB(api.JobStatusCompleted, api.JobStatusQueued)
+
+ case api.TaskStatusCancelRequested:
+ // Requesting cancellation of a single task has no influence on the job itself.
+ return nil
+
+ case api.TaskStatusPaused:
+ // Pausing a task has no impact on the job.
+ return nil
+
+ case api.TaskStatusCanceled:
+ // Only trigger cancellation/failure of the job if that was actually requested.
+ // A user can also cancel a single task from the web UI or API, in which
+ // case the job should just keep running.
+ if job.Status != api.JobStatusCancelRequested {
+ return nil
+ }
+ // This could be the last 'cancel-requested' task to go to 'canceled'.
+ hasCancelReq, err := sm.persist.JobHasTasksInStatus(ctx, job, api.TaskStatusCancelRequested)
+ if err != nil {
+ return err
+ }
+ if !hasCancelReq {
+ logger.Info().Msg("last task of job went from cancel-requested to canceled")
+ return sm.JobStatusChange(ctx, job, api.JobStatusCanceled)
+ }
+ return nil
+
+ case api.TaskStatusFailed:
+ // Count the number of failed tasks. If it is over the threshold, fail the job.
+ numFailed, numTotal, err := sm.persist.CountTasksOfJobInStatus(ctx, job, api.TaskStatusFailed)
+ if err != nil {
+ return err
+ }
+ failedPercentage := int(float64(numFailed) / float64(numTotal) * 100)
+ failLogger := logger.With().
+ Int("taskNumTotal", numTotal).
+ Int("taskNumFailed", numFailed).
+ Int("failedPercentage", failedPercentage).
+ Int("threshold", taskFailJobPercentage).
+ Logger()
+
+ if failedPercentage >= taskFailJobPercentage {
+ failLogger.Info().Msg("failing job because too many of its tasks failed")
+ return sm.JobStatusChange(ctx, job, api.JobStatusFailed)
+ }
+ // If the job didn't fail, this failure indicates that at least the job is active.
+ failLogger.Info().Msg("task failed, but not enough to fail the job")
+ return jobStatusIfAThenB(api.JobStatusQueued, api.JobStatusActive)
+
+ case api.TaskStatusActive, api.TaskStatusSoftFailed:
+ switch job.Status {
+ case api.JobStatusActive, api.JobStatusCancelRequested:
+ // Do nothing, job is already in the desired status.
+ return nil
+ default:
+ logger.Info().Msg("job became active because one of its task changed status")
+ return sm.JobStatusChange(ctx, job, api.JobStatusActive)
+ }
+
+ case api.TaskStatusCompleted:
+ numComplete, numTotal, err := sm.persist.CountTasksOfJobInStatus(ctx, job, api.TaskStatusCompleted)
+ if err != nil {
+ return err
+ }
+ if numComplete == numTotal {
+ logger.Info().Msg("all tasks of job are completed, job is completed")
+ return sm.JobStatusChange(ctx, job, api.JobStatusCompleted)
+ }
+ logger.Info().
+ Int("taskNumTotal", numTotal).
+ Int("taskNumComplete", numComplete).
+ Msg("task completed; there are more tasks to do")
+ return jobStatusIfAThenB(api.JobStatusQueued, api.JobStatusActive)
+
+ default:
+ logger.Warn().Msg("task obtained status that Flamenco did not expect")
+ return nil
+ }
+}
+
+func (sm *StateMachine) JobStatusChange(ctx context.Context, job *persistence.Job, newJobStatus api.JobStatus) error {
+ logger := log.With().
+ Str("job", job.UUID).
+ Str("jobStatusOld", string(job.Status)).
+ Str("jobStatusNew", string(newJobStatus)).
+ Logger()
+
+ logger.Info().Msg("job status changed")
+
+ // TODO: actually respond to status change, instead of just saving the new job state.
+
+ job.Status = newJobStatus
+ return sm.persist.SaveJobStatus(ctx, job)
+}
diff --git a/internal/manager/task_state_machine/task_state_machine_test.go b/internal/manager/task_state_machine/task_state_machine_test.go
new file mode 100644
index 00000000..79a8b32c
--- /dev/null
+++ b/internal/manager/task_state_machine/task_state_machine_test.go
@@ -0,0 +1,106 @@
+package task_state_machine
+
+/* ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * Original Code Copyright (C) 2022 Blender Foundation.
+ *
+ * This file is part of Flamenco.
+ *
+ * Flamenco is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * Flamenco is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * Flamenco. If not, see .
+ *
+ * ***** END GPL LICENSE BLOCK ***** */
+
+import (
+ "context"
+ "testing"
+
+ "github.com/golang/mock/gomock"
+ "github.com/stretchr/testify/assert"
+ "gorm.io/gorm"
+
+ "gitlab.com/blender/flamenco-ng-poc/internal/manager/persistence"
+ "gitlab.com/blender/flamenco-ng-poc/internal/manager/task_state_machine/mocks"
+ "gitlab.com/blender/flamenco-ng-poc/pkg/api"
+)
+
+type StateMachineMocks struct {
+ persist *mocks.MockPersistenceService
+}
+
+func mockedTaskStateMachine(mockCtrl *gomock.Controller) (*StateMachine, *StateMachineMocks) {
+ mocks := StateMachineMocks{
+ persist: mocks.NewMockPersistenceService(mockCtrl),
+ }
+ sm := NewStateMachine(mocks.persist)
+ return sm, &mocks
+}
+
+func (m *StateMachineMocks) expectSaveTaskWithStatus(
+ t *testing.T,
+ task *persistence.Task,
+ expectTaskStatus api.TaskStatus,
+) {
+ m.persist.EXPECT().
+ SaveTask(gomock.Any(), task).
+ DoAndReturn(func(ctx context.Context, savedTask *persistence.Task) error {
+ assert.Equal(t, expectTaskStatus, savedTask.Status)
+ return nil
+ })
+}
+
+func (m *StateMachineMocks) expectSaveJobWithStatus(
+ t *testing.T,
+ job *persistence.Job,
+ expectJobStatus api.JobStatus,
+) {
+ m.persist.EXPECT().
+ SaveJobStatus(gomock.Any(), job).
+ DoAndReturn(func(ctx context.Context, savedJob *persistence.Job) error {
+ assert.Equal(t, expectJobStatus, savedJob.Status)
+ return nil
+ })
+}
+
+/* taskWithStatus() creates a task of a certain status, with a job of a certain status. */
+func taskWithStatus(jobStatus api.JobStatus, taskStatus api.TaskStatus) *persistence.Task {
+ job := persistence.Job{
+ Model: gorm.Model{ID: 47},
+ UUID: "test-job-f3f5-4cef-9cd7-e67eb28eaf3e",
+
+ Status: jobStatus,
+ }
+ task := persistence.Task{
+ Model: gorm.Model{ID: 327},
+ UUID: "testtask-f474-4e28-aeea-8cbaf2fc96a5",
+
+ JobID: job.ID,
+ Job: &job,
+
+ Status: taskStatus,
+ }
+
+ return &task
+}
+
+func TestTaskStatusChange(t *testing.T) {
+ mockCtrl := gomock.NewController(t)
+ defer mockCtrl.Finish()
+ ctx := context.Background()
+
+ sm, mocks := mockedTaskStateMachine(mockCtrl)
+
+ task := taskWithStatus(api.JobStatusQueued, api.TaskStatusQueued)
+ mocks.expectSaveTaskWithStatus(t, task, api.TaskStatusActive)
+ mocks.expectSaveJobWithStatus(t, task.Job, api.JobStatusActive)
+ assert.NoError(t, sm.TaskStatusChange(ctx, task, api.TaskStatusActive))
+}
diff --git a/pkg/api/flamenco-manager.yaml b/pkg/api/flamenco-manager.yaml
index 5e964b85..2bfb7d10 100644
--- a/pkg/api/flamenco-manager.yaml
+++ b/pkg/api/flamenco-manager.yaml
@@ -337,7 +337,7 @@ components:
TaskStatus:
type: string
- enum: [active, canceled, completed, failed, queued, soft-failed, cancel-requested, fail-requested, paused]
+ enum: [active, canceled, completed, failed, queued, soft-failed, cancel-requested, paused]
Command:
type: object
diff --git a/pkg/api/openapi_spec.gen.go b/pkg/api/openapi_spec.gen.go
index 36a2999b..c77b810b 100644
--- a/pkg/api/openapi_spec.gen.go
+++ b/pkg/api/openapi_spec.gen.go
@@ -47,33 +47,33 @@ var swaggerSpec = []string{
"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",
- "3tXYcU+urfPaTed4dT+MxhkY6rXMtS/Nh6Wtfv36YPDB7CdtNVdDsdEaG94in9SZo4Z6jP0ms9wkT/ik",
- "MwT+yNRbW2IM9Iv1O2JnCMJgtqe+WsagdcWJGwFZycj76uDg4f8TLpfazRjsiJmZL7Wvue2wbNs72vmj",
- "y8MbASPOhJ/4iIyleOA6p0gxrTv33LbYWIbYCSEyhAePyZsVqDWChSalghWTleYbJ0s4tC55hipELgfG",
- "oS/lkiBTrcGax+nu/jhaM86xWgoTAJTC6sZyAFRxhn3HVFSc+1ny7NYz6KG6x9nIpXZFHd/biP8JiRlS",
- "BWb41Scm2K348id1cuPgEa3cerpTHzO2FG9uq4mQa+crUNor8r7FbtUJO6TtcXWN1IYaeJJTsYS+6C5u",
- "5w1c3Kqg2rbWNrEbMZXt4uoOeNnDQReLtaHKuMCla3phqzTNAbCTA1s1xZHOK5PJtZ1fgvar5WKBeDCA",
- "sC5YbN01Q66deGvLwJxWmPp7fawGhbZH0EUgc4vJ0dOYlFTrtVRZeOWiw31RIdSEpaoV9ohqVl921Eo1",
- "SxuYyo0po0vkkYmFdOMGYWhqmtlHFOoycgIUg69S3O/U08lkEao2Jif99vJ7N0h+RlVBCjdLIo+Pj7Ce",
- "ZSkIDa1znh+/XB326K/X6/FSVFjETfwePVmWfHQ4PhiDGOemcH0fM7zDrT8uiqM6aqMH44PxAa6WJQha",
- "Mqz47E+YIU1uLTOhJbMFmPVJqa0q0DOtMo8yN0wumHETBu/p38hsE9QHwu6hZckxWTEpJufaoYbz231e",
- "3R2nXPa0aged0lfPUdvpsai0UaBLiZrCkx4eHHxWztZUE12lKehFxfmGuM9MkBEmfAZfsayi3H2ZGm99",
- "lrsTNl2DM8CffUFC/2JjsyoKqja1VQklAtZ2KIqpvXYnPwltjQ5ttUCxqrSzSh2ddsi9CJ9WNDofAZGV",
- "kglj5a19bFKniSUMONpzMPX89h6t2h8WD6iuXtQMjLcU+BwM4b2hsp235sDU1sz9GtU1R9XqP2++NXf0",
- "9/FcJnOWXe5U4TMwae5CtT2yffcxYiiV/+TiIcgR60VU3NLjvqb/9B7tdE3QWfjumsNKbl8QmrhvntZ2",
- "N/Bbt0lkHkQL5Dyo3WWYifIzo9G6GRkNgmUYLvnR0v0g5kCxO6Copm0J3H9W8OyN2QZYFOhenAQePis4",
- "VgI+lJAayAj4NW3HCOx7hFwHewZf8j+cDmxyJkFcaHbqbY/SbClGcrG4Ju9i8b5Y9KHwUb+G+v0p0heB",
- "Fns65d+7U0SNRmevqLpo130UG2lXXu7R9hPK/UTeeZi9TMPBhX7IYBfCXgqAzZcKyFK66zyW/HjYJGKP",
- "RcS9BrU/Ync414OlzxnL/b7qDxHMN/bBx5XJQRg3bPEjHfSGcIFkXX8vvWOHVECzDa5Ceu57fWfMxBqD",
- "993V+CnWYCXQMln0n/YMyylJ7XvSNMuX8S4wI7t3/L5d6vbukeaQXpB1uMWUgwJ302izQwnDfjBKW6OF",
- "QfAaGEPcK5C1DxpQ7+s6NTo5b4Bn/115z+O5t5tTwpic5EyT1F5zTOztJJoiYHDIXGHqhsweS5qhd8dX",
- "YiIVIlfQSsAXUCMuU8ottFGu7xrPVtCRptI9VzX+nvaO9JrmkFUcTtxs+f4awPat8QHD2vvi7c53F1C9",
- "lv6+afcOnR2Qhys2l3H06ODw7kYSnY+aA8wfgwpN+FMQzIHmo4M/DVxOdg7INBHShEznPs84d4qJluG1",
- "vbYLnbtETnT7SZIIuXaiPjz8vKklRBEVyKVMDGXClt2Wu5gklXFX/pbS3j4W0uKsi7ZbRuwbR53W9Fva",
- "2BdK1qe0d3A1MB9pRcjko518+z5/OFZa37Fu0up7gp/e6999umhJsisWfT2EfTqy6C57/IZscZJDoLW2",
- "0JpCGTLqYIic+O9qNiN71Gi7kTOajRPTpW1jpk3/j5KW3jafOFHymJhNyVLK+abzRbJUcqlA69hfmfK3",
- "zxVZUMYrBXtzS8goGkTWGdugugN1RDGsiEKkqlXwcTc2n0StomvbeN8gIuP/FpTtPWwUYQnGztfqG2AJ",
- "5QmnnbGYttf6tiaCx0fdGWm7iJNFUQn/rZaZvDdIHTfkvTYuTy//HQAA//9lIuHh2TQAAA==",
+ "3tXYcU+urfPaTed4dT+MxhkY6rXMtS/Nh6Wtfv36YPDB7CdtNVdDsdEaG94in9SZo4Z6jP0mswzkCZ9j",
+ "hrAeeXhrK4qB9rB+R+zIQBhM7tQXxxijrhZxEx8rCHlfHRw8/H/C5VK7kYKdKDPzpfYltp2NbTtDO110",
+ "eXgjYMSZ8AMekbEUD1znFCmmdaOe244aqw47EESG8OAxebMCtUZs0KRUsGKy0nzjZAmH1hXOUEHI5cD0",
+ "86VcEmSqNUfzsNzdH0drxjkWR6HhRymsbiwHQBVn2GZMRcW5Hx3Pbj1yHipznI1cJlfU8b0N8J+QhyFV",
+ "YIZffWI+3Qonf1InFQ4e0Uqlpzv1MWNL8ea2mgipdb4Cpb0i71vsVlmwQ9oeV9dIbaiBJzkVS+iL7uJ2",
+ "3sDFreqnbWttE7sRU9kuru6Alz0cdKFXG6qMC1y6phe2KNMcABs3sEVSHOm8Mplc23ElaL9aLhaIBwMI",
+ "64LFllkz5NqJt7YMzGmFmb7XtmpQaHsEXQQyt5gcPY1JSbVeS5WFVy463AcUQk1Yqlphj6hm9WUnq1Sz",
+ "tIGp3JgyukQemVhIN10QhqamGXVEoQwjJ0Ax+CrF/U49nUwWoUhjctLvJr93c+NnVBWkcKMj8vj4CMtX",
+ "loLQ0Drn+fHL1WGP/nq9Hi9FhTXbxO/Rk2XJR4fjgzGIcW4K1+Yxwzvc+uOiOKqjNnowPhgf4GpZgqAl",
+ "wwLP/oQZ0uTWMhNaMltvWZ+U2qoCPdMq8yhzs+OCGTdQ8J7+jcw2QX0g7B5alhyTFZNicq4daji/3efV",
+ "3enJZU+rdq4pfbEctZ0ea0gbBbqUqCk86eHBwWflbE010VWagl5UnG+I+6oEGWHCZ/AVyyrK3Yeo8dZX",
+ "uDth0/UzA/zZFyS0KzY2q6KgalNblVAiYG1noJjaa3fyg8/WpNBWCxSLSDua1NFph9yL8CVFo/MREFkp",
+ "mTBW3trHJnWaWMKAoz0HU49r79Gq/dnwgOrqRc18eEuBz8EQ3psh2/FqDkxtjdivUV1zVK3+8+bTckd/",
+ "H89lMmfZ5U4VPgOT5i5U2xPadx8jhlL5LyweghyxXkTFLT3u6/FP79FO1wSdhe+uOazk9gWhifvEaW13",
+ "A791m0TmQbRAzoPaXYaZKD8iGq2bCdEgWIZZkp8k3Q9iDhS7A4pq2pbA/WcFz95UbYBFge7FSeDhs4Jj",
+ "JeBDCamBjIBf03aMwL5HyHWwZ/Al/8PpwCZnEsSFZqfe9ijNlmIkF4tr8i4W74tFHwof9Wuo358ifRFo",
+ "sadT/r07RdRodPaKqot23UexkXbl5R5tP6HcD+Cdh9m7Mxxc6IcMdiHsHQDYfKmALKW7vWPJj4dNIvZY",
+ "RNxrUPsjdodzPUf6nLHc76v+EMF8Yx98XJkchHHDFj/SQW8I90XW9efRO3ZIBTTb4Cqk5z7Pd8ZMrDF4",
+ "312Nn2INVgItk0X/ac+wnJLUvidNs3wZ7wIzsnvH79ulbu8eaQ7pBVmHS0s5KHAXizY7lDDsB6O0NVoY",
+ "BK+BMcS9Aln7oAH1vq5To5PzBnj235X3PJ57uzkljMlJzjRJ7a3GxF5GoikCBofMFaZuyOyxpBl6d3wl",
+ "JlIhcgWtBHwBNeIypdxCG+X6rvFsBR1pKt1zVeOvZe9Ir2kOWcXhxM2W768BbF8SHzCsvR7e7nx3AdVr",
+ "6a+Xdq/M2QF5uFFzGUePDg7vbiTR+YY5wPwxqNCEPwXBHGg+OvjTwF1k54BMEyFNyHTua4xzp5hoGV7b",
+ "W7rQuTrkRLdfIImQayfqw8PPm1pCFFGBXMrEUCZs2W25i0lSGXfDbyntZWMhLc66aLtlxL5x1GlNv6WN",
+ "faFkfUp7B1cD85FWhEw+2sm37/OHY6X1Hesmrb4n+Om9/t2ni5Yku2LR10PYpyOL7m7Hb8gWJzkEWmsL",
+ "rSmUIaMOhsiJ/65mM7JHjbYbOaPZODFd2jZm2vT/KGnpbfOJEyWPidmULKWcbzpfJEsllwq0jv0NKX/Z",
+ "XJEFZbxSsDe3hIyiQWSdsQ2qO1BHFMOKKESqWgUfd2PzSdQquraN9w0iMv5vQdleu0YRlmDsfK2+8JVQ",
+ "nnDaGYtpe4tvayJ4fNSdkbaLOFkUlfDfapnJe4PUcUPea+Py9PLfAQAA//8fq3bVyDQAAA==",
}
// GetSwagger returns the content of the embedded swagger specification file
diff --git a/pkg/api/openapi_types.gen.go b/pkg/api/openapi_types.gen.go
index 8fb4843a..da42dd62 100644
--- a/pkg/api/openapi_types.gen.go
+++ b/pkg/api/openapi_types.gen.go
@@ -76,8 +76,6 @@ const (
TaskStatusCompleted TaskStatus = "completed"
- TaskStatusFailRequested TaskStatus = "fail-requested"
-
TaskStatusFailed TaskStatus = "failed"
TaskStatusPaused TaskStatus = "paused"