I know that I can export values of some stacks via Cross Stack References. I also know that it's possible to reuse some code using Nested Stacks.
How can I have a template routing-server.yml and ws-server.yml and import (OR compose them in) env-staging.yml?
Look at the reference architecture of the awslabs/ecs-refarch-cloudformation Github repository, it uses nested stacks.
Resources:
VPC:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: https://s3.amazonaws.com/ecs-refarch-cloudformation/infrastructure/vpc.yaml
Parameters:
EnvironmentName: !Ref AWS::StackName
VpcCIDR: 10.180.0.0/16
PublicSubnet1CIDR: 10.180.8.0/21
PublicSubnet2CIDR: 10.180.16.0/21
PrivateSubnet1CIDR: 10.180.24.0/21
PrivateSubnet2CIDR: 10.180.32.0/21
https://github.com/awslabs/ecs-refarch-cloudformation
Related
I have a Cloudformation stack that conditionally invokes a nested stack to create a RDS instance, only if an existing database URL is not passed in as a parameter.
If I pass a value to the DBExistingEndpoint parameter in the stack, the condition CreateDB is set to false, and it will not invoke the nested RDS stack at all.
The issue is that in the AutoScaling launch config resource, there is a conditional dependency. I need to reference either the URL output from the nested stack, or the URL passed in as a parameter to place in a file in the newly launched instance.
Parameters:
DBExistingEndpoint:
Type: String
Description: Set to a URL of a RDS instance to use an existing DB, otherwise create one
Default: ''
...
Conditions:
CreateDB:
!Equals [!Ref DBExistingEndpoint, '']
...
Resources:
# Database created only if existing URL not passed in
DB:
Type: AWS::CloudFormation::Stack
Condition: CreateDB
Properties:
TemplateURL: ...
...
ClusterInstanceLaunchConfig:
Type: AWS::AutoScaling::LaunchConfiguration
Metadata:
AWS::CloudFormation::Init:
config:
files:
/etc/dbenv:
mode: "000640"
owner: root
group: root
content:
!Join
- "\n"
-
- !Sub ["DB_HOST=${DBEndpointAddress}", DBEndpointAddress: !If [CreateDB, !GetAtt DB.Outputs.RDSEndPointAddress, !Ref DBExistingEndpoint]]
...
The issue is that if I pass in an existing endpoint URL, the DB resource is skipped (correctly), but the stack creation fails with Template format error: Unresolved resource dependencies [DB] in the Resources block of the template
Ideally the DB.output.RDSEndpointAddress reference in the ClusterInstanceLauchConfig resource should be ignored because the CreateDB condition in the !If is false
Does anybody know how to code around this limitation?
You should try to set the conditional statement on a different level than it is now.
What will work for sure, is having the conditional statement on the level of the LaunchConfiguration itself, which would also mean quite a lot of duplication of the code. But maybe you could try to see the conditional on the level of content or files etc, to see if there's a middle ground somewhere, to keep duplication low, but avoid the error you're getting right now.
I have a template that includes 3 resources. Is there a way to programmatically exclude 1 of the 3 resources by using a Parameter of my template?
(that is having the same result that i would get by commenting out the unwanted resource in my template)
It depends. Since you haven't specified any template, I can only show what I usually do.
Parameters:
SubnetId:
Type: String
Default: ''
Conditions:
HaveSubnetId:
!Not [!Equals [!Ref SubnetId, '']]
Resources:
MyInstance:
Condition: HaveSubnetId
Type: AWS::EC2::Instance
In this example, MyInstance is going to be created if SubnetId is given (i.e., not empty). If SubnetId is provided, HaveSubnetId will be true.
This is based on Condition section in a resource declaration.
I am building a large application that has "static" resources (API, lambda LayerVersions, DynamoDB table etc) and "dynamic" resources (Lambda functions, Batch and SQS queues).
To neatly arrange this, I created multiple template files with some referring to others using SAM's AWS::Serverless::Application type.
In some of the "modules" (1 level deep nested stacks) I have lambdas that act as lambda proxies, and the API that they integrate with is declared in the StaticResourcesModule nested stack.
However these lambda need AWS::Serverless::Api's RestApiId property to know to which event to respond to.
The circular dependency happens because the Swagger 2.0 template that defines the AWS::Serverless::Api in the first place needs the Lambda's ARN (or lambda function's name and account number) to know which lambda implement what method (x-amazon-apigateway-integration 's uri attribute)
How can I pass to the API a reference to the lambda when the lambda themselves need a reference to the API's RestApiId property and both are in different stacks ?
The top level YAML template file looks like this:
Resources:
StaticResourcesModule:
Type: AWS::Serverless::Application
Properties:
Location: static_resources_module/template.yaml
DataFetchingModule:
Type: AWS::Serverless::Application
Properties:
Location: datafetching_module/template.yaml
Parameters:
MainApiId: !GetAtt StaticResourcesModule.Outputs.MainApiId
datafetching_module/template.yaml :
Parameters:
MainApiId:
Type: String
Description: >
Reference to the main api (AWS::Serverless::Api) resource.
Resources:
FetchingRequestsHandler:
Type: AWS::Serverless::Function
Description: Handles incoming requests [...]
Properties:
[...]
Events:
ApiPostNewRequestEvent:
Type: Api
Properties:
Method: post
Path: /fetching/low-priority
RestApiId: !Ref MainApiId
static_resources_module/template.yaml:
Parameters:
FetchingRequestsHandlerArn:
Type: String
Resources:
MainApi:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
DefinitionUri: api/swagger2_template.yaml
Outputs:
MainApiId:
Value: !Ref MainApi
Description: The Main API's RestApiId which to provide to the Lambda that require an API Event (lambda proxy)
api/swagger2_template.yaml:
/fetching/low-priority:
post:
# API integration, necessary.
x-amazon-apigateway-integration:
uri:
Fn::Sub: "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${FetchingRequestsHandlerArn}/invocations"
Does anyone know if SAM templates support Lifecycleconfigruation settings? I see within standard cloudformation definitions you can define the lifecycle of objects like:
BucketName: "Mys3Bucket"
LifecycleConfiguration:
Rules:
- AbortIncompleteMultipartUpload:
DaysAfterInitiation: 7
Status: Enabled
- ExpirationInDays: 14
...
But this seems to fail when used in a SAM template. Am I doing something wrong or is this not part of the serverless application model definition?
It works for me using the SAM CLI 1.15.0, although documentation seems sparse (hence my landing on this question while trying to figure it out).
The SAM template snippet below successfully creates a bucket and sets an appropriate lifecycle rule.
Resources:
Bucket1:
Type: 'AWS::S3::Bucket'
Properties:
BucketName: !Sub "${BucketName}"
AccessControl: Private
VersioningConfiguration:
Status: Enabled
LifecycleConfiguration:
Rules:
- ExpirationInDays: 6
Status: Enabled
I have created a nested IAM stack, which constists of 3 templates:
- iam-policies
- iam-roles
-iam user/groups
the masterstack template looks like this:
Resources:
Policies:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: https://s3.amazonaws.com/xxx/iam/iam_policies.yaml
UserGroups:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: https://s3.amazonaws.com/xxx/iam/iam_user_groups.yaml
Roles:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: https://s3.amazonaws.com/xxx/iam/iam_roles.yaml
The policy ARNs are exported via Outputs section like:
Outputs:
StackName:
Description: Name of the Stack
Value: !Ref AWS::StackName
CodeBuildServiceRolePolicy:
Description: ARN of the managed policy
Value: !Ref CodeBuildServiceRolePolicy
in the Role template the policies ARNs are imported like
CodeBuildRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub ${EnvironmentName}-CodeBuildRole
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Action:
- 'sts:AssumeRole'
Effect: Allow
Principal:
Service:
- codebuild.amazonaws.com
Path: /
ManagedPolicyArns:
- !GetAtt
- Policies
- Outputs.CodeBuildServiceRolePolicy
But when I try create the stack, it fails saying the Roles stack cannot be created because
Template error: instance of Fn::GetAtt references undefined resource Policies
How can I force the creation of the policies first so the second and third template can use the policies to create roles and user/ groups? Or is the issue elsewhere?
merci A
Your question,
How can I force the creation of the policies first so the second and
third template can use the policies to create roles and user/ groups?
Or is the issue elsewhere?
You can use "DependsOn" attribute. It automatically determines which resources in a template can be parallelized and which have dependencies that require other operations to finish first. You can use DependsOn to explicitly specify dependencies, which overrides the default parallelism and directs CloudFormation to operate on those resources in a specified order.
In your case second and third template DependsOn Policies
More details : DependsOn
The reason on why you aren't able to access the outputs is that, you haven't exposed the outputs for other stacks.
Update your Outputs with the data you want to export. Ref - Outputs for the same.
Then, use the function Fn::ImportValue in the dependent stacks to consume the required data. Ref - ImportValue for the same.
Hope this helps.