Updating an AWS::EC2::EIPAssociation via change set - amazon-web-services

I keep running into the following error when attempting to update an EIPAssociation via a change set:
Interface: [eni-04740b9f34d1d75dc] in use. (Service: AmazonEC2; Status Code: 400; Error Code: InvalidNetworkInterface.InUse; Request ID: 3bfa13f2-abe5-4bb5-80aa-183605d3dfde)
Basically, I changed my resource to reference a value passed in as a parameter instead of an EIP that is created in the same CFT.
Old:
"EIPAssociation": {
"Type": "AWS::EC2::EIPAssociation",
"Properties": {
"AllocationId": {
"Fn::GetAtt": [
"EIP",
"AllocationId"
]
},
"NetworkInterfaceId": {
"Ref": "NetworkInterface"
}
},
"DependsOn": "EC2Instance"
},
New:
"EIPAssociation": {
"Type": "AWS::EC2::EIPAssociation",
"Properties": {
"AllocationId": {
"Ref": "EIPAllocationID"
},
"NetworkInterfaceId": {
"Ref": "NetworkInterface"
}
},
"DependsOn": "EC2Instance"
},
In both cases, "NetworkInterface" is created within the CFT while in the first example "EIP" is created within the CFT and the second example "EIPAllocationID" is passed into the CFT as a parameter. I can log into the console, unassociate the old EIP and associate the new one no problem. But when I attempt to do these via change set I get the annoying ENI in use error. Happens whether the instance is on or off.
Any idea how I proceed with this or what I am doing incorrectly?

Related

How do I successfully retrieve an ALB ListenerArn with CloudFormation to setup ListenerRules?

I'm starting to think there is a fundamental flaw in AWS Cloudformation Template validation/resource lookup related to "Type": "AWS::ElasticLoadBalancingV2::ListenerRule", resources.
Specifically, every time I try to create a new ListenerRule for known working Listeners, Cloudformation errors out with
Unable to retrieve ListenerArn attribute for AWS::ElasticLoadBalancingV2::Listener, with error message One or more listeners not found (Service: ElasticLoadBalancingV2, Status Code: 400, Request ID: c6914f71-074c-4367-983a-bcf1d8fd1350, Extended Request ID: null)
Upon testing, I can make it work by hardcoding the ListenArn attribute in my template, but that's not a solution since the template is used for multiple Stacks with different resources.
Below are the relevant parts of the template:
"WLBListenerHttp": {
"Type": "AWS::ElasticLoadBalancingV2::Listener",
"Properties": {
"DefaultActions": [{
"Type": "forward",
"TargetGroupArn": { "Ref": "WLBTargetGroupHttp" }
}],
"LoadBalancerArn": { "Ref": "WebLoadBalancer" },
"Port": 80,
"Protocol": "HTTP"
}
},
"ListenerRuleHttp": {
"DependsOn": "WLBListenerHttp",
"Type": "AWS::ElasticLoadBalancingV2::ListenerRule",
"Properties": {
"Actions": [{
"Type": "fixed-response",
"FixedResponseConfig": { "StatusCode": "200" }
}],
"Conditions": [{
"Field": "host-header",
"HostHeaderConfig": { "Values": ["domain*"] }
}, {
"Field": "path-pattern",
"PathPatternConfig": { "Values": ["/path/to/respond/to"] }
}],
"ListenerArn": { "Fn::GetAtt": ["WLBListenerHttp", "ListenerArn"] },
"Priority": 1
}
},
Per the documentation on listeners, Fn::GetAtt or Ref should both return the ListenerARN:
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticloadbalancingv2-listener.html
"Return values
Ref
When you pass the logical ID of this resource to the intrinsic Ref function, Ref returns the Amazon Resource Name (ARN) of the listener.
For more information about using the Ref function, see Ref.
Fn::GetAtt
The Fn::GetAtt intrinsic function returns a value for a specified attribute of this type. The following are the available attributes and sample return values.
For more information about using the Fn::GetAtt intrinsic function, see Fn::GetAtt.
ListenerArn
The Amazon Resource Name (ARN) of the listener."
I've tried both "ListenerArn": { "Fn::GetAtt": ["WLBListenerHttp", "ListenerArn"] }, and "ListenerArn": { "Ref": "WLBListenerHttp"}, with no success, resulting in the error noted. If I hardcode the Arn "ListenerArn": "arn::", with the full Arn, it works fine.
As it turns out, my syntax was perfectly fine. However, what I didn't realize is that while the WLBListenerHttp resource existed, it was not actually the same ARN as the one created by CloudFormation. Apparently, someone accidentally deleted it at some point without telling us and then manually recreated it. This left the account in a broken state where CloudFormation had an ARN recorded for the listener from when it was created, but it was truly no longer valid since the new resource had a new ARN.
The solution to this was to delete the offending resource manually, then change the name of it slightly in our CloudFormation templates so it would create a new one.

Can you set a Route53 Resource Record as the IP of an EC2 instance in the same cloudformation script?

I have a cloudformation script that makes an EC2 instance and sets up some alarms. I would like to add a Route53 record for this instance in the same cloudformation, but I am having trouble figuring out what to put for the Resource Record field. Is there a way to reference the newly created EC2 instance's IP address for the ResourceRecord field of the AWS::Route53::RecordSetGroup?
I have already tried to use "ResourceRecords":"EC2Instance" but that got me "Encountered unsupported property Type." I don't know how else to accomplish this outside of manually setting the DNS entry after creation, but I would like to do it in one step so it is done automatically.
Here is what I have:
"Resources": {
"EC2Instance": {
"Type": "AWS::EC2::Instance",
"Properties": {"ImageId": {
"Ref": "AMI"
},
"IamInstanceProfile": {
"Ref": "InstanceProfile"
},
"InstanceType": {
"Ref": "InstanceSize"
},
"BlockDeviceMappings": [{
"DeviceName": "/dev/xvda",
"Ebs": {
"Encrypted": true,
"VolumeSize": 100,
"DeleteOnTermination": false
}
}]
}
},
"DNS": {
"Type": "AWS::Route53::RecordSetGroup",
"Properties": {
"HostedZoneName": {"Ref": "HostedZoneName"},
"Comment": "Alias Record",
"ResourceRecords":"EC2Instance",
"Type": "A",
"Name": {"Fn::Join" : ["",[{"Ref": "ComponentDNSName"},{"Ref": "HostedZoneName"}]]}
}
}
},
I would expect there would be someway to find the newly created IP for the EC2 instance, but I am not sure how. I am thinking I have to use an elastic IP, but I still do not know how to reference that. Thanks for any help or suggestions.
From AWS::EC2::Instance - AWS CloudFormation:
Fn::GetAtt
The Fn::GetAtt intrinsic function returns a value for a specified attribute of this type. The following are the available attributes and sample return values.
PrivateIp
The private IP address of the specified instance. For example: 10.24.34.0.
So, it would be something like:
{ "Fn::GetAtt" : [ "EC2Instance", "PrivateIp" ] }

AWS Nested Stacks - Referencing a Parent Stack's Resource

I'm trying to pass resources (ApiGatewayRestApi and a custom authorizer) to a nested stack through stack parameters, however, they continually fail with Embedded stack <stack_name> was not successfully created: The following resource(s) failed to create. Here's my set up in Serverless:
Parent Stack
{
...
"NestedStack": {
"Type": "AWS::CloudFormation::Stack",
"Properties": {
"Parameters": {
"ServerlessDeploymentBucket": {
"Ref": "ServerlessDeploymentBucket"
},
"ApiGatewayRestApi": {
"Ref": "ApiGatewayRestApi"
},
"AuthDashjwtApiGatewayAuthorizer": {
"Ref": "AuthDashjwtApiGatewayAuthorizer"
},
},
"TemplateURL": "..."
}
},
}
Nested Stack
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "Nested Stack",
"Parameters": {
"ServerlessDeploymentBucket": { "Type": "String" },
"ApiGatewayRestApi": {
"Description": "Rest API",
"Type": "String"
},
"AuthDashjwtApiGatewayAuthorizer": { "Type": "String" },
},
"Resources": {
"ApiGatewayMethodEventsEventidVarStreamsPost": {
"Type": "AWS::ApiGateway::Method",
"Properties": {
"HttpMethod": "POST",
"RequestParameters": {},
"ResourceId": { "Ref": "ApiGatewayResourceEventsEventidVarStreams" },
"RestApiId": { "Ref": "ApiGatewayRestApi" },
"AuthorizationType": "CUSTOM",
"AuthorizerId": { "Ref": "AuthDashjwtApiGatewayAuthorizer" },
...
}
...
}
...
}
Am I not referencing or passing in parameters correctly?
Update based on comments
Unless I'm missing something, the only error message in the CF section of the console is:
Embedded stack <stac_name> was not successfully created: The
following resource(s) failed to create: [PatchDasheventLogGroup,
PostDashstreamLogGroup, GetDashstreamsLogGroup, GetDasheventsLogGroup,
ApiGatewayRestApi, GetDasheventLogGroup, PostDasheventLogGroup,
AuthDashjwtApiGatewayAuthorizer]
as far as log groups go, they look like this:
"GetDasheventLogGroup": {
"Type": "AWS::Logs::LogGroup",
"Properties": {
"LogGroupName": "/aws/lambda/live-api-local-get-event"
}
}
Update 2
The log group issue was due to these logs being moved from the parent stack to the nested stack and needing a new name. In the LogGroup docs I found:
If you specify a name, you cannot perform updates that require replacement of this resource. You can perform updates that require no or some interruption. If you must replace the resource, specify a new name.
This looks like it may have solved the issue... Some more testing is needed to confirm!
The comment from #speshak eventually lead me to the answer. I didn't need to filter by Failed state, but rather Deleted. This allowed me to see the logs for the nested stack that was created, then deleted with more specific messaging.
What this ended up showing me is that the update-stack process was applying the nested stacks to my current set up before removing all the resources from, what would become, the root stack. So the true problem was that I was accidentally trying to create duplicate resources -- AWS saw a resource in a nested stack that matched the root stack, and kicked out with a validation error even though the resource would have been removed from the root stack... eventually.

AWS Cloudformation failing to acknowledge AutoScalingGroup

While using CloudFormation to create EC2 instance along with an autoscaling group, I face the error:
The following resource(s) failed to create: [WebsInstanceServerGroup].
image of CloudFormation Group output
The failure is seen while creating auto scaling group, but when I check the auto scaling group console, it says that the creation was 'successful.' (The 'in-progress' deletion happens after a 15 minute time out value from CloudFormation).
image of AutoScaling output
What could be the reason CloudFormation is not acknowledging that the AutoScale group is created successfully?
The error also says something about WebInstanceServerGroup, so I checked my template for that, but saw nothing suspicious.
"WebsInstanceServerGroup": {
"Type": "AWS::AutoScaling::AutoScalingGroup",
"Properties": {
"AvailabilityZones": {
"Fn::GetAZs": "AWS::Region"
},
"VPCZoneIdentifier": {
"Ref": "WebsELBSubnetId"
},
"LoadBalancerNames": [
{
"Ref": "WebsELB"
}
],
"LaunchConfigurationName": {
"Ref": "WebsEC2Instance"
},
"Cooldown": 300,
"HealthCheckGracePeriod": 600,
"HealthCheckType": "EC2",
"Tags": [
{
"Key": "Name",
"Value": {
"Ref": "WebsInstanceName"
},
"PropagateAtLaunch": "true"
},
{
"Key": "Service",
"Value": {
"Ref": "ServiceTag"
},
"PropagateAtLaunch": "true"
}
],
"MinSize": {
"Ref": "ASGMin"
},
"DesiredCapacity": {
"Ref": "ASGDesired"
},
"MaxSize": {
"Ref": "ASGMax"
}
},
"CreationPolicy": {
"ResourceSignal": {
"Count": {
"Ref": "ASGMin"
},
"Timeout": "PT15M"
}
}
}
Please let me know if more information is required, thanks in advance.
Looks like your EC2 instances in your autoscaling group are not sending the required success signals.
CloudFormation will wait for you to send ASGMin signals before considering your WebsInstanceServerGroup to be successfully created. So if ASGMin is set to 3, each of your 3 EC2 instances should send a signal.
To send the signal you can either use the cfn-signal helper, or with the AWS CLI:
aws cloudformation signal-resource \
--stack-name {your stack name here} \
--status SUCCESS \
--logical-resource-id WebsInstanceServerGroup \
--unique-id {the instance ID for the EC2 instance that is sending the signal}
Use this command at the end of your User Data script, when you consider your EC2 instance to be fully provisioned and ready to go.

AWS ECS - Unable to specify service name in cloudformation template

I am trying to create a AWS - ECS service using cloudformation template
"service": {
"ServiceName": "XXX",
"Type": "AWS::ECS::Service",
"DependsOn": [
"AutoScalingGroup"
],
"Properties": {
"Cluster": {
"Ref": "ECSCluster"
},
"DesiredCount": "1",
"TaskDefinition": {
"Ref": "taskdefinition"
}
}
},
But I am getting an error.
Failed: Invalid template resource property 'ServiceName'
I had same problem when using Name/serviceName. I can see serviceName is a parameter based on docs. But couldn't figure out why it fails. It works if I don't specify name. But I need to specify name so that I can use the same name in a different system that updates the service.
Could you please help?
This is slightly confusing, but the service name is set by the name of the resource you create. There is no ServiceName or Name property. The following will create an ECS service with the name MyService.
"MyService": {
"Type": "AWS::ECS::Service",
"DependsOn": [
"AutoScalingGroup"
],
"Properties": {
"Cluster": {
"Ref": "ECSCluster"
},
"DesiredCount": "1",
"TaskDefinition": {
"Ref": "taskdefinition"
}
}
}
Obviously if you refer to your service within the CloudFormation template you will also need to update your references.