Skip to content

Commit

Permalink
refactor(after stages): Always dynamically build after stages
Browse files Browse the repository at this point in the history
  • Loading branch information
robfletcher committed Mar 15, 2018
1 parent b97d741 commit 7e843cd
Show file tree
Hide file tree
Showing 36 changed files with 964 additions and 639 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,18 @@
import com.netflix.spinnaker.orca.pipeline.StageDefinitionBuilder;
import com.netflix.spinnaker.orca.pipeline.TaskNode;
import com.netflix.spinnaker.orca.pipeline.WaitStage;
import com.netflix.spinnaker.orca.pipeline.graph.StageGraphBuilder;
import com.netflix.spinnaker.orca.pipeline.model.Stage;
import com.netflix.spinnaker.orca.pipeline.model.SyntheticStageOwner;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

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

@Component
public class RollbackClusterStage implements StageDefinitionBuilder {
public static final String PIPELINE_CONFIG_TYPE = "rollbackCluster";
Expand All @@ -58,65 +54,53 @@ public void taskGraph(@Nonnull Stage stage, @Nonnull TaskNode.Builder builder) {
.withTask("determineRollbackCandidates", DetermineRollbackCandidatesTask.class);
}

@Nonnull
@Override
public List<Stage> afterStages(@Nonnull Stage stage) {
StageData stageData = stage.mapTo(StageData.class);
public void afterStages(@Nonnull Stage parent, @Nonnull StageGraphBuilder graph) {
StageData stageData = parent.mapTo(StageData.class);

Map<String, String> rollbackTypes = (Map<String, String>) stage.getOutputs().get("rollbackTypes");
Map<String, String> rollbackTypes = (Map<String, String>) parent.getOutputs().get("rollbackTypes");

// filter out any regions that do _not_ have a rollback target
List<String> regionsToRollback = stageData.regions
.stream()
.filter(rollbackTypes::containsKey)
.collect(Collectors.toList());

List<Stage> stages = new ArrayList<>();
for (String region : regionsToRollback) {
Map<String, Object> context = new HashMap<>();
context.put(
"rollbackType",
((Map) stage.getOutputs().get("rollbackTypes")).get(region)
((Map) parent.getOutputs().get("rollbackTypes")).get(region)
);
context.put(
"rollbackContext",
((Map) stage.getOutputs().get("rollbackContexts")).get(region)
((Map) parent.getOutputs().get("rollbackContexts")).get(region)
);
context.put("type", rollbackServerGroupStage.getType());
context.put("region", region);
context.put("credentials", stageData.credentials);
context.put("cloudProvider", stageData.cloudProvider);

// propagate any attributes of the parent stage that are relevant to this rollback
context.putAll(propagateParentStageContext(stage.getParent()));

stages.add(
newStage(
stage.getExecution(),
rollbackServerGroupStage.getType(),
"Rollback " + region,
context,
stage,
SyntheticStageOwner.STAGE_AFTER
)
);
context.putAll(propagateParentStageContext(parent.getParent()));

Stage rollbackStage = graph.add((it) -> {
it.setType(rollbackServerGroupStage.getType());
it.setName("Rollback " + region);
it.setContext(context);
});

if (stageData.waitTimeBetweenRegions != null && regionsToRollback.indexOf(region) < regionsToRollback.size() - 1) {
// only add the waitStage if we're not the very last region!
stages.add(
newStage(
stage.getExecution(),
waitStage.getType(),
"Wait after " + region,
Collections.singletonMap("waitTime", stageData.waitTimeBetweenRegions),
stage,
SyntheticStageOwner.STAGE_AFTER
)
);
graph.connect(
rollbackStage,
(it) -> {
it.setType(waitStage.getType());
it.setName("Wait after " + region);
it.setContext(Collections.singletonMap("waitTime", stageData.waitTimeBetweenRegions));
});
}
}

return stages;
}

private static Map<String, Object> propagateParentStageContext(Stage parent) {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright 2015 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.cluster;

import com.netflix.spinnaker.orca.clouddriver.tasks.cluster.AbstractClusterWideClouddriverTask;
import com.netflix.spinnaker.orca.clouddriver.tasks.cluster.AbstractWaitForClusterWideClouddriverTask;
import com.netflix.spinnaker.orca.clouddriver.tasks.cluster.ShrinkClusterTask;
import com.netflix.spinnaker.orca.clouddriver.tasks.cluster.WaitForClusterShrinkTask;
import com.netflix.spinnaker.orca.pipeline.graph.StageGraphBuilder;
import com.netflix.spinnaker.orca.pipeline.model.Stage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Nonnull;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

@Component
public class ShrinkClusterStage extends AbstractClusterWideClouddriverOperationStage {

private final DisableClusterStage disableClusterStage;

@Autowired
public ShrinkClusterStage(DisableClusterStage disableClusterStage) {
this.disableClusterStage = disableClusterStage;
}

@Override
public Class<? extends AbstractClusterWideClouddriverTask> getClusterOperationTask() {
return ShrinkClusterTask.class;
}

@Override
public Class<? extends AbstractWaitForClusterWideClouddriverTask> getWaitForTask() {
return WaitForClusterShrinkTask.class;
}

@Override
public void beforeStages(
@Nonnull Stage parent,
@Nonnull StageGraphBuilder graph
) {
if (Objects.equals(parent.getContext().get("allowDeleteActive"), true)) {
Map<String, Object> context = new HashMap<>(parent.getContext());
context.put("remainingEnabledServerGroups", parent.getContext().get("shrinkToSize"));
context.put("preferLargerOverNewer", parent.getContext().get("retainLargerOverNewer"));
context.put("continueIfClusterNotFound", Objects.equals(parent.getContext().get("shrinkToSize"), 0));

// We don't want the key propagated if interestingHealthProviderNames isn't defined, since this prevents
// health providers from the stage's 'determineHealthProviders' task to be added to the context.
if (parent.getContext().get("interestingHealthProviderNames") != null) {
context.put("interestingHealthProviderNames", parent.getContext().get("interestingHealthProviderNames"));
}

graph.add((it) -> {
it.setType(disableClusterStage.getType());
it.setName("disableCluster");
it.setContext(context);
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
* limitations under the License.
*/


package com.netflix.spinnaker.orca.clouddriver.pipeline.providers.aws

import javax.annotation.Nonnull
import com.netflix.spinnaker.kork.core.RetrySupport
import com.netflix.spinnaker.orca.clouddriver.FeaturesService
import com.netflix.spinnaker.orca.clouddriver.OortService
Expand All @@ -25,14 +25,11 @@ import com.netflix.spinnaker.orca.clouddriver.tasks.MonitorKatoTask
import com.netflix.spinnaker.orca.clouddriver.tasks.servergroup.ServerGroupCacheForceRefreshTask
import com.netflix.spinnaker.orca.pipeline.StageDefinitionBuilder
import com.netflix.spinnaker.orca.pipeline.TaskNode
import com.netflix.spinnaker.orca.pipeline.graph.StageGraphBuilder
import com.netflix.spinnaker.orca.pipeline.model.Stage
import com.netflix.spinnaker.orca.pipeline.model.SyntheticStageOwner
import groovy.util.logging.Slf4j
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component

import javax.annotation.Nonnull

import static com.netflix.spinnaker.orca.clouddriver.tasks.servergroup.PinnedServerGroupTagGenerator.PINNED_CAPACITY_TAG

/**
Expand Down Expand Up @@ -67,31 +64,26 @@ class ApplySourceServerGroupCapacityStage implements StageDefinitionBuilder {
}

@Override
List<Stage> afterStages(@Nonnull Stage stage) {
void afterStages(@Nonnull Stage stage, @Nonnull StageGraphBuilder graph) {
try {
def taggingEnabled = featuresService.areEntityTagsAvailable()
if (!taggingEnabled) {
return []
return
}

def entityTags = fetchEntityTags(oortService, retrySupport, stage)?.getAt(0)
if (!entityTags) {
return []
return
}

return [
newStage(
stage.execution,
deleteEntityTagsStage.type,
"Cleanup Server Group Tags",
[
id : entityTags.id,
tags: Collections.singletonList(PINNED_CAPACITY_TAG)
],
stage,
SyntheticStageOwner.STAGE_AFTER
)
]
graph.add {
it.type = deleteEntityTagsStage.type
it.name = "Cleanup Server Group Tags"
it.context = [
id : entityTags.id,
tags: Collections.singletonList(PINNED_CAPACITY_TAG)
]
}
} catch (Exception e) {
log.error(
"Unable to determine whether server group is pinned (serverGroup: {}, account: {}, region: {})",
Expand All @@ -102,7 +94,6 @@ class ApplySourceServerGroupCapacityStage implements StageDefinitionBuilder {
)

// any false negatives (pinned server groups that were not detected) will be caught by the RestorePinnedServerGroupsAgent
return []
}
}

Expand Down
Loading

0 comments on commit 7e843cd

Please sign in to comment.