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

User-defined Metadata for ASG Creation, ASG NextGroup & SWF AutoDeployment #592

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ class AutoScalingController {
}
Subnets subnets = awsEc2Service.getSubnets(userContext)
Map<String, String> purposeToVpcId = subnets.mapPurposeToVpcId()
Map<String, String> userMetaData = params.userMetaData ?: [:]
String subnetPurpose = params.subnetPurpose ?: null
String vpcId = purposeToVpcId[subnetPurpose]
Set<String> appsWithClusterOptLevel = []
Expand Down Expand Up @@ -285,7 +286,8 @@ class AutoScalingController {
iamInstanceProfile: configService.defaultIamRole,
spotUrl: configService.spotUrl,
isChaosMonkeyActive: cloudReadyService.isChaosMonkeyActive(userContext.region),
appsWithClusterOptLevel: appsWithClusterOptLevel ?: []
appsWithClusterOptLevel: appsWithClusterOptLevel ?: [],
userMetaData: userMetaData ?: [:]
]
}

Expand Down Expand Up @@ -355,8 +357,10 @@ class AutoScalingController {
launchConfigTemplate.spotPrice = spotInstanceRequestService.recommendSpotPrice(userContext, instType)
}
boolean enableChaosMonkey = params.chaosMonkey == 'enabled'
Map<String, String> userMetaData = params.userMetaData ?: [:]
CreateAutoScalingGroupResult result = awsAutoScalingService.createLaunchConfigAndAutoScalingGroup(
userContext, groupTemplate, launchConfigTemplate, suspendedProcesses, enableChaosMonkey)
userContext, groupTemplate, launchConfigTemplate, suspendedProcesses, enableChaosMonkey,
userMetaData)
flash.message = result.toString()
if (result.succeeded()) {
redirect(action: 'show', params: [id: groupName])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,8 @@ Group: ${loadBalancerNames}"""
instanceType: instanceType,
groupName: nextGroupName,
securityGroups: securityGroups,
maxStartupRetries: convertToIntOrUseDefault(params.maxStartupRetries, 5)
maxStartupRetries: convertToIntOrUseDefault(params.maxStartupRetries, 5),
userMetadata: params.userMetaData ?: [:]
),
initialTraffic: initialTraffic,
minSize: minSize,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ class DeploymentController {
} else {
String deploymentId = deploymentService.startDeployment(userContext,
startDeploymentRequest.deploymentOptions, startDeploymentRequest.lcOptions,
startDeploymentRequest.asgOptions)
startDeploymentRequest.asgOptions, startDeploymentRequest.userMetaData)
render ([deploymentId: deploymentId] as JSON)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ class PushController {
instanceType: params.instanceType,
groupName: groupName,
securityGroups: selectedSecurityGroups,
maxStartupRetries: params.maxStartupRetries?.toInteger() ?: 5
maxStartupRetries: params.maxStartupRetries?.toInteger() ?: 5,
userMetadata: params.userMetaData ?: [:]
),
newestFirst: params.newestFirst == 'true',
relaunchCount: relaunchCount,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1152,7 +1152,7 @@ class AwsAutoScalingService implements CacheInitializer, InitializingBean {
CreateAutoScalingGroupResult createLaunchConfigAndAutoScalingGroup(UserContext userContext,
AutoScalingGroup groupTemplate, LaunchConfiguration launchConfigTemplate,
Collection<AutoScalingProcessType> suspendedProcesses, boolean enableChaosMonkey = false,
Task existingTask = null) {
Map<String, String> userMetaData = [:], Task existingTask = null) {

CreateAutoScalingGroupResult result = new CreateAutoScalingGroupResult()
String groupName = groupTemplate.autoScalingGroupName
Expand All @@ -1169,7 +1169,7 @@ class AwsAutoScalingService implements CacheInitializer, InitializingBean {
launchConfig.securityGroups = launchTemplateService.includeDefaultSecurityGroups(
launchConfigTemplate.securityGroups, groupTemplate.VPCZoneIdentifier as boolean, userContext.region)
taskService.runTask(userContext, msg, { Task task ->
String userData = launchTemplateService.buildUserData(userContext, groupOptions, launchConfig)
String userData = launchTemplateService.buildUserData(userContext, groupOptions, launchConfig, userMetaData)
launchConfig.userData = userData
result.launchConfigName = launchConfigName
result.autoScalingGroupName = groupName
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,12 @@ class DeploymentService {
* @return the unique ID of the workflow execution that is starting
*/
public String startDeployment(UserContext userContext, DeploymentWorkflowOptions deploymentOptions,
LaunchConfigurationBeanOptions lcOverrides, AutoScalingGroupBeanOptions asgOverrides) {
LaunchConfigurationBeanOptions lcOverrides, AutoScalingGroupBeanOptions asgOverrides,
Map<String, String> userMetaData) {

SwfWorkflow<DeploymentWorkflow> workflow = flowService.getNewWorkflowClient(userContext,
DeploymentWorkflow, new Link(EntityType.cluster, deploymentOptions.clusterName))
workflow.client.deploy(userContext, deploymentOptions, lcOverrides, asgOverrides)
workflow.client.deploy(userContext, deploymentOptions, lcOverrides, asgOverrides, userMetaData)
workflow.tags.id
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,16 @@ class LaunchTemplateService {
* @return the user data string that should be applied to the LaunchConfiguration of an auto scaling group
*/
String buildUserData(UserContext userContext, AutoScalingGroupBeanOptions autoScalingGroup,
LaunchConfigurationBeanOptions launchConfiguration) {
LaunchConfigurationBeanOptions launchConfiguration, Map<String, String> userMetaData) {

String imageId = launchConfiguration.imageId
Image image = awsEc2Service.getImage(userContext, imageId)
String appName = Relationships.appNameFromGroupName(autoScalingGroup.autoScalingGroupName)
AppRegistration app = applicationService.getRegisteredApplication(userContext, appName)

// Wrap all the inputs in a single class so we can add more inputs later without changing the plugin interface.
LaunchContext launchContext = new LaunchContext(userContext, image, app, autoScalingGroup, launchConfiguration)
LaunchContext launchContext = new LaunchContext(userContext, image, app, autoScalingGroup, launchConfiguration,
userMetaData)
pluginService.advancedUserDataProvider.buildUserData(launchContext)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ interface DeploymentActivities {
* @return name of the launch configuration
*/
String createLaunchConfigForNextAsg(UserContext userContext, AutoScalingGroupBeanOptions autoScalingGroup,
LaunchConfigurationBeanOptions launchConfiguration)
LaunchConfigurationBeanOptions launchConfiguration, Map<String, String> userMetaData)

/**
* Creates the next ASG in the cluster based on the asgOptions but without instances.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,9 @@ class DeploymentActivitiesImpl implements DeploymentActivities {

@Override
String createLaunchConfigForNextAsg(UserContext userContext, AutoScalingGroupBeanOptions autoScalingGroup,
LaunchConfigurationBeanOptions launchConfiguration) {
LaunchConfigurationBeanOptions launchConfiguration, Map<String, String> userMetaData) {
launchConfiguration.userData = launchTemplateService.buildUserData(userContext, autoScalingGroup,
launchConfiguration)
launchConfiguration, userMetaData)
awsAutoScalingService.createLaunchConfiguration(userContext, launchConfiguration, new Task())
launchConfiguration.launchConfigurationName
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ interface DeploymentWorkflow {
*/
@Execute(version = "1.5")
void deploy(UserContext userContext, DeploymentWorkflowOptions deploymentOptions,
LaunchConfigurationBeanOptions lcOverrides, AutoScalingGroupBeanOptions asgOverrides)
LaunchConfigurationBeanOptions lcOverrides, AutoScalingGroupBeanOptions asgOverrides,
Map<String, String> userMetaData)

/**
* @return current log history of the workflow
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ class DeploymentWorkflowDescriptionTemplate extends WorkflowDescriptionTemplate

@Override
void deploy(UserContext userContext, DeploymentWorkflowOptions deploymentOptions,
LaunchConfigurationBeanOptions lcOverrides, AutoScalingGroupBeanOptions asgOverrides) {
LaunchConfigurationBeanOptions lcOverrides, AutoScalingGroupBeanOptions asgOverrides,
Map<String, String> userMetaData) {
description = "Deploying new ASG to cluster '${deploymentOptions.clusterName}'"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ class DeploymentWorkflowImpl implements DeploymentWorkflow, WorkflowOperator<Dep

@Override
void deploy(UserContext userContext, DeploymentWorkflowOptions deploymentOptions,
LaunchConfigurationBeanOptions lcInputs, AutoScalingGroupBeanOptions asgInputs) {
LaunchConfigurationBeanOptions lcInputs, AutoScalingGroupBeanOptions asgInputs,
Map<String, String> userMetaData) {
String clusterName = deploymentOptions.clusterName
Promise<AsgDeploymentNames> asgDeploymentNamesPromise = promiseFor(activities.getAsgDeploymentNames(userContext,
clusterName))
Expand All @@ -78,7 +79,7 @@ class DeploymentWorkflowImpl implements DeploymentWorkflow, WorkflowOperator<Dep
constructLaunchConfigForNextAsg(userContext, nextAsgTemplate, lcInputs))
waitFor(nextLcTemplateConstructed) { LaunchConfigurationBeanOptions nextLcTemplate ->
startDeployment(userContext, deploymentOptions, asgDeploymentNames, nextAsgTemplate, nextLcTemplate,
runningAsgAnalyses)
userMetaData, runningAsgAnalyses)
}
} withCatch { Throwable e ->
rollbackCause = e
Expand Down Expand Up @@ -110,7 +111,8 @@ class DeploymentWorkflowImpl implements DeploymentWorkflow, WorkflowOperator<Dep

private Promise<Void> startDeployment(UserContext userContext, DeploymentWorkflowOptions deploymentOptions,
AsgDeploymentNames asgDeploymentNames, AutoScalingGroupBeanOptions nextAsgTemplate,
LaunchConfigurationBeanOptions nextLcTemplate, List<DoTry<ScheduledAsgAnalysis>> runningAsgAnalyses) {
LaunchConfigurationBeanOptions nextLcTemplate, Map<String, String> userMetaData,
List<DoTry<ScheduledAsgAnalysis>> runningAsgAnalyses) {

Map<Class<? extends DeploymentStep>, Closure<Promise>> stepsToOperations = [
(WaitStep): { WaitStep step ->
Expand All @@ -120,7 +122,8 @@ class DeploymentWorkflowImpl implements DeploymentWorkflow, WorkflowOperator<Dep
(CreateAsgStep): { CreateAsgStep step ->
status "Creating Launch Configuration '${asgDeploymentNames.nextLaunchConfigName}'."
Promise<String> launchConfigCreated = promiseFor(
activities.createLaunchConfigForNextAsg(userContext, nextAsgTemplate, nextLcTemplate))
activities.createLaunchConfigForNextAsg(userContext, nextAsgTemplate, nextLcTemplate,
userMetaData))
waitFor(launchConfigCreated) {
status "Creating Auto Scaling Group '${asgDeploymentNames.nextAsgName}' \
initially with 0 instances."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class StartDeploymentRequest {
DeploymentWorkflowOptions deploymentOptions
LaunchConfigurationBeanOptions lcOptions
AutoScalingGroupBeanOptions asgOptions
Map<String, String> userMetaData

/**
* @return List of all validation errors
Expand Down
5 changes: 5 additions & 0 deletions src/groovy/com/netflix/asgard/model/LaunchContext.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,9 @@ import groovy.transform.Canonical
* An object similar in most ways to the launch configuration with which the deployment will be done.
*/
LaunchConfigurationBeanOptions launchConfiguration

/**
* User metadata for providing to custom userdata providers
*/
Map<String, String> userMetaData
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,5 @@ import groovy.transform.Immutable
String groupName
List<String> securityGroups
Integer maxStartupRetries = 5
Map<String, String> userMetadata = [:]
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ class GroupCreateOperation extends AbstractPushOperation {
}

CreateAutoScalingGroupResult result = awsAutoScalingService.createLaunchConfigAndAutoScalingGroup(
options.common.userContext, groupTemplate, launchConfigTemplate, suspendedProcesses, false, task)
options.common.userContext, groupTemplate, launchConfigTemplate, suspendedProcesses, false,
options.common.userMetadata, task)
log.debug """GroupCreateOperation.start for Cluster '${clusterName}' Group created with Load Balancers: \
${groupTemplate.loadBalancerNames} and result ${result}"""
task.log(result.toString())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ class RollingPushOperation extends AbstractPushOperation {
AutoScalingGroupBeanOptions groupForUserData = AutoScalingGroupBeanOptions.from(group, subnets)
groupForUserData.launchConfigurationName = newLaunchName
launchConfig.userData = launchTemplateService.buildUserData(options.common.userContext, groupForUserData,
launchConfig)
launchConfig, options.common.userMetadata)
awsAutoScalingService.createLaunchConfiguration(options.common.userContext, launchConfig, task)

Time.sleepCancellably 200 // small pause before ASG update to avoid rate limiting
Expand Down
4 changes: 2 additions & 2 deletions test/unit/com/netflix/asgard/AutoScalingControllerSpec.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -380,8 +380,8 @@ class AutoScalingControllerSpec extends Specification {

then:
1 * controller.awsAutoScalingService.createLaunchConfigAndAutoScalingGroup(_, _, expectedLaunchConfiguration,
_, _) >> new CreateAutoScalingGroupResult()
0 * controller.awsAutoScalingService.createLaunchConfigAndAutoScalingGroup(_, _, _, _, _)
_, _, _) >> new CreateAutoScalingGroupResult()
0 * controller.awsAutoScalingService.createLaunchConfigAndAutoScalingGroup(_, _, _, _, _, _)

where:
ebsOptimizedParam | ebsOptimizedValue
Expand Down
9 changes: 6 additions & 3 deletions test/unit/com/netflix/asgard/DeploymentControllerSpec.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ class DeploymentControllerSpec extends Specification {
{"type": "DisableAsg", "targetAsg": "Previous"},
{"type": "Judgment", "durationMinutes": 241},
{"type": "DeleteAsg", "targetAsg": "Previous"}
]}}""" as String
]},
"userMetaData": {"meta": "data"}
}""" as String
}

void setup() {
Expand Down Expand Up @@ -195,8 +197,9 @@ class DeploymentControllerSpec extends Specification {
subnetPurpose: "internal",
terminationPolicies: ["OldestLaunchConfiguration"],
tags: [],
suspendedProcesses: []
)
suspendedProcesses: [],
),
[meta: "data"]
) >> '123'
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,10 @@ class DeploymentServiceUnitSpec extends Specification {
DeploymentWorkflowOptions deployOpts = new DeploymentWorkflowOptions(clusterName: 'Calysteral')
LaunchConfigurationBeanOptions lcOpts = new LaunchConfigurationBeanOptions()
AutoScalingGroupBeanOptions asgOpts = new AutoScalingGroupBeanOptions()
Map<String, String> userMetaData = [meta: "data"]

when:
String taskId = deploymentService.startDeployment(userContext, deployOpts, lcOpts, asgOpts)
String taskId = deploymentService.startDeployment(userContext, deployOpts, lcOpts, asgOpts, userMetaData)

then:
taskId == '07700900461'
Expand Down
9 changes: 6 additions & 3 deletions test/unit/com/netflix/asgard/LaunchTemplateServiceSpec.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ class LaunchTemplateServiceSpec extends Specification {
launchConfigurationName: 'hello-wassup-987654321')
LaunchConfigurationBeanOptions launchConfig = new LaunchConfigurationBeanOptions(
launchConfigurationName: 'hello-wassup-987654321', imageId: image.imageId)
Map<String, String> userMetaData = [meta: "data"]

launchTemplateService.applicationService = Mock(ApplicationService) {
getRegisteredApplication(*_) >> application
}
Expand All @@ -146,11 +148,11 @@ class LaunchTemplateServiceSpec extends Specification {
}

when:
String userData = launchTemplateService.buildUserData(userContext, asg, launchConfig)
String userData = launchTemplateService.buildUserData(userContext, asg, launchConfig, userMetaData)

then:
1 * advancedUserDataProvider.buildUserData(
new LaunchContext(userContext, image, application, asg, launchConfig)) >> 'ta da!'
new LaunchContext(userContext, image, application, asg, launchConfig, userMetaData)) >> 'ta da!'
userData == 'ta da!'
}

Expand All @@ -163,7 +165,8 @@ class LaunchTemplateServiceSpec extends Specification {
String userData = launchTemplateService.buildUserDataForImage(userContext, image)

then:
1 * advancedUserDataProvider.buildUserData(new LaunchContext(userContext, image, null, null, null)) >> 'ta da!'
1 * advancedUserDataProvider.buildUserData(new LaunchContext(userContext, image, null, null, null, null)) >>
'ta da!'
userData == 'ta da!'
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ class DeploymentActivitiesSpec extends Specification {
def 'should create launch config for next ASG'() {
when:
deploymentActivities.createLaunchConfigForNextAsg(userContext, null,
new LaunchConfigurationBeanOptions(launchConfigurationName: 'rearden_metal_pourer-20130718090004'))
new LaunchConfigurationBeanOptions(launchConfigurationName: 'rearden_metal_pourer-20130718090004'),
[meta:"data"])

then:
with(mockAwsAutoScalingService) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class DeploymentWorkflowDescriptionTemplateSpec extends Specification {
DeploymentWorkflowDescriptionTemplate descriptionTemplate = new DeploymentWorkflowDescriptionTemplate()

when:
descriptionTemplate.deploy(null, new DeploymentWorkflowOptions(clusterName: 'the_seaward'), null, null)
descriptionTemplate.deploy(null, new DeploymentWorkflowOptions(clusterName: 'the_seaward'), null, null, null)

then:
"Deploying new ASG to cluster 'the_seaward'" == descriptionTemplate.description
Expand Down
Loading