DependsOn with if else statement in cloudforamtion yml template - amazon-web-services

Hi i have 2 AWS::ElasticLoadBalancingV2::Listener name Listener1 and Listener2. I have a condition in which either listner1 is deployed or listner1
I have created a ecs service which i want to be depended on Listener.
Service:
Type: AWS::ECS::Service
DependsOn: !If [Condition, Listener1, Listener2]
Properties:
When deployed its giving me error Template format error: DependsOn must be a string or list of strings.

Sadly, you can't do the following:
DependsOn: !If [Condition, Listener1, Listener2]
As the error message says, DependsOn takes only a string value or a list of strings, not a function, e.g:
DependsOn: [SomeExistingResource1, SomeExistingResource2]
Also Fn::If can only be used in metadata attribute, update policy attribute, and property values. From docs:
Currently, AWS CloudFormation supports the Fn::If intrinsic function in the metadata attribute, update policy attribute, and property values in the Resources section and Outputs sections of a template.
Thus you can't use Fn::If in DependsOn.

Related

AWS Cloudformation: Outputs ServiceName for Unnamed ECS Service

I create ECS stack via cloudformation. Everything works fine.
Due to a certain reason, I do not specify ServiceName for ECS service (Name: Service) in definition.
However, I want to have it in outputs, after Cloudformation creates the stack.
So for this purpose, I defined outputs like this:
Outputs:
ECSServiceName:
Description: Service Name I want to see
Value: !GetAtt Service.ServiceName
When I run update CF Stack, I receive an error from AWS:
Requested attribute ServiceName must be a readonly property in schema for AWS::ECS::Service
Does this mean that I cannot receive it in outputs, if it wasn't strictly specified before? Or I made a mistake somewhere in Outputs definition?
You have to export ECSServiceName from your template. Also the correct way to get ECS service name is !GetAtt Service.Name:
Outputs:
ECSServiceName:
Description: Service Name I want to see
Value: !GetAtt Service.Name
Export:
Name: ECSServiceName
Then, in other templates, you can use ImportValue to reference the exported output:
!ImportValue ECSClusterName

How to pass parameters to a cloudformation template which is embedded inside serverless.yaml file

I have a cloudformation template that I would like to embed in the resources section but the existing cloudformation template contains parameters. Is it possible to handle this?
resources: Resources: ${file(cloudformation-resources.yaml)}
I am trying to create IAM roles and Lambda functions using the template. and the template takes the environment name, security groupId, bucket name where the lambda code resides as passing as parameters. and I am using !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/ to get the log group inside the template.
But I am ending up with an error " Invalid variable reference syntax for variable AWS::Region. You can only reference env vars, options, & files. You can check our docs for more info."
How can I handle this using serverless.yaml file.
Here is the serverless.yaml which i am trying
service: sample
frameworkVersion: ">=1.0.0 <2.0.0"
plugins:
- serverless-pseudo-parameters
provider:
name: aws
stackName: "${opt:stackName,env:StackName}"
parameters:
SecurityGroupId: "${opt:SecurityGroupId,env:SecurityGroupId}"
Subnets: "${opt:Subnets,env:Subnets}"
environment: "${opt:environment,env:environment}"
LambdacodeBucketName: "${opt:LambdacodeBucketName,env:LambdacodeBucketName}"
resources:
- ${file(test/template.yaml)}
Thanks in advance

Default value AWS replace with pseudo parameter reference

I have a parameter in an aws cloudformation template
Parameters:
ExecRole:
Type: String
Description: Required. Lambda exec role ARN
Default: arn:aws:iam::123456789:role/lambdaExecRole
Assuming the 123456789 is the AcountId I want to use the pseudo parameter reference but I cannot do it, I try the followings without success
Default: arn:aws:iam::!Ref{AWS::AccountId}:role/exLambdaExecRole
Default: !Sub 'arn:aws:iam::${AWS::AccountId}:role/exLambdaExecRole'
In the last case is throwing me an error
Default member must be a string.
It seems like functions (ex. !Sub) are not supported in default values of Parameters.
Here's a workaround we're using.
We have a separate stack called Parameters which exports whatever parameters needed in other stacks. For instance:
Outputs:
VpcId:
Description: Id of the VPC.
Value: !Ref VpcId
Export:
Name: !Sub 'stk-${EnvType}-${EnvId}-VpcId'
In other stacks we simply import these exported values:
VpcId: !ImportValue
'Fn::Sub': 'stk-${EnvType}-${EnvId}-VpcId'
EnvType and EnvId are the same for all the stacks of one environment.
With roles you might want to do the following. Create a separate Roles template, implement your roles there and export their ARNs:
Outputs:
LambdaExecutionRoleArn:
Description: ARN of the execution role for the log-and-pass function.
Value: !GetAtt
- LambdaExecutionRole
- Arn
Export:
Name: !Sub 'stk-${EnvType}-${EnvId}-roles-LambdaExecutionRole-Arn'
Again, in other stack you could simply ImportValue:
Role: !ImportValue
'Fn::Sub': 'stk-${EnvType}-${EnvId}-roles-LogAndPassFunctionExecutionRole-Arn'
Assuming this will always be role, why can't you as a parameter ask for the nae to be passed in then use the Sub intrinsic function to replace in the Resources section of your CloudFormation template.
That way your arn:aws:iam::${AWS::AccountId}:role part of the arn would not need to be part of the parameter.

AWS Athena deployment serverless framework

has somebody a hint how I have to transform !Ref und !Sub from CloudFormation into serverless.yml.
resources:
Resources:
AthenaCreateDatabaseQuery:
Type: 'AWS::Athena::NamedQuery'
Properties:
Description: Run this query to initialize the Athena database
QueryString: "CREATE DATABASE IF NOT EXISTS $(self:custom.etlDatabase};"
Database: ${self:custom.etlDataBase}
In Cloudformation the QueryString Property starts with !Sub and
the Database Property with !Ref.
Thanks Christian
!Sub isn't currently supported natively by serverless.com (see this issue on GitHub) but you can use the following plugin https://gitlab.com/kabo/serverless-cf-vars
Whenever you want the cloudformation template to have a string that contains ${}, simply use #{} instead, and it will get transformed into correct ${} (with Fn::Sub inserted for you) in the cloudformation template before deployment.
Or use a custom variable syntax as suggested here. Both require the use of Fn::Sub and Fn::Ref in yaml instead of the short form !Sub and !Ref

Add a Condition that gets attributes from a custom resource

I have one CFT that creates an EBS volume. Then I have a second CFT that attaches the volume to the instance. I use a Custom Resource which runs a lambda to find the EbsVolumeId and the InstanceId
The 2 CFT's are part of a jenkins pipeline and its possible that the playbook that uses the CFT to create the EBS volume can be skipped and thus there is no EbsVolumeId to reference.
So in the CFT that attaches the EBS volume, I tried adding a Condition
Resources:
MountPoint:
Type: AWS::EC2::VolumeAttachment
Condition: AttachEBS
Properties:
InstanceId: !GetAtt SCSHelper.InstanceId
VolumeId: !GetAtt SCSHelper.EbsVolumeId
The custom resource looks like
SCSHelper:
Type: Custom::SCSHelper
So I have to define the condition before the resources:
Conditions:
AttachEBS: !Not [!Equals http:// !GetAtt SCSHelper.EbsVolumeId , None ]
The problem is the Conditions is failing with:
An error occurred (ValidationError) when calling the CreateStack operation: Template format error: Unresolved dependencies https://forums.aws.amazon.com/. Cannot reference resources in the Conditions block of the template An error occurred (ValidationError) when calling the CreateStack operation: Template format error: Unresolved dependencies https://forums.aws.amazon.com/.
So it appears that the SCSHelper.EbsVolumeId attribute is not available for the condition to use.
Is there a way to make this work or is there a better way to conditionally run the CFT that attaches the EBS volume?
Thanks in advance...
The important section of the Conditions documentation is this
Parameters
Define the input values that you want to evaluate in your conditions. Conditions will result in true or false based on values from these input parameters.
Conditions in CloudFormation can be based on Parameters alone. They can't take in-flight resource values into account, as these values aren't known at compile time.