From 4d05b2b30b3740f62469f270e52530131fa5a8ce Mon Sep 17 00:00:00 2001 From: AbdulRahman AlHamali Date: Thu, 25 Mar 2021 16:09:30 -0400 Subject: [PATCH] working --- .../orca/pipeline/CompoundExecutionOperator.java | 6 +++--- .../spinnaker/orca/pipeline/ExecutionRunner.java | 3 ++- .../pipeline/persistence/ExecutionRepository.java | 2 +- .../events/IgnoreStageFailureInterlinkEvent.java | 9 +++++++-- .../netflix/spinnaker/orca/q/QueueExecutionRunner.kt | 4 ++-- .../orca/q/handler/IgnoreStageFailureHandler.kt | 9 +++++---- .../kotlin/com/netflix/spinnaker/orca/q/messages.kt | 11 ++++++----- .../orca/q/handler/IgnoreStageFailureHandlerTest.kt | 8 ++++---- .../pipeline/persistence/SqlExecutionRepository.kt | 4 ++-- .../spinnaker/orca/controllers/TaskController.groovy | 4 ++-- 10 files changed, 34 insertions(+), 26 deletions(-) diff --git a/orca-core/src/main/java/com/netflix/spinnaker/orca/pipeline/CompoundExecutionOperator.java b/orca-core/src/main/java/com/netflix/spinnaker/orca/pipeline/CompoundExecutionOperator.java index 3f7ad2817f..a3f2a53836 100644 --- a/orca-core/src/main/java/com/netflix/spinnaker/orca/pipeline/CompoundExecutionOperator.java +++ b/orca-core/src/main/java/com/netflix/spinnaker/orca/pipeline/CompoundExecutionOperator.java @@ -120,15 +120,15 @@ public PipelineExecution restartStage(@Nonnull String executionId, @Nonnull Stri } public PipelineExecution ignoreStageFailure( - @Nonnull String executionId, @Nonnull String stageId) { + @Nonnull String executionId, @Nonnull String stageId, String reason) { PipelineExecution execution = repository.retrieve(ExecutionType.PIPELINE, executionId); if (repository.handlesPartition(execution.getPartition())) { - runner.ignoreFailure(execution, stageId); + runner.ignoreFailure(execution, stageId, reason); } else { log.info( "Not pushing queue message action='ignoreFailure' for execution with foreign partition='{}'", execution.getPartition()); - repository.ignoreStageFailure(executionId, stageId); + repository.ignoreStageFailure(executionId, stageId, reason); } return execution; } diff --git a/orca-core/src/main/java/com/netflix/spinnaker/orca/pipeline/ExecutionRunner.java b/orca-core/src/main/java/com/netflix/spinnaker/orca/pipeline/ExecutionRunner.java index 9fbcedd82d..55be5178c0 100644 --- a/orca-core/src/main/java/com/netflix/spinnaker/orca/pipeline/ExecutionRunner.java +++ b/orca-core/src/main/java/com/netflix/spinnaker/orca/pipeline/ExecutionRunner.java @@ -27,7 +27,8 @@ default void restart(@Nonnull PipelineExecution execution, @Nonnull String stage throw new UnsupportedOperationException(); } - default void ignoreFailure(@Nonnull PipelineExecution execution, @Nonnull String stageId) { + default void ignoreFailure( + @Nonnull PipelineExecution execution, @Nonnull String stageId, String reason) { throw new UnsupportedOperationException(); } diff --git a/orca-core/src/main/java/com/netflix/spinnaker/orca/pipeline/persistence/ExecutionRepository.java b/orca-core/src/main/java/com/netflix/spinnaker/orca/pipeline/persistence/ExecutionRepository.java index 976410d0be..12592de813 100644 --- a/orca-core/src/main/java/com/netflix/spinnaker/orca/pipeline/persistence/ExecutionRepository.java +++ b/orca-core/src/main/java/com/netflix/spinnaker/orca/pipeline/persistence/ExecutionRepository.java @@ -186,7 +186,7 @@ default boolean handlesPartition(@Nullable String partitionOfExecution) { // foreign executions default void restartStage(String executionId, String stageId) {} - default void ignoreStageFailure(String executionId, String stageId) {} + default void ignoreStageFailure(String executionId, String stageId, String reason) {} final class ExecutionCriteria { private int pageSize = 3500; diff --git a/orca-interlink/src/main/java/com/netflix/spinnaker/orca/interlink/events/IgnoreStageFailureInterlinkEvent.java b/orca-interlink/src/main/java/com/netflix/spinnaker/orca/interlink/events/IgnoreStageFailureInterlinkEvent.java index 117e96804a..b36bd5b365 100644 --- a/orca-interlink/src/main/java/com/netflix/spinnaker/orca/interlink/events/IgnoreStageFailureInterlinkEvent.java +++ b/orca-interlink/src/main/java/com/netflix/spinnaker/orca/interlink/events/IgnoreStageFailureInterlinkEvent.java @@ -43,19 +43,24 @@ public class IgnoreStageFailureInterlinkEvent implements InterlinkEvent { @Nonnull ExecutionType executionType; @Nonnull String executionId; @Nonnull String stageId; + String reason; public IgnoreStageFailureInterlinkEvent( - @Nonnull ExecutionType executionType, @Nonnull String executionId, @Nonnull String stageId) { + @Nonnull ExecutionType executionType, + @Nonnull String executionId, + @Nonnull String stageId, + String reason) { // for the moment, only ExecutionType.PIPELINE can have ignored stages // but since we are defining the protocol on the wire here, let's be a bit future proof and // accept potentially different execution types this.executionType = executionType; this.executionId = executionId; this.stageId = stageId; + this.reason = reason; } @Override public void applyTo(CompoundExecutionOperator executionOperator) { - executionOperator.ignoreStageFailure(executionId, stageId); + executionOperator.ignoreStageFailure(executionId, stageId, reason); } } diff --git a/orca-queue/src/main/kotlin/com/netflix/spinnaker/orca/q/QueueExecutionRunner.kt b/orca-queue/src/main/kotlin/com/netflix/spinnaker/orca/q/QueueExecutionRunner.kt index f451649e3f..e1a8e69a55 100644 --- a/orca-queue/src/main/kotlin/com/netflix/spinnaker/orca/q/QueueExecutionRunner.kt +++ b/orca-queue/src/main/kotlin/com/netflix/spinnaker/orca/q/QueueExecutionRunner.kt @@ -38,8 +38,8 @@ class QueueExecutionRunner( queue.push(RestartStage(execution, stageId, AuthenticatedRequest.getSpinnakerUser().orElse(null))) } - override fun ignoreFailure(execution: PipelineExecution, stageId: String) { - queue.push(IgnoreStageFailure(execution, stageId, AuthenticatedRequest.getSpinnakerUser().orElse(null))) + override fun ignoreFailure(execution: PipelineExecution, stageId: String, reason: String?) { + queue.push(IgnoreStageFailure(execution, stageId, AuthenticatedRequest.getSpinnakerUser().orElse(null), reason)) } override fun unpause(execution: PipelineExecution) { diff --git a/orca-queue/src/main/kotlin/com/netflix/spinnaker/orca/q/handler/IgnoreStageFailureHandler.kt b/orca-queue/src/main/kotlin/com/netflix/spinnaker/orca/q/handler/IgnoreStageFailureHandler.kt index 458a92a49c..867509ebf1 100644 --- a/orca-queue/src/main/kotlin/com/netflix/spinnaker/orca/q/handler/IgnoreStageFailureHandler.kt +++ b/orca-queue/src/main/kotlin/com/netflix/spinnaker/orca/q/handler/IgnoreStageFailureHandler.kt @@ -54,7 +54,7 @@ class IgnoreStageFailureHandler( } } else { stage.status = FAILED_CONTINUE - stage.addIgnoreFailureDetails(message.user) + stage.addIgnoreFailureDetails(message.user, message.reason) repository.storeStage(stage) val topLevelStage = stage.topLevelStage @@ -74,10 +74,11 @@ class IgnoreStageFailureHandler( } } - private fun StageExecution.addIgnoreFailureDetails(user: String?) { + private fun StageExecution.addIgnoreFailureDetails(user: String?, reason: String?) { context["ignoreFailureDetails"] = mapOf( - "failureIgnoredBy" to (user ?: "anonymous"), - "failureIgnoreTime" to clock.millis(), + "by" to (user ?: "anonymous"), + "reason" to (reason ?: "unspecified"), + "time" to clock.millis(), "previousException" to context.remove("exception") ) } diff --git a/orca-queue/src/main/kotlin/com/netflix/spinnaker/orca/q/messages.kt b/orca-queue/src/main/kotlin/com/netflix/spinnaker/orca/q/messages.kt index 96a1086018..ae71303fe6 100644 --- a/orca-queue/src/main/kotlin/com/netflix/spinnaker/orca/q/messages.kt +++ b/orca-queue/src/main/kotlin/com/netflix/spinnaker/orca/q/messages.kt @@ -256,13 +256,14 @@ data class IgnoreStageFailure( override val executionId: String, override val application: String, override val stageId: String, - val user: String? + val user: String?, + val reason: String? ) : Message(), StageLevel { - constructor(source: PipelineExecution, stageId: String, user: String?) : - this(source.type, source.id, source.application, stageId, user) + constructor(source: PipelineExecution, stageId: String, user: String?, reason: String?) : + this(source.type, source.id, source.application, stageId, user, reason) - constructor(stage: StageExecution, user: String?) : - this(stage.execution.type, stage.execution.id, stage.execution.application, stage.id, user) + constructor(stage: StageExecution, user: String?, reason: String?) : + this(stage.execution.type, stage.execution.id, stage.execution.application, stage.id, user, reason) } @JsonTypeName("resumeStage") diff --git a/orca-queue/src/test/kotlin/com/netflix/spinnaker/orca/q/handler/IgnoreStageFailureHandlerTest.kt b/orca-queue/src/test/kotlin/com/netflix/spinnaker/orca/q/handler/IgnoreStageFailureHandlerTest.kt index 26a00155a6..37108947ec 100644 --- a/orca-queue/src/test/kotlin/com/netflix/spinnaker/orca/q/handler/IgnoreStageFailureHandlerTest.kt +++ b/orca-queue/src/test/kotlin/com/netflix/spinnaker/orca/q/handler/IgnoreStageFailureHandlerTest.kt @@ -115,7 +115,7 @@ object IgnoreStageFailureHandlerTest : SubjectSpek({ status = NOT_STARTED } } - val message = IgnoreStageFailure(pipeline.type, pipeline.id, "foo", pipeline.stageByRef("1").id, "aalhamali@coveo.com") + val message = IgnoreStageFailure(pipeline.type, pipeline.id, "foo", pipeline.stageByRef("1").id, "aalhamali@coveo.com", null) beforeGroup { whenever(repository.retrieve(message.executionType, message.executionId)) doReturn pipeline @@ -152,7 +152,7 @@ object IgnoreStageFailureHandlerTest : SubjectSpek({ endTime = clock.instant().minus(59, MINUTES).toEpochMilli() } } - val message = IgnoreStageFailure(pipeline.type, pipeline.id, "foo", pipeline.stageByRef("1").id, "aalhamali@coveo.com") + val message = IgnoreStageFailure(pipeline.type, pipeline.id, "foo", pipeline.stageByRef("1").id, "aalhamali@coveo.com", null) beforeGroup { whenever(repository.retrieve(PIPELINE, message.executionId)) doReturn pipeline @@ -220,7 +220,7 @@ object IgnoreStageFailureHandlerTest : SubjectSpek({ status = NOT_STARTED } } - val message = IgnoreStageFailure(pipeline.type, pipeline.id, "foo", pipeline.stageByRef("1").id, "aalhamali@coveo.com") + val message = IgnoreStageFailure(pipeline.type, pipeline.id, "foo", pipeline.stageByRef("1").id, "aalhamali@coveo.com", null) beforeGroup { whenever(repository.retrieve(PIPELINE, message.executionId)) doReturn pipeline @@ -285,7 +285,7 @@ object IgnoreStageFailureHandlerTest : SubjectSpek({ startTime = clock.instant().minus(1, HOURS).toEpochMilli() } } - val message = IgnoreStageFailure(pipeline.type, pipeline.id, "foo", pipeline.stageByRef("1").id, "aalhamali@coveo.com") + val message = IgnoreStageFailure(pipeline.type, pipeline.id, "foo", pipeline.stageByRef("1").id, "aalhamali@coveo.com", null) beforeGroup { whenever(repository.retrieve(PIPELINE, message.executionId)) doReturn pipeline diff --git a/orca-sql/src/main/kotlin/com/netflix/spinnaker/orca/sql/pipeline/persistence/SqlExecutionRepository.kt b/orca-sql/src/main/kotlin/com/netflix/spinnaker/orca/sql/pipeline/persistence/SqlExecutionRepository.kt index ff3c1b703a..36ab1380b2 100644 --- a/orca-sql/src/main/kotlin/com/netflix/spinnaker/orca/sql/pipeline/persistence/SqlExecutionRepository.kt +++ b/orca-sql/src/main/kotlin/com/netflix/spinnaker/orca/sql/pipeline/persistence/SqlExecutionRepository.kt @@ -254,8 +254,8 @@ class SqlExecutionRepository( } } - override fun ignoreStageFailure(executionId: String, stageId: String) { - doForeignAware(IgnoreStageFailureInterlinkEvent(PIPELINE, executionId, stageId)) { + override fun ignoreStageFailure(executionId: String, stageId: String, reason: String?) { + doForeignAware(IgnoreStageFailureInterlinkEvent(PIPELINE, executionId, stageId, reason)) { _, _ -> log.debug("ignoreStageFailure is a no-op for local executions") } } diff --git a/orca-web/src/main/groovy/com/netflix/spinnaker/orca/controllers/TaskController.groovy b/orca-web/src/main/groovy/com/netflix/spinnaker/orca/controllers/TaskController.groovy index 7e67a044ea..0bd712e0fa 100644 --- a/orca-web/src/main/groovy/com/netflix/spinnaker/orca/controllers/TaskController.groovy +++ b/orca-web/src/main/groovy/com/netflix/spinnaker/orca/controllers/TaskController.groovy @@ -508,13 +508,13 @@ class TaskController { @PreAuthorize("hasPermission(this.getPipeline(#id)?.application, 'APPLICATION', 'EXECUTE')") @RequestMapping(value = "/pipelines/{id}/stages/{stageId}/ignoreFailure", method = RequestMethod.PUT) PipelineExecution ignoreFailureOfPipelineStage( - @PathVariable String id, @PathVariable String stageId) { + @PathVariable String id, @PathVariable String stageId, @RequestBody Map details) { def pipeline = executionRepository.retrieve(PIPELINE, id) def stage = pipeline.stageById(stageId) if (!(boolean) stage.context.getCurrentOnly("allowIgnoreFailure", false)) { throw new CannotUpdateExecutionStage("Stage does not allow ignoreFailure action") } - return executionOperator.ignoreStageFailure(id, stageId) + return executionOperator.ignoreStageFailure(id, stageId, details["reason"]) } @PreAuthorize("hasPermission(this.getPipeline(#id)?.application, 'APPLICATION', 'READ')")