Skip to content

Commit

Permalink
fix(pipeline_template): config level stage replacement
Browse files Browse the repository at this point in the history
  • Loading branch information
emjburns committed Sep 19, 2017
1 parent 7ce0f61 commit 9ea25de
Show file tree
Hide file tree
Showing 6 changed files with 303 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import com.netflix.spinnaker.orca.pipelinetemplate.v1schema.V1SchemaExecutionGenerator;
import com.netflix.spinnaker.orca.pipelinetemplate.v1schema.graph.GraphMutator;
import com.netflix.spinnaker.orca.pipelinetemplate.v1schema.model.PipelineTemplate;
import com.netflix.spinnaker.orca.pipelinetemplate.v1schema.model.StageDefinition;
import com.netflix.spinnaker.orca.pipelinetemplate.v1schema.model.TemplateConfiguration;
import com.netflix.spinnaker.orca.pipelinetemplate.v1schema.render.DefaultRenderContext;
import com.netflix.spinnaker.orca.pipelinetemplate.v1schema.render.RenderContext;
Expand All @@ -44,6 +45,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
* highlevel lifecycle
Expand Down Expand Up @@ -100,13 +102,20 @@ private Map<String, Object> processInternal(Map<String, Object> pipeline) {
Errors validationErrors = new Errors();

TemplateConfiguration templateConfiguration = request.getConfig();
new V1TemplateConfigurationSchemaValidator().validate(templateConfiguration, validationErrors);

PipelineTemplate template = getPipelineTemplate(request, templateConfiguration);

new V1TemplateConfigurationSchemaValidator().validate(
templateConfiguration,
validationErrors,
new V1TemplateConfigurationSchemaValidator.SchemaValidatorContext(
template.getStages().stream().map(StageDefinition::getId).collect(Collectors.toList())
)
);
if (validationErrors.hasErrors(request.plan)) {
return validationErrors.toResponse();
}

PipelineTemplate template = getPipelineTemplate(request, templateConfiguration);

new V1TemplateSchemaValidator().validate(template, validationErrors, new SchemaValidatorContext(!templateConfiguration.getStages().isEmpty()));
if (validationErrors.hasErrors(request.plan)) {
return validationErrors.toResponse();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,14 @@
import com.netflix.spinnaker.orca.pipelinetemplate.validator.ValidatorContext;
import com.netflix.spinnaker.orca.pipelinetemplate.validator.VersionedSchema;

public class V1TemplateConfigurationSchemaValidator implements SchemaValidator {
import java.util.List;

private static final String SUPPORTED_VERSION = "1";
public class V1TemplateConfigurationSchemaValidator<T extends V1TemplateConfigurationSchemaValidator.SchemaValidatorContext> implements SchemaValidator<T> {

public void validate(VersionedSchema configuration, Errors errors) {
validate(configuration, errors, new EmptyValidatorContext());
}
private static final String SUPPORTED_VERSION = "1";

@Override
public void validate(VersionedSchema configuration, Errors errors, ValidatorContext context) {
public void validate(VersionedSchema configuration, Errors errors, SchemaValidatorContext context) {
if (!(configuration instanceof TemplateConfiguration)) {
throw new IllegalArgumentException("Expected TemplateConfiguration");
}
Expand Down Expand Up @@ -63,7 +61,7 @@ public void validate(VersionedSchema configuration, Errors errors, ValidatorCont
V1SchemaValidationHelper.validateStageDefinitions(config.getStages(), errors, V1TemplateConfigurationSchemaValidator::location);

config.getStages().forEach(s -> {
if ((s.getDependsOn() == null || s.getDependsOn().isEmpty()) && (s.getInject() == null || !s.getInject().hasAny())) {
if (!context.stageIds.contains(s.getId()) && (s.getDependsOn() == null || s.getDependsOn().isEmpty()) && (s.getInject() == null || !s.getInject().hasAny())) {
errors.add(new Error()
.withMessage("A configuration-defined stage should have either dependsOn or an inject rule defined")
.withLocation(location(String.format("stages.%s", s.getId())))
Expand All @@ -77,4 +75,12 @@ public void validate(VersionedSchema configuration, Errors errors, ValidatorCont
private static String location(String location) {
return "configuration:" + location;
}

public static class SchemaValidatorContext implements ValidatorContext {
List<String> stageIds;

public SchemaValidatorContext(List<String> stageIds) {
this.stageIds = stageIds;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class V1TemplateConfigurationSchemaValidatorSpec extends Specification {
def templateConfiguration = new TemplateConfiguration(schema: schema)

when:
subject.validate(templateConfiguration, errors)
subject.validate(templateConfiguration, errors, new V1TemplateConfigurationSchemaValidator.SchemaValidatorContext([]))

then:
if (hasErrors) {
Expand All @@ -56,7 +56,7 @@ class V1TemplateConfigurationSchemaValidatorSpec extends Specification {
def templateConfiguration = new TemplateConfiguration(schema: "1", pipeline: new PipelineDefinition(application: application))

when:
subject.validate(templateConfiguration, errors)
subject.validate(templateConfiguration, errors, new V1TemplateConfigurationSchemaValidator.SchemaValidatorContext([]))

then:
if (hasErrors) {
Expand Down Expand Up @@ -89,7 +89,7 @@ class V1TemplateConfigurationSchemaValidatorSpec extends Specification {
)

when:
subject.validate(templateConfiguration, errors)
subject.validate(templateConfiguration, errors, new V1TemplateConfigurationSchemaValidator.SchemaValidatorContext(templateStageIds))

then:
if (hasErrors) {
Expand All @@ -100,9 +100,10 @@ class V1TemplateConfigurationSchemaValidatorSpec extends Specification {
}

where:
dependsOn | injectFirst | hasErrors
null | true | false
['bar'] | false | false
null | null | true
dependsOn | injectFirst | templateStageIds | hasErrors
null | true | [] | false
['bar'] | false | [] | false
null | null | [] | true
null | null | ["foo"] | false
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
schema: "1"
pipeline:
application: orca
name: MPT Stage Replacement Test
template:
source: stageReplacement-template.yml
variables:
myCustomFirstStageName: "HELLO ROB"
stages:
- id: bake1
type: findImageFromTags
name: "{{ myCustomFirstStageName }}"
config:
cloudProvider: aws
cloudProviderType: aws
packageName: "{{ application }}"
regions:
- us-east-1
- us-west-1
- us-west-2
- eu-west-1
tags:
stack: test
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
{
"id": "unknown",
"keepWaitingPipelines": false,
"limitConcurrent": true,
"application": "orca",
"name": "MPT Stage Replacement Test",
"notifications": [],
"stages": [
{
"cloudProvider": "aws",
"cloudProviderType": "aws",
"name": "HELLO ROB",
"packageName": "orca",
"refId": "bake1",
"regions": [
"us-east-1",
"us-west-1",
"us-west-2",
"eu-west-1"
],
"tags": {
"stack": "test"
},
"requisiteStageRefIds": [],
"type": "findImageFromTags",
"id": null
},
{
"id": null,
"clusters": [
{
"account": "test",
"application": "spindemo",
"availabilityZones": {
"us-west-1": [
"us-west-1a",
"us-west-1c"
]
},
"capacity": {
"desired": 1,
"max": 1,
"min": 1
},
"cloudProvider": "aws",
"cooldown": 10,
"copySourceCustomBlockDeviceMappings": true,
"ebsOptimized": false,
"enabledMetrics": [],
"freeFormDetails": "demo",
"healthCheckGracePeriod": 600,
"healthCheckType": "EC2",
"iamRole": "myIAMRole",
"instanceMonitoring": false,
"instanceType": "m3.large",
"interestingHealthProviderNames": [
"Amazon"
],
"keyPair": "keypair",
"loadBalancers": [
"spindemo-demo-frontend"
],
"maxRemainingAsgs": 2,
"preferSourceCapacity": true,
"provider": "aws",
"scaleDown": true,
"securityGroups": [],
"stack": "test",
"strategy": "redblack",
"subnetType": "mySubnet",
"suspendedProcesses": [],
"tags": {},
"targetGroups": [],
"targetHealthyDeployPercentage": 100,
"terminationPolicies": [
"Default"
],
"useAmiBlockDeviceMappings": false,
"useSourceCapacity": true
},
{
"account": "test",
"application": "spindemo",
"availabilityZones": {
"us-east-1": [
"us-east-1c",
"us-east-1d",
"us-east-1e"
]
},
"capacity": {
"desired": 0,
"max": 0,
"min": 0
},
"cloudProvider": "aws",
"cooldown": 10,
"ebsOptimized": false,
"freeFormDetails": "demo",
"healthCheckGracePeriod": 600,
"healthCheckType": "EC2",
"iamRole": "myIAMRole",
"instanceMonitoring": false,
"instanceType": "m3.large",
"interestingHealthProviderNames": [
"Amazon"
],
"keyPair": "keypair",
"provider": "aws",
"securityGroups": [],
"stack": "test",
"strategy": "highlander",
"subnetType": "mySubnet",
"suspendedProcesses": [],
"tags": {},
"targetHealthyDeployPercentage": 100,
"terminationPolicies": [
"Default"
],
"useSourceCapacity": false
}
],
"name": "Deploy",
"refId": "deploy2",
"requisiteStageRefIds": [
"bake1"
],
"type": "deploy"
}
],
"parameterConfig": []
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
---
schema: "1"
id: stageReplacement
metadata:
name: Stage Replacement
description: Example for replacing a stage
variables:
- name: myCustomFirstStageName
stages:
- id: bake1
type: bake
name: "{{ myCustomFirstStageName }}"
config:
baseLabel: release
baseOs: trusty
cloudProviderType: aws
enhancedNetworking: false
extendedAttributes: {}
overrideTimeout: true
package: orca
regions:
- us-east-1
- us-west-1
- us-west-2
- eu-west-1
sendNotifications: true
showAdvancedOptions: true
stageTimeoutMs: 900000
storeType: ebs
user: example@example.com
vmType: hvm
- id: deploy2
type: deploy
dependsOn:
- bake1
name: Deploy
config:
clusters:
- account: test
application: spindemo
availabilityZones:
us-west-1:
- us-west-1a
- us-west-1c
capacity:
desired: 1
max: 1
min: 1
cloudProvider: aws
cooldown: 10
copySourceCustomBlockDeviceMappings: true
ebsOptimized: false
enabledMetrics: []
freeFormDetails: demo
healthCheckGracePeriod: 600
healthCheckType: EC2
iamRole: myIAMRole
instanceMonitoring: false
instanceType: m3.large
interestingHealthProviderNames:
- Amazon
keyPair: keypair
loadBalancers:
- spindemo-demo-frontend
maxRemainingAsgs: 2
preferSourceCapacity: true
provider: aws
scaleDown: true
securityGroups: []
stack: test
strategy: redblack
subnetType: mySubnet
suspendedProcesses: []
tags: {}
targetGroups: []
targetHealthyDeployPercentage: 100
terminationPolicies:
- Default
useAmiBlockDeviceMappings: false
useSourceCapacity: true
- account: test
application: spindemo
availabilityZones:
us-east-1:
- us-east-1c
- us-east-1d
- us-east-1e
capacity:
desired: 0
max: 0
min: 0
cloudProvider: aws
cooldown: 10
ebsOptimized: false
freeFormDetails: demo
healthCheckGracePeriod: 600
healthCheckType: EC2
iamRole: myIAMRole
instanceMonitoring: false
instanceType: m3.large
interestingHealthProviderNames:
- Amazon
keyPair: keypair
provider: aws
securityGroups: []
stack: test
strategy: highlander
subnetType: mySubnet
suspendedProcesses: []
tags: {}
targetHealthyDeployPercentage: 100
terminationPolicies:
- Default
useSourceCapacity: false

0 comments on commit 9ea25de

Please sign in to comment.