Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(child pipeline executions): Add support for omit other stages fr… #4303

Closed
Closed
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package com.netflix.spinnaker.orca.front50.tasks

import com.fasterxml.jackson.databind.ObjectMapper
import com.netflix.spinnaker.kork.exceptions.ConfigurationException
import com.netflix.spinnaker.orca.api.pipeline.models.ExecutionStatus
import com.netflix.spinnaker.orca.api.pipeline.Task
Expand All @@ -25,6 +26,7 @@ import com.netflix.spinnaker.orca.api.pipeline.TaskResult
import com.netflix.spinnaker.orca.api.pipeline.ExecutionPreprocessor
import com.netflix.spinnaker.orca.front50.DependentPipelineStarter
import com.netflix.spinnaker.orca.front50.Front50Service
import com.netflix.spinnaker.orca.jackson.OrcaObjectMapper
import com.netflix.spinnaker.orca.pipeline.util.ContextParameterProcessor
import com.netflix.spinnaker.orca.pipelinetemplate.V2Util
import com.netflix.spinnaker.security.AuthenticatedRequest
Expand Down Expand Up @@ -64,6 +66,7 @@ class StartPipelineTask implements Task {
String application = stage.context.pipelineApplication ?: stage.context.application
Boolean isStrategy = stage.context.pipelineParameters?.strategy ?: false
String pipelineId = isStrategy ? stage.context.pipelineId : stage.context.pipeline
Boolean isIsolated = stage.context.isolatedStreamExecution?: false

List<Map<String, Object>> pipelines = isStrategy ? front50Service.getStrategies(application) : front50Service.getPipelines(application, false)
Map<String, Object> pipelineConfig = pipelines.find { it.id == pipelineId }
Expand Down Expand Up @@ -106,6 +109,24 @@ class StartPipelineTask implements Task {
}
}

if (isIsolated) {
ObjectMapper objectOrcaMapper = OrcaObjectMapper.getInstance()
PipelineExecution pipelineExecutionIsolated = objectOrcaMapper.readValue(objectOrcaMapper.writeValueAsString(stage.execution), PipelineExecution.class);
pipelineExecutionIsolated.getStages().clear()
pipelineExecutionIsolated.getStages().add(stage.getExecution().getStages().stream()
.filter({ s -> s.getId().equals(stage.getId()) }).findFirst().get())

def pipeline = dependentPipelineStarter.trigger(
pipelineConfig,
stage.context.user as String,
pipelineExecutionIsolated,
parameters,
stage.id,
getUser(stage.execution)
)
return TaskResult.builder(ExecutionStatus.SUCCEEDED).context([executionId: pipeline.id, executionName: pipelineConfig.name]).build()
}

def pipeline = dependentPipelineStarter.trigger(
pipelineConfig,
stage.context.user as String,
Expand All @@ -115,7 +136,7 @@ class StartPipelineTask implements Task {
getUser(stage.execution)
)

TaskResult.builder(ExecutionStatus.SUCCEEDED).context([executionId: pipeline.id, executionName: pipelineConfig.name]).build()
return TaskResult.builder(ExecutionStatus.SUCCEEDED).context([executionId: pipeline.id, executionName: pipelineConfig.name]).build()
}

// There are currently two sources-of-truth for the user:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ public class PipelineStage implements StageDefinitionBuilder, CancellableStage {
@Value("${stages.pipeline.defaultSkipDownstreamOutput:false}")
private boolean defaultSkipDownstreamOutput;

@Value("${stages.pipeline.defaultIsolatedStreamExecution:false}")
private boolean defaultIsolatedStreamExecution;

public static final String PIPELINE_CONFIG_TYPE =
StageDefinitionBuilder.getType(PipelineStage.class);

Expand All @@ -59,6 +62,7 @@ public PipelineStage(ExecutionRepository executionRepository) {
public void taskGraph(@Nonnull StageExecution stage, @Nonnull TaskNode.Builder builder) {
// only start the pipeline if no execution ID already exists
if (stage.getContext().get("executionId") == null) {
stage.getContext().putIfAbsent("isolatedStreamExecution", defaultIsolatedStreamExecution);
builder.withTask("startPipeline", StartPipelineTask.class);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@

package com.netflix.spinnaker.orca.front50.tasks


import com.netflix.spinnaker.orca.api.pipeline.ExecutionPreprocessor
import com.netflix.spinnaker.orca.front50.DependentPipelineStarter
import com.netflix.spinnaker.orca.front50.Front50Service
import com.netflix.spinnaker.orca.pipeline.model.StageExecutionImpl
import com.netflix.spinnaker.orca.pipeline.util.ContextParameterProcessor
import spock.lang.Specification
import spock.lang.Subject
Expand Down Expand Up @@ -111,4 +111,53 @@ class StartPipelineTaskSpec extends Specification {
) || "authenticated_user" || ["account1"]

}

@Unroll
def "should trigger the dependent pipeline with isolatedStreamExecution"() {
given:
def pipelineConfig = [id: "testStrategyId", application: "orca", name: "testStrategy", other: "other"]

1 * front50Service.getStrategies(_) >> [pipelineConfig]
def stage = stage {
type = "whatever"
name = "testing"
context = [
pipelineId : "testStrategyId",
pipelineParameters : [
strategy: true,
zone : "north-pole-1",
],
isolatedStreamExecution: isIsolatedStreamExecution
]
}

stage.getExecution().getStages().add(new StageExecutionImpl(stage.getExecution(), "stage2"))
stage.getExecution().getStages().add(new StageExecutionImpl(stage.getExecution(), "stage3"))
def parentPipelineStageId
def pipelineExecution

when:
def result = task.execute(stage)

then:
dependentPipelineStarter.trigger(*_) >> {
pipelineExecution = it[2]
parentPipelineStageId = it[4]

return pipeline {
id = "testPipelineId"
application = "orca"
}
}

parentPipelineStageId == stage.id
stagesNumber == pipelineExecution.getStages().size()

where:
isIsolatedStreamExecution || stagesNumber
false || 3
true || 1

}

}