Skip to content

Commit

Permalink
feat(rollback): Support rolling back to a server group that no longer…
Browse files Browse the repository at this point in the history
… exists (#1716)

This PR provides a rollback strategy that will clone forward with the
image details that were tagged as part of #1705.

It also supports the `imageName` being explicitly provided, but that's
an exceptional case that would not be supported in the UI.

The `spinnaker:metadata` tag will include `buildInfo` for the image if
it is returned from `clouddriver`.
  • Loading branch information
ajordens authored Oct 19, 2017
1 parent 45ddb81 commit c6a0f45
Show file tree
Hide file tree
Showing 9 changed files with 613 additions and 153 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,13 @@
package com.netflix.spinnaker.orca.clouddriver.pipeline.servergroup

import com.fasterxml.jackson.annotation.JsonIgnore
import com.netflix.spinnaker.orca.clouddriver.pipeline.providers.aws.ApplySourceServerGroupCapacityStage
import com.netflix.spinnaker.orca.clouddriver.pipeline.providers.aws.CaptureSourceServerGroupCapacityStage
import com.netflix.spinnaker.orca.kato.pipeline.support.ResizeStrategy
import com.netflix.frigga.Names
import com.netflix.spinnaker.orca.RetrySupport
import com.netflix.spinnaker.orca.clouddriver.OortService
import com.netflix.spinnaker.orca.clouddriver.pipeline.servergroup.rollback.ExplicitRollback
import com.netflix.spinnaker.orca.clouddriver.pipeline.servergroup.rollback.PreviousImageRollback
import com.netflix.spinnaker.orca.clouddriver.pipeline.servergroup.rollback.Rollback
import com.netflix.spinnaker.orca.clouddriver.pipeline.servergroup.rollback.TestRollback
import com.netflix.spinnaker.orca.pipeline.StageDefinitionBuilder
import com.netflix.spinnaker.orca.pipeline.model.Execution
import com.netflix.spinnaker.orca.pipeline.model.Stage
Expand All @@ -37,7 +41,7 @@ class RollbackServerGroupStage implements StageDefinitionBuilder {
AutowireCapableBeanFactory autowireCapableBeanFactory

@Override
def <T extends Execution<T>> List<Stage<T>> aroundStages(Stage<T> stage) {
<T extends Execution<T>> List<Stage<T>> aroundStages(Stage<T> stage) {
def stageData = stage.mapTo(StageData)

if (!stageData.rollbackType) {
Expand All @@ -50,7 +54,9 @@ class RollbackServerGroupStage implements StageDefinitionBuilder {
}

static enum RollbackType {
EXPLICIT(ExplicitRollback)
EXPLICIT(ExplicitRollback),
PREVIOUS_IMAGE(PreviousImageRollback),
TEST(TestRollback)

final Class implementationClass

Expand All @@ -62,117 +68,4 @@ class RollbackServerGroupStage implements StageDefinitionBuilder {
static class StageData {
RollbackType rollbackType
}

static interface Rollback {
def <T extends Execution<T>> List<Stage<T>> buildStages(Stage<T> parentStage)
}

static class ExplicitRollback implements Rollback {
String rollbackServerGroupName
String restoreServerGroupName
Integer targetHealthyRollbackPercentage

@Autowired
@JsonIgnore
EnableServerGroupStage enableServerGroupStage

@Autowired
@JsonIgnore
DisableServerGroupStage disableServerGroupStage

@Autowired
@JsonIgnore
ResizeServerGroupStage resizeServerGroupStage

@Autowired
@JsonIgnore
CaptureSourceServerGroupCapacityStage captureSourceServerGroupCapacityStage

@Autowired
@JsonIgnore
ApplySourceServerGroupCapacityStage applySourceServerGroupCapacityStage

@JsonIgnore
def <T extends Execution<T>> List<Stage<T>> buildStages(Stage<T> parentStage) {
def stages = []

Map enableServerGroupContext = new HashMap(parentStage.context)
enableServerGroupContext.targetHealthyDeployPercentage = targetHealthyRollbackPercentage
enableServerGroupContext.serverGroupName = restoreServerGroupName
stages << newStage(
parentStage.execution, enableServerGroupStage.type, "enable", enableServerGroupContext, parentStage, SyntheticStageOwner.STAGE_AFTER
)

stages << buildCaptureSourceServerGroupCapacityStage(parentStage, parentStage.mapTo(ResizeStrategy.Source))

Map resizeServerGroupContext = new HashMap(parentStage.context) + [
action : ResizeStrategy.ResizeAction.scale_to_server_group.toString(),
source : {
def source = parentStage.mapTo(ResizeStrategy.Source)
source.serverGroupName = rollbackServerGroupName
return source
}.call(),
asgName : restoreServerGroupName,
pinMinimumCapacity: true,
targetHealthyDeployPercentage: targetHealthyRollbackPercentage
]
stages << newStage(
parentStage.execution, resizeServerGroupStage.type, "resize", resizeServerGroupContext, parentStage, SyntheticStageOwner.STAGE_AFTER
)

Map disableServerGroupContext = new HashMap(parentStage.context)
disableServerGroupContext.serverGroupName = rollbackServerGroupName
stages << newStage(
parentStage.execution, disableServerGroupStage.type, "disable", disableServerGroupContext, parentStage, SyntheticStageOwner.STAGE_AFTER
)

stages << buildApplySourceServerGroupCapacityStage(parentStage, parentStage.mapTo(ResizeStrategy.Source))
return stages
}

Stage buildCaptureSourceServerGroupCapacityStage(Stage parentStage,
ResizeStrategy.Source source) {
Map captureSourceServerGroupCapacityContext = [
useSourceCapacity: true,
source : [
asgName : rollbackServerGroupName,
serverGroupName: rollbackServerGroupName,
region : source.region,
account : source.credentials,
cloudProvider : source.cloudProvider
]
]
return newStage(
parentStage.execution,
captureSourceServerGroupCapacityStage.type,
"snapshot",
captureSourceServerGroupCapacityContext,
parentStage,
SyntheticStageOwner.STAGE_AFTER
)
}

Stage buildApplySourceServerGroupCapacityStage(Stage parentStage,
ResizeStrategy.Source source) {
Map applySourceServerGroupCapacityContext = [
credentials: source.credentials,
target : [
asgName : restoreServerGroupName,
serverGroupName: restoreServerGroupName,
region : source.region,
account : source.credentials,
cloudProvider : source.cloudProvider
]
]
return newStage(
parentStage.execution,
applySourceServerGroupCapacityStage.type,
"apply",
applySourceServerGroupCapacityContext,
parentStage,
SyntheticStageOwner.STAGE_AFTER
)
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
* Copyright 2017 Netflix, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.netflix.spinnaker.orca.clouddriver.pipeline.servergroup.rollback

import com.fasterxml.jackson.annotation.JsonIgnore
import com.netflix.spinnaker.orca.clouddriver.pipeline.providers.aws.ApplySourceServerGroupCapacityStage
import com.netflix.spinnaker.orca.clouddriver.pipeline.providers.aws.CaptureSourceServerGroupCapacityStage
import com.netflix.spinnaker.orca.clouddriver.pipeline.servergroup.DisableServerGroupStage
import com.netflix.spinnaker.orca.clouddriver.pipeline.servergroup.EnableServerGroupStage
import com.netflix.spinnaker.orca.clouddriver.pipeline.servergroup.ResizeServerGroupStage
import com.netflix.spinnaker.orca.kato.pipeline.support.ResizeStrategy
import com.netflix.spinnaker.orca.pipeline.model.Execution
import com.netflix.spinnaker.orca.pipeline.model.Stage
import com.netflix.spinnaker.orca.pipeline.model.SyntheticStageOwner
import org.springframework.beans.factory.annotation.Autowired;

import static com.netflix.spinnaker.orca.pipeline.StageDefinitionBuilder.newStage

class ExplicitRollback implements Rollback {
String rollbackServerGroupName
String restoreServerGroupName
Integer targetHealthyRollbackPercentage

@Autowired
@JsonIgnore
EnableServerGroupStage enableServerGroupStage

@Autowired
@JsonIgnore
DisableServerGroupStage disableServerGroupStage

@Autowired
@JsonIgnore
ResizeServerGroupStage resizeServerGroupStage

@Autowired
@JsonIgnore
CaptureSourceServerGroupCapacityStage captureSourceServerGroupCapacityStage

@Autowired
@JsonIgnore
ApplySourceServerGroupCapacityStage applySourceServerGroupCapacityStage

@JsonIgnore
def <T extends Execution<T>> List<Stage<T>> buildStages(Stage<T> parentStage) {
def stages = []

Map enableServerGroupContext = new HashMap(parentStage.context)
enableServerGroupContext.targetHealthyDeployPercentage = targetHealthyRollbackPercentage
enableServerGroupContext.serverGroupName = restoreServerGroupName
stages << newStage(
parentStage.execution, enableServerGroupStage.type, "enable", enableServerGroupContext, parentStage, SyntheticStageOwner.STAGE_AFTER
)

stages << buildCaptureSourceServerGroupCapacityStage(parentStage, parentStage.mapTo(ResizeStrategy.Source))

Map resizeServerGroupContext = new HashMap(parentStage.context) + [
action : ResizeStrategy.ResizeAction.scale_to_server_group.toString(),
source : {
def source = parentStage.mapTo(ResizeStrategy.Source)
source.serverGroupName = rollbackServerGroupName
return source
}.call(),
asgName : restoreServerGroupName,
pinMinimumCapacity : true,
targetHealthyDeployPercentage: targetHealthyRollbackPercentage
]
stages << newStage(
parentStage.execution, resizeServerGroupStage.type, "resize", resizeServerGroupContext, parentStage, SyntheticStageOwner.STAGE_AFTER
)

Map disableServerGroupContext = new HashMap(parentStage.context)
disableServerGroupContext.serverGroupName = rollbackServerGroupName
stages << newStage(
parentStage.execution, disableServerGroupStage.type, "disable", disableServerGroupContext, parentStage, SyntheticStageOwner.STAGE_AFTER
)

stages << buildApplySourceServerGroupCapacityStage(parentStage, parentStage.mapTo(ResizeStrategy.Source))
return stages
}

Stage buildCaptureSourceServerGroupCapacityStage(Stage parentStage,
ResizeStrategy.Source source) {
Map captureSourceServerGroupCapacityContext = [
useSourceCapacity: true,
source : [
asgName : rollbackServerGroupName,
serverGroupName: rollbackServerGroupName,
region : source.region,
account : source.credentials,
cloudProvider : source.cloudProvider
]
]
return newStage(
parentStage.execution,
captureSourceServerGroupCapacityStage.type,
"snapshot",
captureSourceServerGroupCapacityContext,
parentStage,
SyntheticStageOwner.STAGE_AFTER
)
}

Stage buildApplySourceServerGroupCapacityStage(Stage parentStage,
ResizeStrategy.Source source) {
Map applySourceServerGroupCapacityContext = [
credentials: source.credentials,
target : [
asgName : restoreServerGroupName,
serverGroupName: restoreServerGroupName,
region : source.region,
account : source.credentials,
cloudProvider : source.cloudProvider
]
]
return newStage(
parentStage.execution,
applySourceServerGroupCapacityStage.type,
"apply",
applySourceServerGroupCapacityContext,
parentStage,
SyntheticStageOwner.STAGE_AFTER
)
}
}
Loading

0 comments on commit c6a0f45

Please sign in to comment.