AWS Cloudformation: Outputs ServiceName for Unnamed ECS Service - amazon-web-services

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

Related

Expose SNSTopic TopicArn in AWS CloudFormation Template: How might I expose my TopicArn in my CloudFormation script for my SNS Topic?

I'd like to expose the TopicArn Value (referenced in the outputs section at the bottom of my code snippet) of my SNStopic via Cloudformation template in the outputs tab of my stack in a similar manner to the way it's exposed in the resources when I create an SNStopic through the service catalog. I tried to access it by referencing it in the outputs section of my yaml script using dot notation but have been unsuccessful thus far. How might I be able to do so? I'm looking to do this so others using my script in the future won't have to go searching for the TopicArn in another place in order to subscribe to it.
Another important thing to note is that the provisioned product id below, under the properties section of the resources code block generates an SNSTopic.
Resources:
LabTrainingSnsTopic:
Type: "AWS::ServiceCatalog::CloudFormationProvisionedProduct"
Properties:
ProductId: prod-4iafsjovqrsrm # Sns Topic
ProvisioningArtifactName: "v1.1" # Must be an actual version number.
ProvisionedProductName: !Ref ProvisionedProductName
...
Outputs:
AccountID:
Description: The account in which this was built.
Value: !Ref 'AWS::AccountId'
TopicArn:
Description: Arn of the topic we created
Value: !GetAtt LabTrainingHigSnsTopic.ProvisionedProductName.Resources.SNSTopic
service catalog screenshot
cloudformation screenshot

Referencing an EC2 instance's name tag in AWS CloudFormation without parameterization

I have a CloudFormation stack that creates an EC2 instance and gives it a name tag.
I want to create a CloudWatch alarm, and reference the EC2 instance's name in the alarm's name - something like AlarmName: !Sub "Status Check Alarm - ${EC2InstanceName}".
!Ref will allow me to reference the CloudFormation script's parameters, but I don't want to parameterize the EC2 instance name - I don't want or need that to be customizable, and I don't want users to have the ability to choose a custom name for the server.
I tried outputting the EC2 instance name so I could !Ref that, but I got an Invalid template resource property 'Outputs' error, so I don't know if my approach even works:
EC2Instance:
Properties: ...
Type: AWS::EC2::Instance
Outputs:
EC2InstanceName:
Description: The server's name.
Value: !GetAtt EC2Instance.Tags.Name
Export:
Name: "EC2InstanceName"
How do I reference the EC2 instance's name without parameterizing the name at the top-level of the script?
EDIT:
I ended up using parameters anyway so I could !Ref them. I guess you could also set up an "allowed values" list containing only a single value that matches the default. It's lame but it works, I guess.
Parameters:
EC2InstanceName:
Type: String
Default: "web-server-blah"
Description: The name of the EC2 instance.
You can use !GetAtt only for attributes which are specifically named in the documentation https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html
Tags are not among them.
But if you provide a different tag for your instance, then you can refer it without even exporting it (providing that it is a constant value).
I see what you are trying to do, but AWS does not support everything you would like to work out of the box. One way how I imagine it can be done - and you may not like it - is either via a macro or a custom resource (lambda function).
Can't use just use !Ref EC2Instance? I realize it won't be the friendly "Name" tag value, but it could be more useful, especially if you have duplicates of the same "Name". It would make your alarm be something like "Status Check Alarm - i-123456789".
Whereas if you use the name it might be something more like 10 alarms that read "Status Check Alarm - WWWServer", but now which WWWServer?

How to reference Cloudformation Ressources in a new Cloudformation template?

I have two Cloudformation files and I want to reference already created Ressources from one template, in another template. For Example: In the first one I create an ECS Cluster. In the second one I want to reference this cluster and build a Service in it. How can I do it?
To do this you have to exporting stack output values from the first template. Presumably this would be ECS Cluster name and/or its arn:
MyCluster:
Type: AWS::ECS::Cluster
Properties:
#....
Outputs:
MyClusterName:
Value: !Ref MyCluster
Export:
Name: ECSClusterName
Then in the second template you would use ImportValue to reference the exported output:
MyESSService:
Type: AWS::ECS::Service
Properties:
Cluster: !ImportValue ECSClusterName

DependsOn with if else statement in cloudforamtion yml template

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.

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.