in src/riff-raff-yaml-file/index.ts [210:303]
constructor(app: App) {
this.allCdkStacks = app.node.findAll().filter((_) => _ instanceof GuStack) as GuStack[];
const allowedStages = new Set(this.allCdkStacks.map(({ stage }) => stage));
this.allStageTags = Array.from(allowedStages);
this.allStackTags = Array.from(new Set(this.allCdkStacks.map(({ stack }) => stack)));
this.allRegions = Array.from(new Set(this.allCdkStacks.map(({ region }) => region)));
this.validateStacksInApp();
this.validateAllRegionsAreResolved();
this.outdir = app.outdir;
const deployments = new Map<RiffRaffDeploymentName, RiffRaffDeploymentProps>();
const groupedStacks: GroupedCdkStacks = groupByClassNameStackRegionStage(this.allCdkStacks);
Object.values(groupedStacks).forEach((stackTagGroup) => {
Object.values(stackTagGroup).forEach((regionGroup) => {
Object.values(regionGroup).forEach((stageGroup) => {
const stacks: GuStack[] = Object.values(stageGroup).flat();
// The items in `stacks` only differ by stage, so we can just use the first item in the list.
const [stack] = stacks;
if (!stack) {
throw new Error("Unable to produce a working riff-raff.yaml file; there are no stacks!");
}
const lambdas = this.getLambdas(stack);
const autoscalingGroups = this.getAutoScalingGroups(stack);
const artifactUploads: RiffRaffDeployment[] = [
lambdas.filter((_) => !_.withoutArtifactUpload).map(uploadLambdaArtifact),
autoscalingGroups.map(uploadAutoscalingArtifact),
].flat();
artifactUploads.forEach(({ name, props }) => deployments.set(name, props));
const parentStacks: RiffRaffDeployment[] = this.getGuStackDependencies(stack).map((x) =>
cloudFormationDeployment([x], [], this.outdir),
);
const cfnDeployment = cloudFormationDeployment(stacks, [...artifactUploads, ...parentStacks], this.outdir);
deployments.set(cfnDeployment.name, cfnDeployment.props);
const lambdasWithoutAnAlias = lambdas.filter((lambda) => lambda.alias === undefined);
// If the Lambda has an alias it is using versioning. When using versioning, there is no need for Riff-Raff
// to modify the unpublished version of the function
lambdasWithoutAnAlias.forEach((lambda) => {
const lambdaDeployment = updateLambdaDeployment(lambda, cfnDeployment);
deployments.set(lambdaDeployment.name, lambdaDeployment.props);
});
/*
Instances in an ASG with an `AutoScalingRollingUpdate` update policy are rotated via CloudFormation.
Therefore, they do not need to also perform an `autoscaling` deployment via Riff-Raff.
*/
const legacyAutoscalingGroups = autoscalingGroups.filter((asg) => {
const { cfnOptions } = asg.node.defaultChild as CfnAutoScalingGroup;
const { updatePolicy } = cfnOptions;
return updatePolicy?.autoScalingRollingUpdate === undefined;
});
legacyAutoscalingGroups.forEach((asg) => {
const asgDeployment = autoscalingDeployment(asg, cfnDeployment);
deployments.set(asgDeployment.name, asgDeployment.props);
});
const amiParametersToTags = getAmiParameters(autoscalingGroups);
const minInServiceParamMap = HorizontallyScalingDeploymentProperties.getInstance(stack).asgToParamMap;
const minInServiceAsgs = autoscalingGroups.filter((asg) => minInServiceParamMap.has(asg.node.id));
const minInstancesInServiceParameters = getMinInstancesInServiceParameters(minInServiceAsgs);
deployments.set(cfnDeployment.name, {
...cfnDeployment.props,
parameters: {
...cfnDeployment.props.parameters,
// only add the `amiParametersToTags` property if there are some
...(autoscalingGroups.length > 0 && { amiParametersToTags }),
// only add the `minInstancesInServiceParameters` property if there are some
...(minInServiceAsgs.length > 0 && { minInstancesInServiceParameters }),
},
});
});
});
});
this.riffRaffYaml = {
allowedStages,
deployments,
};
}