From dfc3f09c9e949a1d4f4cda171197235c89e17767 Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Wed, 11 Oct 2023 16:05:01 +0200 Subject: [PATCH 01/12] Added rerun pipeline job api method --- api/jobs/job_controller.go | 56 +++++++++++++++++++++++ api/jobs/manage_job_handler.go | 82 ++++++++++++++++++++++++++++++++++ api/jobs/models/job.go | 35 ++++++++++----- api/jobs/start_job_handler.go | 16 ++++--- api/jobs/stop_job_handler.go | 35 --------------- swaggerui_src/swagger.json | 57 +++++++++++++++++++++++ 6 files changed, 227 insertions(+), 54 deletions(-) create mode 100644 api/jobs/manage_job_handler.go delete mode 100644 api/jobs/stop_job_handler.go diff --git a/api/jobs/job_controller.go b/api/jobs/job_controller.go index 180ed1f9..4d93ea27 100644 --- a/api/jobs/job_controller.go +++ b/api/jobs/job_controller.go @@ -10,6 +10,7 @@ import ( "github.com/equinor/radix-api/models" radixhttp "github.com/equinor/radix-common/net/http" "github.com/gorilla/mux" + log "github.com/sirupsen/logrus" ) const rootPath = "/applications/{appName}" @@ -41,6 +42,11 @@ func (jc *jobController) GetRoutes() models.Routes { Method: "POST", HandlerFunc: StopApplicationJob, }, + models.Route{ + Path: rootPath + "/jobs/{jobName}/rerun", + Method: "POST", + HandlerFunc: RerunApplicationJob, + }, models.Route{ Path: rootPath + "/jobs/{jobName}/pipelineruns", Method: "GET", @@ -217,6 +223,7 @@ func StopApplicationJob(accounts models.Accounts, w http.ResponseWriter, r *http appName := mux.Vars(r)["appName"] jobName := mux.Vars(r)["jobName"] + log.Infof("Stop the pipeline job %s in the application %s", jobName, appName) handler := Init(accounts, deployments.Init(accounts)) err := handler.StopJob(r.Context(), appName, jobName) @@ -228,6 +235,55 @@ func StopApplicationJob(accounts models.Accounts, w http.ResponseWriter, r *http w.WriteHeader(http.StatusNoContent) } +// RerunApplicationJob Reruns the pipeline job +func RerunApplicationJob(accounts models.Accounts, w http.ResponseWriter, r *http.Request) { + // swagger:operation POST /applications/{appName}/jobs/{jobName}/restart pipeline-job rerunApplicationJob + // --- + // summary: Reruns the pipeline job + // parameters: + // - name: appName + // in: path + // description: name of application + // type: string + // required: true + // - name: jobName + // in: path + // description: name of job + // type: string + // required: true + // - name: Impersonate-User + // in: header + // description: Works only with custom setup of cluster. Allow impersonation of test users (Required if Impersonate-Group is set) + // type: string + // required: false + // - name: Impersonate-Group + // in: header + // description: Works only with custom setup of cluster. Allow impersonation of test group (Required if Impersonate-User is set) + // type: array + // items: + // type: string + // required: false + // responses: + // "204": + // description: "Job rerun ok" + // "401": + // description: "Unauthorized" + // "404": + // description: "Not found" + appName := mux.Vars(r)["appName"] + jobName := mux.Vars(r)["jobName"] + log.Infof("Ru-run the pipeline job %s in the application %s", jobName, appName) + handler := Init(accounts, deployments.Init(accounts)) + err := handler.RerunJob(r.Context(), appName, jobName) + + if err != nil { + radixhttp.ErrorResponse(w, r, err) + return + } + + w.WriteHeader(http.StatusNoContent) +} + // GetTektonPipelineRuns Get the Tekton pipeline runs overview func GetTektonPipelineRuns(accounts models.Accounts, w http.ResponseWriter, r *http.Request) { // swagger:operation GET /applications/{appName}/jobs/{jobName}/pipelineruns pipeline-job getTektonPipelineRuns diff --git a/api/jobs/manage_job_handler.go b/api/jobs/manage_job_handler.go new file mode 100644 index 00000000..fb3c4a15 --- /dev/null +++ b/api/jobs/manage_job_handler.go @@ -0,0 +1,82 @@ +package jobs + +import ( + "context" + "fmt" + + jobModels "github.com/equinor/radix-api/api/jobs/models" + "github.com/equinor/radix-api/api/kubequery" + v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" + log "github.com/sirupsen/logrus" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// StopJob Stops an application job +func (jh JobHandler) StopJob(ctx context.Context, appName, jobName string) error { + log.Infof("Stopping the job: %s, %s", jobName, appName) + job, err := jh.getPipelineJob(ctx, appName, jobName) + if err != nil { + return err + } + + job.Spec.Stop = true + + _, err = jh.userAccount.RadixClient.RadixV1().RadixJobs(job.GetNamespace()).Update(ctx, job, metav1.UpdateOptions{}) + if err != nil { + return fmt.Errorf("failed to patch job object: %v", err) + } + return nil +} + +// RerunJob Reruns the pipeline job as a copy +func (jh JobHandler) RerunJob(ctx context.Context, appName, srcJobName string) error { + log.Infof("Rerunning the job %s in the application %s", srcJobName, appName) + srcRadixJob, err := jh.getPipelineJob(ctx, appName, srcJobName) + if err != nil { + return err + } + + destRadixJob := jh.buildPipelineJobRerunFrom(srcRadixJob) + _, err = jh.createPipelineJob(ctx, appName, destRadixJob) + if err != nil { + return fmt.Errorf("failed to create a job %s to rerun: %v", srcRadixJob.GetName(), err) + } + + log.Infof("reran the job %s as a new job %s in the application %s", srcRadixJob.GetName(), destRadixJob.GetName(), appName) + return nil +} + +func (jh JobHandler) buildPipelineJobRerunFrom(srcRadixJob *v1.RadixJob) *v1.RadixJob { + destJobName, imageTag := getUniqueJobName(workerImage) + destRadixJob := v1.RadixJob{ + ObjectMeta: metav1.ObjectMeta{ + Name: destJobName, + Labels: srcRadixJob.Labels, + Annotations: srcRadixJob.Annotations, + }, + Spec: srcRadixJob.Spec, + } + destRadixJob.ObjectMeta.Annotations[jobModels.RadixPipelineJobRerunAnnotation] = srcRadixJob.GetName() + if len(destRadixJob.Spec.Build.ImageTag) > 0 { + destRadixJob.Spec.Build.ImageTag = imageTag + } + destRadixJob.Spec.Stop = false + triggeredBy, err := jh.getTriggeredBy("") + if err != nil { + log.Warnf("failed to get triggeredBy: %v", err) + } + destRadixJob.Spec.TriggeredBy = triggeredBy + return &destRadixJob +} + +func (jh JobHandler) getPipelineJob(ctx context.Context, appName string, jobName string) (*v1.RadixJob, error) { + job, err := kubequery.GetRadixJob(ctx, jh.serviceAccount.RadixClient, appName, jobName) + if err == nil { + return job, nil + } + if errors.IsNotFound(err) { + return nil, jobModels.PipelineNotFoundError(appName, jobName) + } + return nil, err +} diff --git a/api/jobs/models/job.go b/api/jobs/models/job.go index 77468236..446a2c86 100644 --- a/api/jobs/models/job.go +++ b/api/jobs/models/job.go @@ -6,6 +6,10 @@ import ( v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" ) +const ( + RadixPipelineJobRerunAnnotation = "radix.equinor.com/rerun-pipeline-job-from" +) + // Job holds general information about job // swagger:model Job type Job struct { @@ -39,6 +43,12 @@ type Job struct { // example: a_user@equinor.com TriggeredBy string `json:"triggeredBy"` + // RerunFromJob The source name of the job if this job was restarted from it + // + // required: false + // example: radix-pipeline-20231011104617-urynf + RerunFromJob string `json:"rerunFromJob"` + // Started timestamp // // required: false @@ -127,18 +137,19 @@ func GetJobFromRadixJob(job *v1.RadixJob, jobDeployments []*deploymentModels.Dep } jobModel := Job{ - Name: job.GetName(), - Branch: job.Spec.Build.Branch, - CommitID: job.Spec.Build.CommitID, - Created: created, - Started: radixutils.FormatTime(job.Status.Started), - Ended: radixutils.FormatTime(job.Status.Ended), - Status: GetStatusFromRadixJobStatus(job.Status, job.Spec.Stop), - Pipeline: string(job.Spec.PipeLineType), - Steps: steps, - Deployments: jobDeployments, - Components: jobComponents, - TriggeredBy: job.Spec.TriggeredBy, + Name: job.GetName(), + Branch: job.Spec.Build.Branch, + CommitID: job.Spec.Build.CommitID, + Created: created, + Started: radixutils.FormatTime(job.Status.Started), + Ended: radixutils.FormatTime(job.Status.Ended), + Status: GetStatusFromRadixJobStatus(job.Status, job.Spec.Stop), + Pipeline: string(job.Spec.PipeLineType), + Steps: steps, + Deployments: jobDeployments, + Components: jobComponents, + TriggeredBy: job.Spec.TriggeredBy, + RerunFromJob: job.Annotations[RadixPipelineJobRerunAnnotation], } if job.Spec.PipeLineType == v1.Promote { jobModel.PromotedFromEnvironment = job.Spec.Promote.FromEnvironment diff --git a/api/jobs/start_job_handler.go b/api/jobs/start_job_handler.go index 98042e33..83610afc 100644 --- a/api/jobs/start_job_handler.go +++ b/api/jobs/start_job_handler.go @@ -34,16 +34,19 @@ func (jh JobHandler) HandleStartPipelineJob(ctx context.Context, appName string, return nil, err } - job := jh.createPipelineJob(appName, radixRegistration.Spec.CloneURL, radixConfigFullName, pipeline, jobSpec) + job := jh.buildPipelineJob(appName, radixRegistration.Spec.CloneURL, radixConfigFullName, pipeline, jobSpec) + return jh.createPipelineJob(ctx, appName, job) +} +func (jh JobHandler) createPipelineJob(ctx context.Context, appName string, job *v1.RadixJob) (*jobModels.JobSummary, error) { log.Infof("Starting job: %s, %s", job.GetName(), workerImage) appNamespace := k8sObjectUtils.GetAppNamespace(appName) - job, err = jh.userAccount.RadixClient.RadixV1().RadixJobs(appNamespace).Create(ctx, job, metav1.CreateOptions{}) + job, err := jh.userAccount.RadixClient.RadixV1().RadixJobs(appNamespace).Create(ctx, job, metav1.CreateOptions{}) if err != nil { return nil, err } - metrics.AddJobTriggered(appName, string(pipeline.Type)) + metrics.AddJobTriggered(appName, string(job.Spec.PipeLineType)) log.Infof("Started job: %s, %s", job.GetName(), workerImage) return jobModels.GetSummaryFromRadixJob(job), nil @@ -59,7 +62,7 @@ func getRadixConfigFullName(radixRegistration *v1.RadixRegistration) (string, er return radixRegistration.Spec.RadixConfigFullName, nil } -func (jh JobHandler) createPipelineJob(appName, cloneURL, radixConfigFullName string, pipeline *pipelineJob.Definition, jobSpec *jobModels.JobParameters) *v1.RadixJob { +func (jh JobHandler) buildPipelineJob(appName, cloneURL, radixConfigFullName string, pipeline *pipelineJob.Definition, jobSpec *jobModels.JobParameters) *v1.RadixJob { jobName, imageTag := getUniqueJobName(workerImage) if len(jobSpec.ImageTag) > 0 { imageTag = jobSpec.ImageTag @@ -69,7 +72,7 @@ func (jh JobHandler) createPipelineJob(appName, cloneURL, radixConfigFullName st var promoteSpec v1.RadixPromoteSpec var deploySpec v1.RadixDeploySpec - triggeredBy, err := jh.getTriggeredBy(jobSpec) + triggeredBy, err := jh.getTriggeredBy(jobSpec.TriggeredBy) if err != nil { log.Warnf("failed to get triggeredBy: %v", err) } @@ -121,8 +124,7 @@ func (jh JobHandler) createPipelineJob(appName, cloneURL, radixConfigFullName st return &job } -func (jh JobHandler) getTriggeredBy(jobSpec *jobModels.JobParameters) (string, error) { - triggeredBy := jobSpec.TriggeredBy +func (jh JobHandler) getTriggeredBy(triggeredBy string) (string, error) { if triggeredBy != "" && triggeredBy != "" { return triggeredBy, nil } diff --git a/api/jobs/stop_job_handler.go b/api/jobs/stop_job_handler.go deleted file mode 100644 index 6e8b6a71..00000000 --- a/api/jobs/stop_job_handler.go +++ /dev/null @@ -1,35 +0,0 @@ -package jobs - -import ( - "context" - "fmt" - - jobModels "github.com/equinor/radix-api/api/jobs/models" - crdUtils "github.com/equinor/radix-operator/pkg/apis/utils" - log "github.com/sirupsen/logrus" - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// StopJob Stops an application job -func (jh JobHandler) StopJob(ctx context.Context, appName, jobName string) error { - log.Infof("Stopping job: %s, %s", jobName, appName) - appNamespace := crdUtils.GetAppNamespace(appName) - job, err := jh.serviceAccount.RadixClient.RadixV1().RadixJobs(appNamespace).Get(ctx, jobName, metav1.GetOptions{}) - - if errors.IsNotFound(err) { - return jobModels.PipelineNotFoundError(appName, jobName) - } - if err != nil { - return err - } - - job.Spec.Stop = true - - _, err = jh.userAccount.RadixClient.RadixV1().RadixJobs(appNamespace).Update(ctx, job, metav1.UpdateOptions{}) - if err != nil { - return fmt.Errorf("failed to patch job object: %v", err) - } - - return nil -} diff --git a/swaggerui_src/swagger.json b/swaggerui_src/swagger.json index 155eb3e8..12926e2a 100644 --- a/swaggerui_src/swagger.json +++ b/swaggerui_src/swagger.json @@ -4364,6 +4364,57 @@ } } }, + "/applications/{appName}/jobs/{jobName}/restart": { + "post": { + "tags": [ + "pipeline-job" + ], + "summary": "Reruns the pipeline job", + "operationId": "rerunApplicationJob", + "parameters": [ + { + "type": "string", + "description": "name of application", + "name": "appName", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name of job", + "name": "jobName", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Works only with custom setup of cluster. Allow impersonation of test users (Required if Impersonate-Group is set)", + "name": "Impersonate-User", + "in": "header" + }, + { + "type": "array", + "items": { + "type": "string" + }, + "description": "Works only with custom setup of cluster. Allow impersonation of test group (Required if Impersonate-User is set)", + "name": "Impersonate-Group", + "in": "header" + } + ], + "responses": { + "204": { + "description": "Job rerun ok" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not found" + } + } + } + }, "/applications/{appName}/jobs/{jobName}/stop": { "post": { "tags": [ @@ -6238,6 +6289,12 @@ "x-go-name": "PromotedToEnvironment", "example": "qa" }, + "rerunFromJob": { + "description": "RerunFromJob The source name of the job if this job was restarted from it", + "type": "string", + "x-go-name": "RerunFromJob", + "example": "radix-pipeline-20231011104617-urynf" + }, "started": { "description": "Started timestamp", "type": "string", From 5c6e904d6fa1110bfc833e93c79818a990d1e2a6 Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Thu, 12 Oct 2023 17:05:45 +0200 Subject: [PATCH 02/12] Added rerun pipeline job tests --- api/jobs/job_handler_test.go | 114 +++++++++++++++++++++++++++++---- api/jobs/manage_job_handler.go | 19 ++++-- api/jobs/models/job_errors.go | 6 ++ 3 files changed, 123 insertions(+), 16 deletions(-) diff --git a/api/jobs/job_handler_test.go b/api/jobs/job_handler_test.go index 0dc08c1e..a4efdf05 100644 --- a/api/jobs/job_handler_test.go +++ b/api/jobs/job_handler_test.go @@ -2,18 +2,17 @@ package jobs import ( "context" + "fmt" "testing" "time" - secretproviderfake "sigs.k8s.io/secrets-store-csi-driver/pkg/client/clientset/versioned/fake" - deployMock "github.com/equinor/radix-api/api/deployments/mock" deploymentModels "github.com/equinor/radix-api/api/deployments/models" jobModels "github.com/equinor/radix-api/api/jobs/models" "github.com/equinor/radix-api/models" - radixmodels "github.com/equinor/radix-common/models" + models2 "github.com/equinor/radix-common/models" radixutils "github.com/equinor/radix-common/utils" - v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" + "github.com/equinor/radix-operator/pkg/apis/radix/v1" "github.com/equinor/radix-operator/pkg/apis/utils" "github.com/equinor/radix-operator/pkg/apis/utils/slice" radixfake "github.com/equinor/radix-operator/pkg/client/clientset/versioned/fake" @@ -23,6 +22,7 @@ import ( k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" kubefake "k8s.io/client-go/kubernetes/fake" + secretproviderfake "sigs.k8s.io/secrets-store-csi-driver/pkg/client/clientset/versioned/fake" ) type JobHandlerTestSuite struct { @@ -52,16 +52,40 @@ type jobStatusScenario struct { expectedStatus string } +type jobProperties struct { + name string + condition v1.RadixJobCondition + stop bool +} + +type jobRerunScenario struct { + scenarioName string + existingJob *jobProperties + jobNameToRerun string + expectedError error +} + func TestRunJobHandlerTestSuite(t *testing.T) { suite.Run(t, new(JobHandlerTestSuite)) } func (s *JobHandlerTestSuite) SetupTest() { + s.setupTest() +} + +func (s *JobHandlerTestSuite) setupTest() { s.inKubeClient, s.inRadixClient, s.outKubeClient, s.outRadixClient, s.inSecretProviderClient, s.outSecretProviderClient = s.getUtils() - accounts := models.NewAccounts(s.inKubeClient, s.inRadixClient, s.inSecretProviderClient, nil, s.outKubeClient, s.outRadixClient, s.outSecretProviderClient, nil, "", radixmodels.Impersonation{}) + accounts := models.NewAccounts(s.inKubeClient, s.inRadixClient, s.inSecretProviderClient, nil, s.outKubeClient, s.outRadixClient, s.outSecretProviderClient, nil, "", models2.Impersonation{}) s.accounts = accounts } +func (s *JobHandlerTestSuite) getUtils() (inKubeClient *kubefake.Clientset, inRadixClient *radixfake.Clientset, outKubeClient *kubefake.Clientset, outRadixClient *radixfake.Clientset, inSecretProviderClient *secretproviderfake.Clientset, outSecretProviderClient *secretproviderfake.Clientset) { + inKubeClient, outKubeClient = kubefake.NewSimpleClientset(), kubefake.NewSimpleClientset() + inRadixClient, outRadixClient = radixfake.NewSimpleClientset(), radixfake.NewSimpleClientset() + inSecretProviderClient, outSecretProviderClient = secretproviderfake.NewSimpleClientset(), secretproviderfake.NewSimpleClientset() + return +} + func (s *JobHandlerTestSuite) Test_GetApplicationJob() { jobName, appName, branch, commitId, pipeline, triggeredBy := "a_job", "an_app", "a_branch", "a_commitid", v1.BuildDeploy, "a_user" started, ended := metav1.NewTime(time.Date(2020, 1, 1, 0, 0, 0, 0, time.Local)), metav1.NewTime(time.Date(2020, 1, 2, 0, 0, 0, 0, time.Local)) @@ -90,7 +114,8 @@ func (s *JobHandlerTestSuite) Test_GetApplicationJob() { }, }, } - s.outRadixClient.RadixV1().RadixJobs(rj.Namespace).Create(context.Background(), rj, metav1.CreateOptions{}) + _, err := s.outRadixClient.RadixV1().RadixJobs(rj.Namespace).Create(context.Background(), rj, metav1.CreateOptions{}) + s.NoError(err) deploymentName := "a_deployment" comp1Name, comp1Type, comp1Image := "comp1", "type1", "image1" @@ -229,9 +254,76 @@ func (s *JobHandlerTestSuite) Test_GetApplicationJob_Status() { } } -func (s *JobHandlerTestSuite) getUtils() (inKubeClient *kubefake.Clientset, inRadixClient *radixfake.Clientset, outKubeClient *kubefake.Clientset, outRadixClient *radixfake.Clientset, inSecretProviderClient *secretproviderfake.Clientset, outSecretProviderClient *secretproviderfake.Clientset) { - inKubeClient, outKubeClient = kubefake.NewSimpleClientset(), kubefake.NewSimpleClientset() - inRadixClient, outRadixClient = radixfake.NewSimpleClientset(), radixfake.NewSimpleClientset() - inSecretProviderClient, outSecretProviderClient = secretproviderfake.NewSimpleClientset(), secretproviderfake.NewSimpleClientset() - return +func (s *JobHandlerTestSuite) TestJobHandler_RerunJob() { + appName := "anyApp" + namespace := utils.GetAppNamespace(appName) + tests := []jobRerunScenario{ + {scenarioName: "existing failed job", existingJob: &jobProperties{name: "job1", condition: v1.JobFailed}, jobNameToRerun: "job1", expectedError: nil}, + {scenarioName: "existing stopped job", existingJob: &jobProperties{name: "job1", condition: v1.JobStopped, stop: true}, jobNameToRerun: "job1", expectedError: nil}, + {scenarioName: "existing running job", existingJob: &jobProperties{name: "job1", condition: v1.JobRunning}, jobNameToRerun: "job1", expectedError: jobModels.JobHasInvalidConditionToRerunError(appName, "job1", v1.JobRunning)}, + {scenarioName: "existing stopped-no-changes job", existingJob: &jobProperties{name: "job1", condition: v1.JobStoppedNoChanges}, jobNameToRerun: "job1", expectedError: jobModels.JobHasInvalidConditionToRerunError(appName, "job1", v1.JobStoppedNoChanges)}, + {scenarioName: "existing queued job", existingJob: &jobProperties{name: "job1", condition: v1.JobQueued}, jobNameToRerun: "job1", expectedError: jobModels.JobHasInvalidConditionToRerunError(appName, "job1", v1.JobQueued)}, + {scenarioName: "existing succeeded job", existingJob: &jobProperties{name: "job1", condition: v1.JobSucceeded}, jobNameToRerun: "job1", expectedError: jobModels.JobHasInvalidConditionToRerunError(appName, "job1", v1.JobSucceeded)}, + {scenarioName: "existing waiting job", existingJob: &jobProperties{name: "job1", condition: v1.JobWaiting}, jobNameToRerun: "job1", expectedError: jobModels.JobHasInvalidConditionToRerunError(appName, "job1", v1.JobWaiting)}, + {scenarioName: "not existing job", existingJob: nil, jobNameToRerun: "job1", expectedError: jobModels.PipelineNotFoundError(appName, "job1")}, + } + for _, tt := range tests { + s.T().Run(tt.scenarioName, func(t *testing.T) { + s.setupTest() + ctrl := gomock.NewController(s.T()) + defer ctrl.Finish() + dh := deployMock.NewMockDeployHandler(ctrl) + jh := JobHandler{ + accounts: s.accounts, + userAccount: s.accounts.UserAccount, + serviceAccount: s.accounts.ServiceAccount, + deploy: dh, + } + if tt.existingJob != nil { + _, err := s.inRadixClient.RadixV1().RadixJobs(namespace).Create(context.Background(), &v1.RadixJob{ + ObjectMeta: metav1.ObjectMeta{Namespace: namespace, Name: tt.existingJob.name}, + Spec: v1.RadixJobSpec{Stop: tt.existingJob.stop}, + Status: v1.RadixJobStatus{Condition: tt.existingJob.condition}, + }, metav1.CreateOptions{}) + s.NoError(err) + } + + err := jh.RerunJob(context.Background(), appName, tt.jobNameToRerun) + s.Equal(tt.expectedError, err) + }) + } +} + +func (s *JobHandlerTestSuite) TestJobHandler_StopJob() { + type args struct { + ctx context.Context + appName string + jobName string + } + // appName := "anyApp" + tests := []struct { + name string + setMocks func(s *JobHandlerTestSuite, deployHandlerMock *deployMock.MockDeployHandler) + args args + wantErr assert.ErrorAssertionFunc + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + s.T().Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(s.T()) + defer ctrl.Finish() + dh := deployMock.NewMockDeployHandler(ctrl) + jh := JobHandler{ + accounts: s.accounts, + userAccount: s.accounts.UserAccount, + serviceAccount: s.accounts.ServiceAccount, + deploy: dh, + } + + tt.setMocks(s, dh) + + tt.wantErr(t, jh.StopJob(tt.args.ctx, tt.args.appName, tt.args.jobName), fmt.Sprintf("StopJob(%v, %v, %v)", tt.args.ctx, tt.args.appName, tt.args.jobName)) + }) + } } diff --git a/api/jobs/manage_job_handler.go b/api/jobs/manage_job_handler.go index fb3c4a15..7355f3ad 100644 --- a/api/jobs/manage_job_handler.go +++ b/api/jobs/manage_job_handler.go @@ -6,12 +6,15 @@ import ( jobModels "github.com/equinor/radix-api/api/jobs/models" "github.com/equinor/radix-api/api/kubequery" + "github.com/equinor/radix-common/utils/slice" v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" log "github.com/sirupsen/logrus" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +var jobConditionsAllowedForRerun = []v1.RadixJobCondition{v1.JobFailed, v1.JobStopped} + // StopJob Stops an application job func (jh JobHandler) StopJob(ctx context.Context, appName, jobName string) error { log.Infof("Stopping the job: %s, %s", jobName, appName) @@ -32,18 +35,21 @@ func (jh JobHandler) StopJob(ctx context.Context, appName, jobName string) error // RerunJob Reruns the pipeline job as a copy func (jh JobHandler) RerunJob(ctx context.Context, appName, srcJobName string) error { log.Infof("Rerunning the job %s in the application %s", srcJobName, appName) - srcRadixJob, err := jh.getPipelineJob(ctx, appName, srcJobName) + radixJob, err := jh.getPipelineJob(ctx, appName, srcJobName) if err != nil { return err } + if !slice.Any(jobConditionsAllowedForRerun, func(condition v1.RadixJobCondition) bool { return condition == radixJob.Status.Condition }) { + return jobModels.JobHasInvalidConditionToRerunError(appName, srcJobName, radixJob.Status.Condition) + } - destRadixJob := jh.buildPipelineJobRerunFrom(srcRadixJob) - _, err = jh.createPipelineJob(ctx, appName, destRadixJob) + copiedRadixJob := jh.buildPipelineJobRerunFrom(radixJob) + _, err = jh.createPipelineJob(ctx, appName, copiedRadixJob) if err != nil { - return fmt.Errorf("failed to create a job %s to rerun: %v", srcRadixJob.GetName(), err) + return fmt.Errorf("failed to create a job %s to rerun: %v", radixJob.GetName(), err) } - log.Infof("reran the job %s as a new job %s in the application %s", srcRadixJob.GetName(), destRadixJob.GetName(), appName) + log.Infof("reran the job %s as a new job %s in the application %s", radixJob.GetName(), copiedRadixJob.GetName(), appName) return nil } @@ -57,6 +63,9 @@ func (jh JobHandler) buildPipelineJobRerunFrom(srcRadixJob *v1.RadixJob) *v1.Rad }, Spec: srcRadixJob.Spec, } + if destRadixJob.ObjectMeta.Annotations == nil { + destRadixJob.ObjectMeta.Annotations = make(map[string]string) + } destRadixJob.ObjectMeta.Annotations[jobModels.RadixPipelineJobRerunAnnotation] = srcRadixJob.GetName() if len(destRadixJob.Spec.Build.ImageTag) > 0 { destRadixJob.Spec.Build.ImageTag = imageTag diff --git a/api/jobs/models/job_errors.go b/api/jobs/models/job_errors.go index 4e98a812..7abb1a71 100644 --- a/api/jobs/models/job_errors.go +++ b/api/jobs/models/job_errors.go @@ -4,6 +4,7 @@ import ( "fmt" radixhttp "github.com/equinor/radix-common/net/http" + v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" ) // PipelineNotFoundError Pipeline job not found @@ -20,3 +21,8 @@ func PipelineStepNotFoundError(appName, jobName, stepName string) error { func PipelineRunNotFoundError(appName, jobName, pipelineRunName string) error { return radixhttp.TypeMissingError(fmt.Sprintf("pipeline run %s not found for the app %s and the pipeline job %s", pipelineRunName, appName, jobName), nil) } + +// JobHasInvalidConditionToRerunError Pipeline job cannot be rerun due to invalid condition +func JobHasInvalidConditionToRerunError(appName, jobName string, jobCondition v1.RadixJobCondition) error { + return radixhttp.ValidationError("Radix Application Pipeline", fmt.Sprintf("only Failed or Stopped pipeline jobs can be rerun, the job %s for the app %s has status %s", appName, jobName, jobCondition)) +} From 2ba24e0258f57f9538a6819d093277a0b298a231 Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Fri, 13 Oct 2023 15:01:29 +0200 Subject: [PATCH 03/12] Added stop pipeline job tests --- api/jobs/job_handler_test.go | 63 ++++++++++++++++++---------------- api/jobs/manage_job_handler.go | 27 ++++++++++----- api/jobs/models/job_errors.go | 15 +++++--- 3 files changed, 62 insertions(+), 43 deletions(-) diff --git a/api/jobs/job_handler_test.go b/api/jobs/job_handler_test.go index a4efdf05..95be213b 100644 --- a/api/jobs/job_handler_test.go +++ b/api/jobs/job_handler_test.go @@ -2,7 +2,6 @@ package jobs import ( "context" - "fmt" "testing" "time" @@ -273,12 +272,7 @@ func (s *JobHandlerTestSuite) TestJobHandler_RerunJob() { ctrl := gomock.NewController(s.T()) defer ctrl.Finish() dh := deployMock.NewMockDeployHandler(ctrl) - jh := JobHandler{ - accounts: s.accounts, - userAccount: s.accounts.UserAccount, - serviceAccount: s.accounts.ServiceAccount, - deploy: dh, - } + jh := s.getJobHandler(dh) if tt.existingJob != nil { _, err := s.inRadixClient.RadixV1().RadixJobs(namespace).Create(context.Background(), &v1.RadixJob{ ObjectMeta: metav1.ObjectMeta{Namespace: namespace, Name: tt.existingJob.name}, @@ -295,35 +289,46 @@ func (s *JobHandlerTestSuite) TestJobHandler_RerunJob() { } func (s *JobHandlerTestSuite) TestJobHandler_StopJob() { - type args struct { - ctx context.Context - appName string - jobName string - } - // appName := "anyApp" - tests := []struct { - name string - setMocks func(s *JobHandlerTestSuite, deployHandlerMock *deployMock.MockDeployHandler) - args args - wantErr assert.ErrorAssertionFunc - }{ - // TODO: Add test cases. + appName := "anyApp" + namespace := utils.GetAppNamespace(appName) + tests := []jobRerunScenario{ + {scenarioName: "existing failed job", existingJob: &jobProperties{name: "job1", condition: v1.JobFailed}, jobNameToRerun: "job1", expectedError: jobModels.JobHasInvalidConditionToRerunError(appName, "job1", v1.JobFailed)}, + {scenarioName: "existing stopped job", existingJob: &jobProperties{name: "job1", condition: v1.JobStopped, stop: true}, jobNameToRerun: "job1", expectedError: jobModels.JobHasInvalidConditionToStopError(appName, "job1", v1.JobStopped)}, + {scenarioName: "existing running job with stop in spec", existingJob: &jobProperties{name: "job1", condition: v1.JobRunning, stop: true}, jobNameToRerun: "job1", expectedError: jobModels.JobAlreadyRequestedToStopError(appName, "job1")}, + {scenarioName: "existing running job", existingJob: &jobProperties{name: "job1", condition: v1.JobRunning}, jobNameToRerun: "job1", expectedError: nil}, + {scenarioName: "existing stopped-no-changes job", existingJob: &jobProperties{name: "job1", condition: v1.JobStoppedNoChanges}, jobNameToRerun: "job1", expectedError: jobModels.JobHasInvalidConditionToRerunError(appName, "job1", v1.JobStoppedNoChanges)}, + {scenarioName: "existing queued job", existingJob: &jobProperties{name: "job1", condition: v1.JobQueued}, jobNameToRerun: "job1", expectedError: nil}, + {scenarioName: "existing succeeded job", existingJob: &jobProperties{name: "job1", condition: v1.JobSucceeded}, jobNameToRerun: "job1", expectedError: nil}, + {scenarioName: "existing waiting job", existingJob: &jobProperties{name: "job1", condition: v1.JobWaiting}, jobNameToRerun: "job1", expectedError: nil}, + {scenarioName: "not existing job", existingJob: nil, jobNameToRerun: "job1", expectedError: jobModels.PipelineNotFoundError(appName, "job1")}, } for _, tt := range tests { - s.T().Run(tt.name, func(t *testing.T) { + s.T().Run(tt.scenarioName, func(t *testing.T) { + s.setupTest() ctrl := gomock.NewController(s.T()) defer ctrl.Finish() dh := deployMock.NewMockDeployHandler(ctrl) - jh := JobHandler{ - accounts: s.accounts, - userAccount: s.accounts.UserAccount, - serviceAccount: s.accounts.ServiceAccount, - deploy: dh, + jh := s.getJobHandler(dh) + if tt.existingJob != nil { + _, err := s.inRadixClient.RadixV1().RadixJobs(namespace).Create(context.Background(), &v1.RadixJob{ + ObjectMeta: metav1.ObjectMeta{Namespace: namespace, Name: tt.existingJob.name}, + Spec: v1.RadixJobSpec{Stop: tt.existingJob.stop}, + Status: v1.RadixJobStatus{Condition: tt.existingJob.condition}, + }, metav1.CreateOptions{}) + s.NoError(err) } - tt.setMocks(s, dh) - - tt.wantErr(t, jh.StopJob(tt.args.ctx, tt.args.appName, tt.args.jobName), fmt.Sprintf("StopJob(%v, %v, %v)", tt.args.ctx, tt.args.appName, tt.args.jobName)) + err := jh.StopJob(context.Background(), appName, tt.jobNameToRerun) + s.Equal(tt.expectedError, err) }) } } + +func (s *JobHandlerTestSuite) getJobHandler(dh *deployMock.MockDeployHandler) JobHandler { + return JobHandler{ + accounts: s.accounts, + userAccount: s.accounts.UserAccount, + serviceAccount: s.accounts.ServiceAccount, + deploy: dh, + } +} diff --git a/api/jobs/manage_job_handler.go b/api/jobs/manage_job_handler.go index 7355f3ad..daf01113 100644 --- a/api/jobs/manage_job_handler.go +++ b/api/jobs/manage_job_handler.go @@ -13,19 +13,28 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -var jobConditionsAllowedForRerun = []v1.RadixJobCondition{v1.JobFailed, v1.JobStopped} +var ( + jobConditionsInValidForJobStop = []v1.RadixJobCondition{v1.JobFailed, v1.JobStopped, v1.JobStoppedNoChanges} + jobConditionsValidForJobRerun = []v1.RadixJobCondition{v1.JobFailed, v1.JobStopped} +) // StopJob Stops an application job func (jh JobHandler) StopJob(ctx context.Context, appName, jobName string) error { log.Infof("Stopping the job: %s, %s", jobName, appName) - job, err := jh.getPipelineJob(ctx, appName, jobName) + radixJob, err := jh.getPipelineJob(ctx, appName, jobName) if err != nil { return err } + if radixJob.Spec.Stop { + return jobModels.JobAlreadyRequestedToStopError(appName, jobName) + } + if slice.Any(jobConditionsInValidForJobStop, func(condition v1.RadixJobCondition) bool { return condition == radixJob.Status.Condition }) { + return jobModels.JobHasInvalidConditionToStopError(appName, jobName, radixJob.Status.Condition) + } - job.Spec.Stop = true + radixJob.Spec.Stop = true - _, err = jh.userAccount.RadixClient.RadixV1().RadixJobs(job.GetNamespace()).Update(ctx, job, metav1.UpdateOptions{}) + _, err = jh.userAccount.RadixClient.RadixV1().RadixJobs(radixJob.GetNamespace()).Update(ctx, radixJob, metav1.UpdateOptions{}) if err != nil { return fmt.Errorf("failed to patch job object: %v", err) } @@ -33,14 +42,14 @@ func (jh JobHandler) StopJob(ctx context.Context, appName, jobName string) error } // RerunJob Reruns the pipeline job as a copy -func (jh JobHandler) RerunJob(ctx context.Context, appName, srcJobName string) error { - log.Infof("Rerunning the job %s in the application %s", srcJobName, appName) - radixJob, err := jh.getPipelineJob(ctx, appName, srcJobName) +func (jh JobHandler) RerunJob(ctx context.Context, appName, jobName string) error { + log.Infof("Rerunning the job %s in the application %s", jobName, appName) + radixJob, err := jh.getPipelineJob(ctx, appName, jobName) if err != nil { return err } - if !slice.Any(jobConditionsAllowedForRerun, func(condition v1.RadixJobCondition) bool { return condition == radixJob.Status.Condition }) { - return jobModels.JobHasInvalidConditionToRerunError(appName, srcJobName, radixJob.Status.Condition) + if !slice.Any(jobConditionsValidForJobRerun, func(condition v1.RadixJobCondition) bool { return condition == radixJob.Status.Condition }) { + return jobModels.JobHasInvalidConditionToRerunError(appName, jobName, radixJob.Status.Condition) } copiedRadixJob := jh.buildPipelineJobRerunFrom(radixJob) diff --git a/api/jobs/models/job_errors.go b/api/jobs/models/job_errors.go index 7abb1a71..7c00c972 100644 --- a/api/jobs/models/job_errors.go +++ b/api/jobs/models/job_errors.go @@ -17,12 +17,17 @@ func PipelineStepNotFoundError(appName, jobName, stepName string) error { return radixhttp.TypeMissingError(fmt.Sprintf("step %s for the job %s not found for the app %s", stepName, jobName, appName), nil) } -// PipelineRunNotFoundError Tekton PipelineRun not found for the pipeline job -func PipelineRunNotFoundError(appName, jobName, pipelineRunName string) error { - return radixhttp.TypeMissingError(fmt.Sprintf("pipeline run %s not found for the app %s and the pipeline job %s", pipelineRunName, appName, jobName), nil) -} - // JobHasInvalidConditionToRerunError Pipeline job cannot be rerun due to invalid condition func JobHasInvalidConditionToRerunError(appName, jobName string, jobCondition v1.RadixJobCondition) error { return radixhttp.ValidationError("Radix Application Pipeline", fmt.Sprintf("only Failed or Stopped pipeline jobs can be rerun, the job %s for the app %s has status %s", appName, jobName, jobCondition)) } + +// JobAlreadyRequestedToStopError Pipeline job was already requested to stop +func JobAlreadyRequestedToStopError(appName, jobName string) error { + return radixhttp.ValidationError("Radix Application Pipeline", fmt.Sprintf("job %s for the app %s is already requested to stop", appName, jobName)) +} + +// JobHasInvalidConditionToStopError Pipeline job cannot be stopped due to invalid condition +func JobHasInvalidConditionToStopError(appName, jobName string, jobCondition v1.RadixJobCondition) error { + return radixhttp.ValidationError("Radix Application Pipeline", fmt.Sprintf("only not Failed or Stopped pipeline jobs can be stopped, the job %s for the app %s has status %s", appName, jobName, jobCondition)) +} From bd732fa4f4075aec1b18e75f915517c822c5faa7 Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Mon, 16 Oct 2023 10:39:48 +0200 Subject: [PATCH 04/12] Cleanup and unit-test fix --- api/jobs/job_controller.go | 2 +- api/jobs/job_handler_test.go | 82 +++++++++++++++++----------------- api/jobs/manage_job_handler.go | 52 ++++++++++----------- api/jobs/models/job_errors.go | 8 ++-- 4 files changed, 72 insertions(+), 72 deletions(-) diff --git a/api/jobs/job_controller.go b/api/jobs/job_controller.go index 4d93ea27..8ce05eb0 100644 --- a/api/jobs/job_controller.go +++ b/api/jobs/job_controller.go @@ -272,7 +272,7 @@ func RerunApplicationJob(accounts models.Accounts, w http.ResponseWriter, r *htt // description: "Not found" appName := mux.Vars(r)["appName"] jobName := mux.Vars(r)["jobName"] - log.Infof("Ru-run the pipeline job %s in the application %s", jobName, appName) + log.Infof("Rerun the pipeline job %s in the application %s", jobName, appName) handler := Init(accounts, deployments.Init(accounts)) err := handler.RerunJob(r.Context(), appName, jobName) diff --git a/api/jobs/job_handler_test.go b/api/jobs/job_handler_test.go index 95be213b..f1ce09f1 100644 --- a/api/jobs/job_handler_test.go +++ b/api/jobs/job_handler_test.go @@ -9,9 +9,9 @@ import ( deploymentModels "github.com/equinor/radix-api/api/deployments/models" jobModels "github.com/equinor/radix-api/api/jobs/models" "github.com/equinor/radix-api/models" - models2 "github.com/equinor/radix-common/models" + radixmodels "github.com/equinor/radix-common/models" radixutils "github.com/equinor/radix-common/utils" - "github.com/equinor/radix-operator/pkg/apis/radix/v1" + radixv1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" "github.com/equinor/radix-operator/pkg/apis/utils" "github.com/equinor/radix-operator/pkg/apis/utils/slice" radixfake "github.com/equinor/radix-operator/pkg/client/clientset/versioned/fake" @@ -46,14 +46,14 @@ type jobCreatedScenario struct { type jobStatusScenario struct { scenarioName string jobName string - condition v1.RadixJobCondition + condition radixv1.RadixJobCondition stop bool expectedStatus string } type jobProperties struct { name string - condition v1.RadixJobCondition + condition radixv1.RadixJobCondition stop bool } @@ -74,7 +74,7 @@ func (s *JobHandlerTestSuite) SetupTest() { func (s *JobHandlerTestSuite) setupTest() { s.inKubeClient, s.inRadixClient, s.outKubeClient, s.outRadixClient, s.inSecretProviderClient, s.outSecretProviderClient = s.getUtils() - accounts := models.NewAccounts(s.inKubeClient, s.inRadixClient, s.inSecretProviderClient, nil, s.outKubeClient, s.outRadixClient, s.outSecretProviderClient, nil, "", models2.Impersonation{}) + accounts := models.NewAccounts(s.inKubeClient, s.inRadixClient, s.inSecretProviderClient, nil, s.outKubeClient, s.outRadixClient, s.outSecretProviderClient, nil, "", radixmodels.Impersonation{}) s.accounts = accounts } @@ -86,28 +86,28 @@ func (s *JobHandlerTestSuite) getUtils() (inKubeClient *kubefake.Clientset, inRa } func (s *JobHandlerTestSuite) Test_GetApplicationJob() { - jobName, appName, branch, commitId, pipeline, triggeredBy := "a_job", "an_app", "a_branch", "a_commitid", v1.BuildDeploy, "a_user" + jobName, appName, branch, commitId, pipeline, triggeredBy := "a_job", "an_app", "a_branch", "a_commitid", radixv1.BuildDeploy, "a_user" started, ended := metav1.NewTime(time.Date(2020, 1, 1, 0, 0, 0, 0, time.Local)), metav1.NewTime(time.Date(2020, 1, 2, 0, 0, 0, 0, time.Local)) - step1Name, step1Pod, step1Condition, step1Started, step1Ended, step1Components := "step1_name", "step1_pod", v1.JobRunning, metav1.Now(), metav1.NewTime(time.Now().Add(1*time.Hour)), []string{"step1_comp1", "step1_comp2"} + step1Name, step1Pod, step1Condition, step1Started, step1Ended, step1Components := "step1_name", "step1_pod", radixv1.JobRunning, metav1.Now(), metav1.NewTime(time.Now().Add(1*time.Hour)), []string{"step1_comp1", "step1_comp2"} step2Name := "step2_name" - rj := &v1.RadixJob{ + rj := &radixv1.RadixJob{ ObjectMeta: metav1.ObjectMeta{ Name: jobName, Namespace: utils.GetAppNamespace(appName), }, - Spec: v1.RadixJobSpec{ - Build: v1.RadixBuildSpec{ + Spec: radixv1.RadixJobSpec{ + Build: radixv1.RadixBuildSpec{ Branch: branch, CommitID: commitId, }, PipeLineType: pipeline, TriggeredBy: triggeredBy, }, - Status: v1.RadixJobStatus{ + Status: radixv1.RadixJobStatus{ Started: &started, Ended: &ended, - Steps: []v1.RadixJobStep{ + Steps: []radixv1.RadixJobStep{ {Name: step1Name, PodName: step1Pod, Condition: step1Condition, Started: &step1Started, Ended: &step1Ended, Components: step1Components}, {Name: step2Name}, }, @@ -207,7 +207,7 @@ func (s *JobHandlerTestSuite) Test_GetApplicationJob_Created() { dh := deployMock.NewMockDeployHandler(ctrl) dh.EXPECT().GetDeploymentsForPipelineJob(context.Background(), gomock.Any(), gomock.Any()).Return(nil, nil).Times(1) h := Init(s.accounts, dh) - rj := v1.RadixJob{ObjectMeta: metav1.ObjectMeta{Name: scenario.jobName, Namespace: utils.GetAppNamespace(appName), CreationTimestamp: scenario.creationTimestamp}} + rj := radixv1.RadixJob{ObjectMeta: metav1.ObjectMeta{Name: scenario.jobName, Namespace: utils.GetAppNamespace(appName), CreationTimestamp: scenario.creationTimestamp}} if scenario.jobStatusCreated != emptyTime { rj.Status.Created = &scenario.jobStatusCreated } @@ -223,10 +223,10 @@ func (s *JobHandlerTestSuite) Test_GetApplicationJob_Created() { func (s *JobHandlerTestSuite) Test_GetApplicationJob_Status() { appName := "any_app" scenarios := []jobStatusScenario{ - {scenarioName: "status is set to condition when stop is false", jobName: "job1", condition: v1.JobFailed, stop: false, expectedStatus: jobModels.Failed.String()}, - {scenarioName: "status is Stopping when stop is true and condition is not Stopped", jobName: "job2", condition: v1.JobRunning, stop: true, expectedStatus: jobModels.Stopping.String()}, - {scenarioName: "status is Stopped when stop is true and condition is Stopped", jobName: "job3", condition: v1.JobStopped, stop: true, expectedStatus: jobModels.Stopped.String()}, - {scenarioName: "status is JobStoppedNoChanges when there is no changes", jobName: "job4", condition: v1.JobStoppedNoChanges, stop: false, expectedStatus: jobModels.StoppedNoChanges.String()}, + {scenarioName: "status is set to condition when stop is false", jobName: "job1", condition: radixv1.JobFailed, stop: false, expectedStatus: jobModels.Failed.String()}, + {scenarioName: "status is Stopping when stop is true and condition is not Stopped", jobName: "job2", condition: radixv1.JobRunning, stop: true, expectedStatus: jobModels.Stopping.String()}, + {scenarioName: "status is Stopped when stop is true and condition is Stopped", jobName: "job3", condition: radixv1.JobStopped, stop: true, expectedStatus: jobModels.Stopped.String()}, + {scenarioName: "status is JobStoppedNoChanges when there is no changes", jobName: "job4", condition: radixv1.JobStoppedNoChanges, stop: false, expectedStatus: jobModels.StoppedNoChanges.String()}, {scenarioName: "status is Waiting when condition is empty", jobName: "job5", expectedStatus: jobModels.Waiting.String()}, } @@ -238,10 +238,10 @@ func (s *JobHandlerTestSuite) Test_GetApplicationJob_Status() { dh := deployMock.NewMockDeployHandler(ctrl) dh.EXPECT().GetDeploymentsForPipelineJob(context.Background(), gomock.Any(), gomock.Any()).Return(nil, nil).Times(1) h := Init(s.accounts, dh) - rj := v1.RadixJob{ + rj := radixv1.RadixJob{ ObjectMeta: metav1.ObjectMeta{Name: scenario.jobName, Namespace: utils.GetAppNamespace(appName)}, - Spec: v1.RadixJobSpec{Stop: scenario.stop}, - Status: v1.RadixJobStatus{Condition: scenario.condition}, + Spec: radixv1.RadixJobSpec{Stop: scenario.stop}, + Status: radixv1.RadixJobStatus{Condition: scenario.condition}, } _, err := s.outRadixClient.RadixV1().RadixJobs(rj.Namespace).Create(context.Background(), &rj, metav1.CreateOptions{}) @@ -257,13 +257,13 @@ func (s *JobHandlerTestSuite) TestJobHandler_RerunJob() { appName := "anyApp" namespace := utils.GetAppNamespace(appName) tests := []jobRerunScenario{ - {scenarioName: "existing failed job", existingJob: &jobProperties{name: "job1", condition: v1.JobFailed}, jobNameToRerun: "job1", expectedError: nil}, - {scenarioName: "existing stopped job", existingJob: &jobProperties{name: "job1", condition: v1.JobStopped, stop: true}, jobNameToRerun: "job1", expectedError: nil}, - {scenarioName: "existing running job", existingJob: &jobProperties{name: "job1", condition: v1.JobRunning}, jobNameToRerun: "job1", expectedError: jobModels.JobHasInvalidConditionToRerunError(appName, "job1", v1.JobRunning)}, - {scenarioName: "existing stopped-no-changes job", existingJob: &jobProperties{name: "job1", condition: v1.JobStoppedNoChanges}, jobNameToRerun: "job1", expectedError: jobModels.JobHasInvalidConditionToRerunError(appName, "job1", v1.JobStoppedNoChanges)}, - {scenarioName: "existing queued job", existingJob: &jobProperties{name: "job1", condition: v1.JobQueued}, jobNameToRerun: "job1", expectedError: jobModels.JobHasInvalidConditionToRerunError(appName, "job1", v1.JobQueued)}, - {scenarioName: "existing succeeded job", existingJob: &jobProperties{name: "job1", condition: v1.JobSucceeded}, jobNameToRerun: "job1", expectedError: jobModels.JobHasInvalidConditionToRerunError(appName, "job1", v1.JobSucceeded)}, - {scenarioName: "existing waiting job", existingJob: &jobProperties{name: "job1", condition: v1.JobWaiting}, jobNameToRerun: "job1", expectedError: jobModels.JobHasInvalidConditionToRerunError(appName, "job1", v1.JobWaiting)}, + {scenarioName: "existing failed job", existingJob: &jobProperties{name: "job1", condition: radixv1.JobFailed}, jobNameToRerun: "job1", expectedError: nil}, + {scenarioName: "existing stopped job", existingJob: &jobProperties{name: "job1", condition: radixv1.JobStopped, stop: true}, jobNameToRerun: "job1", expectedError: nil}, + {scenarioName: "existing running job", existingJob: &jobProperties{name: "job1", condition: radixv1.JobRunning}, jobNameToRerun: "job1", expectedError: jobModels.JobHasInvalidConditionToRerunError(appName, "job1", radixv1.JobRunning)}, + {scenarioName: "existing stopped-no-changes job", existingJob: &jobProperties{name: "job1", condition: radixv1.JobStoppedNoChanges}, jobNameToRerun: "job1", expectedError: jobModels.JobHasInvalidConditionToRerunError(appName, "job1", radixv1.JobStoppedNoChanges)}, + {scenarioName: "existing queued job", existingJob: &jobProperties{name: "job1", condition: radixv1.JobQueued}, jobNameToRerun: "job1", expectedError: jobModels.JobHasInvalidConditionToRerunError(appName, "job1", radixv1.JobQueued)}, + {scenarioName: "existing succeeded job", existingJob: &jobProperties{name: "job1", condition: radixv1.JobSucceeded}, jobNameToRerun: "job1", expectedError: jobModels.JobHasInvalidConditionToRerunError(appName, "job1", radixv1.JobSucceeded)}, + {scenarioName: "existing waiting job", existingJob: &jobProperties{name: "job1", condition: radixv1.JobWaiting}, jobNameToRerun: "job1", expectedError: jobModels.JobHasInvalidConditionToRerunError(appName, "job1", radixv1.JobWaiting)}, {scenarioName: "not existing job", existingJob: nil, jobNameToRerun: "job1", expectedError: jobModels.PipelineNotFoundError(appName, "job1")}, } for _, tt := range tests { @@ -274,10 +274,10 @@ func (s *JobHandlerTestSuite) TestJobHandler_RerunJob() { dh := deployMock.NewMockDeployHandler(ctrl) jh := s.getJobHandler(dh) if tt.existingJob != nil { - _, err := s.inRadixClient.RadixV1().RadixJobs(namespace).Create(context.Background(), &v1.RadixJob{ + _, err := s.accounts.UserAccount.RadixClient.RadixV1().RadixJobs(namespace).Create(context.Background(), &radixv1.RadixJob{ ObjectMeta: metav1.ObjectMeta{Namespace: namespace, Name: tt.existingJob.name}, - Spec: v1.RadixJobSpec{Stop: tt.existingJob.stop}, - Status: v1.RadixJobStatus{Condition: tt.existingJob.condition}, + Spec: radixv1.RadixJobSpec{Stop: tt.existingJob.stop}, + Status: radixv1.RadixJobStatus{Condition: tt.existingJob.condition}, }, metav1.CreateOptions{}) s.NoError(err) } @@ -292,14 +292,14 @@ func (s *JobHandlerTestSuite) TestJobHandler_StopJob() { appName := "anyApp" namespace := utils.GetAppNamespace(appName) tests := []jobRerunScenario{ - {scenarioName: "existing failed job", existingJob: &jobProperties{name: "job1", condition: v1.JobFailed}, jobNameToRerun: "job1", expectedError: jobModels.JobHasInvalidConditionToRerunError(appName, "job1", v1.JobFailed)}, - {scenarioName: "existing stopped job", existingJob: &jobProperties{name: "job1", condition: v1.JobStopped, stop: true}, jobNameToRerun: "job1", expectedError: jobModels.JobHasInvalidConditionToStopError(appName, "job1", v1.JobStopped)}, - {scenarioName: "existing running job with stop in spec", existingJob: &jobProperties{name: "job1", condition: v1.JobRunning, stop: true}, jobNameToRerun: "job1", expectedError: jobModels.JobAlreadyRequestedToStopError(appName, "job1")}, - {scenarioName: "existing running job", existingJob: &jobProperties{name: "job1", condition: v1.JobRunning}, jobNameToRerun: "job1", expectedError: nil}, - {scenarioName: "existing stopped-no-changes job", existingJob: &jobProperties{name: "job1", condition: v1.JobStoppedNoChanges}, jobNameToRerun: "job1", expectedError: jobModels.JobHasInvalidConditionToRerunError(appName, "job1", v1.JobStoppedNoChanges)}, - {scenarioName: "existing queued job", existingJob: &jobProperties{name: "job1", condition: v1.JobQueued}, jobNameToRerun: "job1", expectedError: nil}, - {scenarioName: "existing succeeded job", existingJob: &jobProperties{name: "job1", condition: v1.JobSucceeded}, jobNameToRerun: "job1", expectedError: nil}, - {scenarioName: "existing waiting job", existingJob: &jobProperties{name: "job1", condition: v1.JobWaiting}, jobNameToRerun: "job1", expectedError: nil}, + {scenarioName: "existing failed job", existingJob: &jobProperties{name: "job1", condition: radixv1.JobFailed}, jobNameToRerun: "job1", expectedError: jobModels.JobHasInvalidConditionToStopError(appName, "job1", radixv1.JobFailed)}, + {scenarioName: "existing stopped job", existingJob: &jobProperties{name: "job1", condition: radixv1.JobStopped, stop: true}, jobNameToRerun: "job1", expectedError: jobModels.JobAlreadyRequestedToStopError(appName, "job1")}, + {scenarioName: "existing running job with stop in spec", existingJob: &jobProperties{name: "job1", condition: radixv1.JobRunning, stop: true}, jobNameToRerun: "job1", expectedError: jobModels.JobAlreadyRequestedToStopError(appName, "job1")}, + {scenarioName: "existing running job", existingJob: &jobProperties{name: "job1", condition: radixv1.JobRunning}, jobNameToRerun: "job1", expectedError: nil}, + {scenarioName: "existing stopped-no-changes job", existingJob: &jobProperties{name: "job1", condition: radixv1.JobStoppedNoChanges}, jobNameToRerun: "job1", expectedError: jobModels.JobHasInvalidConditionToStopError(appName, "job1", radixv1.JobStoppedNoChanges)}, + {scenarioName: "existing queued job", existingJob: &jobProperties{name: "job1", condition: radixv1.JobQueued}, jobNameToRerun: "job1", expectedError: nil}, + {scenarioName: "existing succeeded job", existingJob: &jobProperties{name: "job1", condition: radixv1.JobSucceeded}, jobNameToRerun: "job1", expectedError: nil}, + {scenarioName: "existing waiting job", existingJob: &jobProperties{name: "job1", condition: radixv1.JobWaiting}, jobNameToRerun: "job1", expectedError: nil}, {scenarioName: "not existing job", existingJob: nil, jobNameToRerun: "job1", expectedError: jobModels.PipelineNotFoundError(appName, "job1")}, } for _, tt := range tests { @@ -310,10 +310,10 @@ func (s *JobHandlerTestSuite) TestJobHandler_StopJob() { dh := deployMock.NewMockDeployHandler(ctrl) jh := s.getJobHandler(dh) if tt.existingJob != nil { - _, err := s.inRadixClient.RadixV1().RadixJobs(namespace).Create(context.Background(), &v1.RadixJob{ + _, err := s.accounts.UserAccount.RadixClient.RadixV1().RadixJobs(namespace).Create(context.Background(), &radixv1.RadixJob{ ObjectMeta: metav1.ObjectMeta{Namespace: namespace, Name: tt.existingJob.name}, - Spec: v1.RadixJobSpec{Stop: tt.existingJob.stop}, - Status: v1.RadixJobStatus{Condition: tt.existingJob.condition}, + Spec: radixv1.RadixJobSpec{Stop: tt.existingJob.stop}, + Status: radixv1.RadixJobStatus{Condition: tt.existingJob.condition}, }, metav1.CreateOptions{}) s.NoError(err) } diff --git a/api/jobs/manage_job_handler.go b/api/jobs/manage_job_handler.go index daf01113..cb188d28 100644 --- a/api/jobs/manage_job_handler.go +++ b/api/jobs/manage_job_handler.go @@ -7,28 +7,28 @@ import ( jobModels "github.com/equinor/radix-api/api/jobs/models" "github.com/equinor/radix-api/api/kubequery" "github.com/equinor/radix-common/utils/slice" - v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" + radixv1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" log "github.com/sirupsen/logrus" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) var ( - jobConditionsInValidForJobStop = []v1.RadixJobCondition{v1.JobFailed, v1.JobStopped, v1.JobStoppedNoChanges} - jobConditionsValidForJobRerun = []v1.RadixJobCondition{v1.JobFailed, v1.JobStopped} + jobConditionsNotValidForJobStop = []radixv1.RadixJobCondition{radixv1.JobFailed, radixv1.JobStopped, radixv1.JobStoppedNoChanges} + jobConditionsValidForJobRerun = []radixv1.RadixJobCondition{radixv1.JobFailed, radixv1.JobStopped} ) // StopJob Stops an application job func (jh JobHandler) StopJob(ctx context.Context, appName, jobName string) error { log.Infof("Stopping the job: %s, %s", jobName, appName) - radixJob, err := jh.getPipelineJob(ctx, appName, jobName) + radixJob, err := jh.getPipelineJobByName(ctx, appName, jobName) if err != nil { return err } if radixJob.Spec.Stop { return jobModels.JobAlreadyRequestedToStopError(appName, jobName) } - if slice.Any(jobConditionsInValidForJobStop, func(condition v1.RadixJobCondition) bool { return condition == radixJob.Status.Condition }) { + if slice.Any(jobConditionsNotValidForJobStop, func(condition radixv1.RadixJobCondition) bool { return condition == radixJob.Status.Condition }) { return jobModels.JobHasInvalidConditionToStopError(appName, jobName, radixJob.Status.Condition) } @@ -44,15 +44,15 @@ func (jh JobHandler) StopJob(ctx context.Context, appName, jobName string) error // RerunJob Reruns the pipeline job as a copy func (jh JobHandler) RerunJob(ctx context.Context, appName, jobName string) error { log.Infof("Rerunning the job %s in the application %s", jobName, appName) - radixJob, err := jh.getPipelineJob(ctx, appName, jobName) + radixJob, err := jh.getPipelineJobByName(ctx, appName, jobName) if err != nil { return err } - if !slice.Any(jobConditionsValidForJobRerun, func(condition v1.RadixJobCondition) bool { return condition == radixJob.Status.Condition }) { + if !slice.Any(jobConditionsValidForJobRerun, func(condition radixv1.RadixJobCondition) bool { return condition == radixJob.Status.Condition }) { return jobModels.JobHasInvalidConditionToRerunError(appName, jobName, radixJob.Status.Condition) } - copiedRadixJob := jh.buildPipelineJobRerunFrom(radixJob) + copiedRadixJob := jh.buildPipelineJobToRerunFrom(radixJob) _, err = jh.createPipelineJob(ctx, appName, copiedRadixJob) if err != nil { return fmt.Errorf("failed to create a job %s to rerun: %v", radixJob.GetName(), err) @@ -62,36 +62,36 @@ func (jh JobHandler) RerunJob(ctx context.Context, appName, jobName string) erro return nil } -func (jh JobHandler) buildPipelineJobRerunFrom(srcRadixJob *v1.RadixJob) *v1.RadixJob { - destJobName, imageTag := getUniqueJobName(workerImage) - destRadixJob := v1.RadixJob{ +func (jh JobHandler) buildPipelineJobToRerunFrom(radixJob *radixv1.RadixJob) *radixv1.RadixJob { + rerunJobName, imageTag := getUniqueJobName(workerImage) + rerunRadixJob := radixv1.RadixJob{ ObjectMeta: metav1.ObjectMeta{ - Name: destJobName, - Labels: srcRadixJob.Labels, - Annotations: srcRadixJob.Annotations, + Name: rerunJobName, + Labels: radixJob.Labels, + Annotations: radixJob.Annotations, }, - Spec: srcRadixJob.Spec, + Spec: radixJob.Spec, } - if destRadixJob.ObjectMeta.Annotations == nil { - destRadixJob.ObjectMeta.Annotations = make(map[string]string) + if rerunRadixJob.ObjectMeta.Annotations == nil { + rerunRadixJob.ObjectMeta.Annotations = make(map[string]string) } - destRadixJob.ObjectMeta.Annotations[jobModels.RadixPipelineJobRerunAnnotation] = srcRadixJob.GetName() - if len(destRadixJob.Spec.Build.ImageTag) > 0 { - destRadixJob.Spec.Build.ImageTag = imageTag + rerunRadixJob.ObjectMeta.Annotations[jobModels.RadixPipelineJobRerunAnnotation] = radixJob.GetName() + if len(rerunRadixJob.Spec.Build.ImageTag) > 0 { + rerunRadixJob.Spec.Build.ImageTag = imageTag } - destRadixJob.Spec.Stop = false + rerunRadixJob.Spec.Stop = false triggeredBy, err := jh.getTriggeredBy("") if err != nil { log.Warnf("failed to get triggeredBy: %v", err) } - destRadixJob.Spec.TriggeredBy = triggeredBy - return &destRadixJob + rerunRadixJob.Spec.TriggeredBy = triggeredBy + return &rerunRadixJob } -func (jh JobHandler) getPipelineJob(ctx context.Context, appName string, jobName string) (*v1.RadixJob, error) { - job, err := kubequery.GetRadixJob(ctx, jh.serviceAccount.RadixClient, appName, jobName) +func (jh JobHandler) getPipelineJobByName(ctx context.Context, appName string, jobName string) (*radixv1.RadixJob, error) { + radixJob, err := kubequery.GetRadixJob(ctx, jh.userAccount.RadixClient, appName, jobName) if err == nil { - return job, nil + return radixJob, nil } if errors.IsNotFound(err) { return nil, jobModels.PipelineNotFoundError(appName, jobName) diff --git a/api/jobs/models/job_errors.go b/api/jobs/models/job_errors.go index 7c00c972..1a014d18 100644 --- a/api/jobs/models/job_errors.go +++ b/api/jobs/models/job_errors.go @@ -4,7 +4,7 @@ import ( "fmt" radixhttp "github.com/equinor/radix-common/net/http" - v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" + radixv1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" ) // PipelineNotFoundError Pipeline job not found @@ -18,16 +18,16 @@ func PipelineStepNotFoundError(appName, jobName, stepName string) error { } // JobHasInvalidConditionToRerunError Pipeline job cannot be rerun due to invalid condition -func JobHasInvalidConditionToRerunError(appName, jobName string, jobCondition v1.RadixJobCondition) error { +func JobHasInvalidConditionToRerunError(appName, jobName string, jobCondition radixv1.RadixJobCondition) error { return radixhttp.ValidationError("Radix Application Pipeline", fmt.Sprintf("only Failed or Stopped pipeline jobs can be rerun, the job %s for the app %s has status %s", appName, jobName, jobCondition)) } // JobAlreadyRequestedToStopError Pipeline job was already requested to stop func JobAlreadyRequestedToStopError(appName, jobName string) error { - return radixhttp.ValidationError("Radix Application Pipeline", fmt.Sprintf("job %s for the app %s is already requested to stop", appName, jobName)) + return radixhttp.ValidationError("Radix Application Pipeline", fmt.Sprintf("job %s for the app %s has being already requested to be stopped", appName, jobName)) } // JobHasInvalidConditionToStopError Pipeline job cannot be stopped due to invalid condition -func JobHasInvalidConditionToStopError(appName, jobName string, jobCondition v1.RadixJobCondition) error { +func JobHasInvalidConditionToStopError(appName, jobName string, jobCondition radixv1.RadixJobCondition) error { return radixhttp.ValidationError("Radix Application Pipeline", fmt.Sprintf("only not Failed or Stopped pipeline jobs can be stopped, the job %s for the app %s has status %s", appName, jobName, jobCondition)) } From 84a2b647b90e0300d80702c2a982a0f68bfac0d1 Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Tue, 17 Oct 2023 13:31:28 +0200 Subject: [PATCH 05/12] Update api/jobs/models/job_errors.go Co-authored-by: Fredrik Hatletvedt <32248439+Pespiri@users.noreply.github.com> --- api/jobs/models/job_errors.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/jobs/models/job_errors.go b/api/jobs/models/job_errors.go index 1a014d18..18a6f121 100644 --- a/api/jobs/models/job_errors.go +++ b/api/jobs/models/job_errors.go @@ -29,5 +29,5 @@ func JobAlreadyRequestedToStopError(appName, jobName string) error { // JobHasInvalidConditionToStopError Pipeline job cannot be stopped due to invalid condition func JobHasInvalidConditionToStopError(appName, jobName string, jobCondition radixv1.RadixJobCondition) error { - return radixhttp.ValidationError("Radix Application Pipeline", fmt.Sprintf("only not Failed or Stopped pipeline jobs can be stopped, the job %s for the app %s has status %s", appName, jobName, jobCondition)) + return radixhttp.ValidationError("Radix Application Pipeline", fmt.Sprintf("only pipeline jobs that doesn't have the status Failed or Stopped can be stopped, but the job %s for the app %s has status %s", appName, jobName, jobCondition)) } From 4773b5a7f8ae940695d781b2b3b18db4f7d6ddfe Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Tue, 17 Oct 2023 13:31:50 +0200 Subject: [PATCH 06/12] Update api/jobs/models/job_errors.go Co-authored-by: Fredrik Hatletvedt <32248439+Pespiri@users.noreply.github.com> --- api/jobs/models/job_errors.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/jobs/models/job_errors.go b/api/jobs/models/job_errors.go index 18a6f121..e29915d7 100644 --- a/api/jobs/models/job_errors.go +++ b/api/jobs/models/job_errors.go @@ -24,7 +24,7 @@ func JobHasInvalidConditionToRerunError(appName, jobName string, jobCondition ra // JobAlreadyRequestedToStopError Pipeline job was already requested to stop func JobAlreadyRequestedToStopError(appName, jobName string) error { - return radixhttp.ValidationError("Radix Application Pipeline", fmt.Sprintf("job %s for the app %s has being already requested to be stopped", appName, jobName)) + return radixhttp.ValidationError("Radix Application Pipeline", fmt.Sprintf("job %s for the app %s has already been requested to be stopped", appName, jobName)) } // JobHasInvalidConditionToStopError Pipeline job cannot be stopped due to invalid condition From 943e5b5b539c8efa8c4886cb28be4135bdfcc747 Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Tue, 17 Oct 2023 13:32:08 +0200 Subject: [PATCH 07/12] Update api/jobs/job_controller.go Co-authored-by: Fredrik Hatletvedt <32248439+Pespiri@users.noreply.github.com> --- api/jobs/job_controller.go | 1 - 1 file changed, 1 deletion(-) diff --git a/api/jobs/job_controller.go b/api/jobs/job_controller.go index 8ce05eb0..d285beae 100644 --- a/api/jobs/job_controller.go +++ b/api/jobs/job_controller.go @@ -223,7 +223,6 @@ func StopApplicationJob(accounts models.Accounts, w http.ResponseWriter, r *http appName := mux.Vars(r)["appName"] jobName := mux.Vars(r)["jobName"] - log.Infof("Stop the pipeline job %s in the application %s", jobName, appName) handler := Init(accounts, deployments.Init(accounts)) err := handler.StopJob(r.Context(), appName, jobName) From 07395659f1c6ef6d7cb235206bf68ee99117e2f4 Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Tue, 17 Oct 2023 13:32:16 +0200 Subject: [PATCH 08/12] Update api/jobs/job_controller.go Co-authored-by: Fredrik Hatletvedt <32248439+Pespiri@users.noreply.github.com> --- api/jobs/job_controller.go | 1 - 1 file changed, 1 deletion(-) diff --git a/api/jobs/job_controller.go b/api/jobs/job_controller.go index d285beae..3c6edd65 100644 --- a/api/jobs/job_controller.go +++ b/api/jobs/job_controller.go @@ -10,7 +10,6 @@ import ( "github.com/equinor/radix-api/models" radixhttp "github.com/equinor/radix-common/net/http" "github.com/gorilla/mux" - log "github.com/sirupsen/logrus" ) const rootPath = "/applications/{appName}" From c7cf98c312eb0398e54220b142a11df68def962c Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Tue, 17 Oct 2023 13:32:23 +0200 Subject: [PATCH 09/12] Update api/jobs/job_controller.go Co-authored-by: Fredrik Hatletvedt <32248439+Pespiri@users.noreply.github.com> --- api/jobs/job_controller.go | 1 - 1 file changed, 1 deletion(-) diff --git a/api/jobs/job_controller.go b/api/jobs/job_controller.go index 3c6edd65..64a6d8b8 100644 --- a/api/jobs/job_controller.go +++ b/api/jobs/job_controller.go @@ -270,7 +270,6 @@ func RerunApplicationJob(accounts models.Accounts, w http.ResponseWriter, r *htt // description: "Not found" appName := mux.Vars(r)["appName"] jobName := mux.Vars(r)["jobName"] - log.Infof("Rerun the pipeline job %s in the application %s", jobName, appName) handler := Init(accounts, deployments.Init(accounts)) err := handler.RerunJob(r.Context(), appName, jobName) From 0ba90f0c1ee4b6d90ac9d97e63ddb7bfbf0a0279 Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Tue, 17 Oct 2023 13:32:45 +0200 Subject: [PATCH 10/12] Update api/jobs/models/job_errors.go Co-authored-by: Fredrik Hatletvedt <32248439+Pespiri@users.noreply.github.com> --- api/jobs/models/job_errors.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/jobs/models/job_errors.go b/api/jobs/models/job_errors.go index e29915d7..b30760fa 100644 --- a/api/jobs/models/job_errors.go +++ b/api/jobs/models/job_errors.go @@ -19,7 +19,7 @@ func PipelineStepNotFoundError(appName, jobName, stepName string) error { // JobHasInvalidConditionToRerunError Pipeline job cannot be rerun due to invalid condition func JobHasInvalidConditionToRerunError(appName, jobName string, jobCondition radixv1.RadixJobCondition) error { - return radixhttp.ValidationError("Radix Application Pipeline", fmt.Sprintf("only Failed or Stopped pipeline jobs can be rerun, the job %s for the app %s has status %s", appName, jobName, jobCondition)) + return radixhttp.ValidationError("Radix Application Pipeline", fmt.Sprintf("only pipeline jobs that have the status Failed or Stopped can be rerun, but the job %s for the app %s has status %s", appName, jobName, jobCondition)) } // JobAlreadyRequestedToStopError Pipeline job was already requested to stop From ae79ba0c47e336be239cdaf88fe678f6845e7e10 Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Tue, 17 Oct 2023 13:33:12 +0200 Subject: [PATCH 11/12] Update api/jobs/manage_job_handler.go Co-authored-by: Fredrik Hatletvedt <32248439+Pespiri@users.noreply.github.com> --- api/jobs/manage_job_handler.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/api/jobs/manage_job_handler.go b/api/jobs/manage_job_handler.go index cb188d28..ebc8be4d 100644 --- a/api/jobs/manage_job_handler.go +++ b/api/jobs/manage_job_handler.go @@ -90,11 +90,11 @@ func (jh JobHandler) buildPipelineJobToRerunFrom(radixJob *radixv1.RadixJob) *ra func (jh JobHandler) getPipelineJobByName(ctx context.Context, appName string, jobName string) (*radixv1.RadixJob, error) { radixJob, err := kubequery.GetRadixJob(ctx, jh.userAccount.RadixClient, appName, jobName) - if err == nil { - return radixJob, nil - } - if errors.IsNotFound(err) { - return nil, jobModels.PipelineNotFoundError(appName, jobName) + if err != nil { + if errors.IsNotFound(err) { + err = jobModels.PipelineNotFoundError(appName, jobName) + } + return nil, err } - return nil, err + return radixJob, nil } From 3d136b0c97dfbab5fba79d3ed012f138497cb569 Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Tue, 17 Oct 2023 13:33:23 +0200 Subject: [PATCH 12/12] Update api/jobs/manage_job_handler.go Co-authored-by: Fredrik Hatletvedt <32248439+Pespiri@users.noreply.github.com> --- api/jobs/manage_job_handler.go | 1 - 1 file changed, 1 deletion(-) diff --git a/api/jobs/manage_job_handler.go b/api/jobs/manage_job_handler.go index ebc8be4d..4aa2be58 100644 --- a/api/jobs/manage_job_handler.go +++ b/api/jobs/manage_job_handler.go @@ -58,7 +58,6 @@ func (jh JobHandler) RerunJob(ctx context.Context, appName, jobName string) erro return fmt.Errorf("failed to create a job %s to rerun: %v", radixJob.GetName(), err) } - log.Infof("reran the job %s as a new job %s in the application %s", radixJob.GetName(), copiedRadixJob.GetName(), appName) return nil }