AWS Cloud Formation error: ElasticMapReduce Cluster failed to stabilize - amazon-web-services

I have been getting this error consistently despite my research telling me that this is an internal-to-Amazon error. I have no idea where to start with this error, or if there is even anything that I can do to help it.
The fact that I have been getting it consistently makes me think that it is something wrong with my script. Here it is:
{
"Description": "Demo pipeline.",
"Resources": {
"s3Demo": {
"Type" : "AWS::S3::Bucket",
"Properties" : {
"BucketName" : "example-dna-demo"
}
},
"s3Access": {
"Type": "AWS::IAM::Role",
"Properties": {
"ManagedPolicyArns": [
"arn:aws:iam::aws:policy/AmazonS3FullAccess"
],
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Principal":{
"Service": "firehose.amazonaws.com"
}
}]
},
"RoleName": "kinesisS3Access"
},
"DependsOn": "s3Demo"
},
"kinesisDemo": {
"Type": "AWS::KinesisFirehose::DeliveryStream",
"Properties": {
"DeliveryStreamName": "Demo-Stream",
"S3DestinationConfiguration": {
"BucketARN" : "arn:aws:s3:::example-dna-demo",
"BufferingHints" : {
"IntervalInSeconds" : 300,
"SizeInMBs" : 5
},
"CompressionFormat" : "UNCOMPRESSED",
"Prefix" : "twitter",
"RoleARN" : { "Fn::GetAtt": [ "s3Access", "Arn" ]}
}
},
"DependsOn": "s3Access"
},
"S3LambdaAccess":{
"Type": "AWS::IAM::Role",
"Properties": {
"ManagedPolicyArns": [
"arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess"
],
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Principal":{
"Service": "lambda.amazonaws.com"
}
}]
},
"RoleName": "lambdaS3Access"
}
},
"LambdaDemo": {
"Type" : "AWS::Lambda::Function",
"Properties" : {
"Code" : {
"S3Bucket" : "example-dna-cloud-formation",
"S3Key" : "lambda_function.py.zip"
},
"Description" : "Looks for S3 writes and loads them into another resource",
"FunctionName" : "DemoLambdaFunction",
"Handler" : "lambda-handler",
"Role" : { "Fn::GetAtt": [ "S3LambdaAccess", "Arn" ]},
"Runtime" : "python2.7"
},
"DependsOn": "S3LambdaAccess"
},
"EMRClusterJobFlowRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Principal":{
"Service": "ec2.amazonaws.com"
}
}]
},
"RoleName": "ClusterRole"
}
},
"EMRServiceRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Principal":{
"Service": "ec2.amazonaws.com"
}
}]
},
"RoleName": "EC2InstanceRole"
}
},
"EMR":{
"Type" : "AWS::EMR::Cluster",
"Properties" : {
"Applications": [
{
"Name" : "Spark"
}
],
"ReleaseLabel": "emr-5.0.0",
"Instances" : {
"CoreInstanceGroup" : {
"BidPrice": 0.06,
"InstanceCount" : 1,
"InstanceType" : "m4.large",
"Market": "SPOT"
},
"MasterInstanceGroup" : {
"BidPrice": 0.06,
"InstanceCount" : 1,
"InstanceType" : "m4.large",
"Market": "SPOT"
}
},
"JobFlowRole" : "EMRClusterJobFlowRole",
"Name" : "DemoEMR",
"ServiceRole" : "EMRServiceRole",
"LogUri":"s3://toyota-dna-cloud-formation/cf-logging"
},
"DependsOn": ["EMRServiceRole", "EMRServiceRole"]
}
}
}
I imagine that you probably couldn't run it because I have a lambda function getting code from an S3 bucket, which I've changed the name of here. I am just learning cloud formation scripts, and I know there is a lot of stuff that I am not doing here, but I just want to build a small thing that works, and then fill it out a little more.
I know that my script worked up until the two IAM Roles and the EMR cluster. Thanks in advance.
EDIT: I specified recent instance versions and chose a ReleaseLabel property. with no luck. Same error.

In my case that was due to missing autoscaling role, called EMR_AutoScaling_DefaultRole.
Once I got it in place via aws emr create-default-roles my cloudformation stack once again started deploying nicely (it was deploying okay just before I added autoscaling stuff in).

It could be that your account has reached the EC2 limit in the region you are trying to deploy to. Have you tried a different region?

So it turns out that there was no default VPC in the region I was running the script in, and that is the reason that my EMR cluster was failing to stabilize.
When I tried running it in a different region, it worked, but because that region DID have a default VPC.

Related

SQS API: sqs:CreateQueue Access to the resource https://sqs.us-east-1.amazonaws.com/ is denied on `amplify push` using Cloudformation

I'm implementing SQS fifo queue. I have to implement i using cloudformation template.
When I do amplify push, I get
Error
API: sqs:CreateQueue Access to the resource https://sqs.us-east-1.amazonaws.com/ is denied
I've added SQS policy followed from aws docs
. Except for accountID, I'm using service in the "Principal" as "sqs.amazonaws.com".
My cloudformation looks like:
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "SQS fifo queue",
"Parameters": {
"env": {
"Type": "String"
}
},
"Resources": {
"QueueExecutionRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"RoleName": {
"Fn::Join": [
"",
[
"queue-exec-role-",
{
"Ref": "env"
}
]
]
},
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "sqs.amazonaws.com"
},
"Action": ["sts:AssumeRole"]
}
]
}
}
},
"SQSPolicy": {
"Type": "AWS::SQS::QueuePolicy",
"Properties": {
"Queues": [{ "Ref": "groupingQueue" }],
"PolicyDocument": {
"Statement": [
{
"Action": ["SQS:SendMessage", "SQS:ReceiveMessage"],
"Effect": "Allow",
"Resource": {
"Fn::GetAtt": ["groupingQueue", "Arn"]
},
"Principal": {
"Service": "sqs.amazonaws.com"
}
}
]
}
}
},
"groupingQueue": {
"Type": "AWS::SQS::Queue",
"Properties": {
"FifoQueue": "true",
"QueueName": {
"Fn::Join": [
"",
[
"grouping-queue-",
{
"Ref": "env"
},
".fifo"
]
]
}
}
}
},
"Outputs": {
"QueueURL": {
"Description": "URL of new Amazon SQS Queue",
"Value": { "Ref": "groupingQueue" }
},
"QueueARN": {
"Description": "ARN of new Amazon SQS Queue",
"Value": { "Fn::GetAtt": ["groupingQueue", "Arn"] }
},
"QueueName": {
"Description": "Name new Amazon SQS Queue",
"Value": { "Fn::GetAtt": ["groupingQueue", "QueueName"] }
}
}
}
I do not want to give AccountID in "Principal", That why used sqs service.
With this exact template, I get access denied on amplify push -y.
I was doing amplify push from server. When I pushed it from my local computer it worked.
Turns out the aws profile I set in server did not have sqs:CreateQueue permissions while my local had the administrator access.
So, I added administrator full access to my server user from console, did amplify push again and it worked smoothly.
PS: you don't need to give administrator permission, you can just give sqs:CreateQueue permission. I did it because I was testing.

CloudFormation Lambda template, Expecting role to be string, when using Ref or GetAtt

When creating my lambda stack I am using a role called LambdaExecutionRole, I am then referencing the ARN through fn::GetAtt
"Role": {"Fn::GetAtt": ["LambdaExecutionRole","Arn"]},
, like the documentation said, I am then given the error saying that the specified resource does not support GetAtt. So I tried with GetAtt, and I am returned:
Properties validation failed for resource GetECLambda with message: #/Code/S3Bucket: failed validation constraint for keyword [pattern] #/Role: expected type: String, found: JSONObject
I also tried with "Role":{ "!Ref" : "LambdaExecutionRole"},
From my understanding one of these should have returned a String and therefore a String would be provided, not a JSON Object. But the issue may be that the String is defined like so: {"The Arn"}, but I am unsure how to avoid that.
The Structure of my lambda and the role are as follows:
{
"AWSTemplateFormatVersion" : "2010-09-09",
"Description" : "Stack to create the get-EC lambda",
"Resources" : {
"LambdaExecutionRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [{ "Effect": "Allow", "Principal": {"Service": ["lambda.amazonaws.com"]}, "Action": ["sts:AssumeRole"] }]
},
"Path": "/",
"Policies": [{
"PolicyName": "root",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [{ "Effect": "Allow", "Action": ["logs:*"], "Resource": "arn:aws:logs:*:*:*" }]
}
}]
}
},
"GetECLambda" : {
"Type" : "AWS::Lambda::Function",
"Properties" : {
"FunctionName": "get-ecs",
"Role":{ "!Ref" : "LambdaExecutionRole"},
"Runtime": "nodejs12.x",
"Code": {
"S3Bucket" : "arn:aws:s3:::flex-fit-lambda-functions-source",
"S3Key": "get-ecs.zip"
}
}
}
}
}
When specifying Cloudformation template in JSON, only this form of calling intrinsic functions is supported:
{ "Fn::GetAtt" : [ "logicalNameOfResource", "attributeName" ] }
!Ref form is only supported for YAML.
So try changing your current call to this in your template:
"Role": { "Fn::GetAtt" : [ "LambdaExecutionRole", "Arn" ] }

API HTTP Gateway lambda integration 'null' in Resource Path

I am setting up an API HTTP Gateway (V2) with lambda integrations via Cloudformation, and everything has been working so far. I have 2 working integrations, but my third integration is not working: Everything looks fine from the API Gateway side (it lists the correct route with a link to the Lambda), but the API endpoint in the lambda is listed as "https://c59boisn2k.execute-api.eu-central-1.amazonaws.com/productionnull". When I try to call the route, it says "Not Found". The odd thing is that I am using the same template for all three integrations.
I was thinking it could be a "dependsOn" issue, but I think I have all the correct dependencies. I tried re-creating the stack from scratch and now two of the three functions say "null" in their URL while the API Gateway still states the correct routes. Can this be a 'dependsOn' problem?
Here's my template for a single integration:
{
"Resources": {
"api": {
"Type": "AWS::ApiGatewayV2::Api",
"Properties": {
"Name": { "Ref": "AWS::StackName" },
"ProtocolType": "HTTP",
"CorsConfiguration": {
"AllowMethods": ["*"],
"AllowOrigins": ["*"]
}
}
},
"stage": {
"Type": "AWS::ApiGatewayV2::Stage",
"Properties": {
"Description": { "Ref": "AWS::StackName" },
"StageName": "production",
"AutoDeploy": true,
"ApiId": { "Ref": "api" },
"AccessLogSettings": {
"DestinationArn": {
"Fn::GetAtt": ["stageLogGroup", "Arn"]
}
}
}
},
"getSignedS3LambdaRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"RoleName": {
"Fn::Sub": "${AWS::StackName}-getSignedS3"
},
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": ["lambda.amazonaws.com"]
},
"Action": ["sts:AssumeRole"]
}
]
},
"Policies": [
{
"PolicyName": "root",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Resource": "arn:aws:logs:*:*:*",
"Action": "logs:*"
},
{
"Effect": "Allow",
"Action": ["s3:*"],
"Resource": ["arn:aws:s3:::euromomo.eu/uploads/*"]
}
]
}
}
]
}
},
"getSignedS3Lambda": {
"Type": "AWS::Lambda::Function",
"DependsOn": ["getSignedS3LambdaRole"],
"Properties": {
"FunctionName": {
"Fn::Sub": "${AWS::StackName}-getSignedS3"
},
"Code": {
"S3Bucket": { "Ref": "operationsS3Bucket" },
"S3Key": { "Ref": "getSignedS3S3Key" }
},
"Runtime": "nodejs10.x",
"Handler": "index.handler",
"Role": { "Fn::GetAtt": ["getSignedS3LambdaRole", "Arn"] }
}
},
"getSignedS3Permission": {
"Type": "AWS::Lambda::Permission",
"DependsOn": ["api", "getSignedS3Lambda"],
"Properties": {
"Action": "lambda:InvokeFunction",
"FunctionName": { "Ref": "getSignedS3Lambda" },
"Principal": "apigateway.amazonaws.com",
"SourceArn": {
"Fn::Sub": "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${api}/*/*"
}
}
},
"getSignedS3Integration": {
"Type": "AWS::ApiGatewayV2::Integration",
"DependsOn": ["getSignedS3Permission"],
"Properties": {
"ApiId": { "Ref": "api" },
"IntegrationType": "AWS_PROXY",
"IntegrationUri": {
"Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${getSignedS3Lambda.Arn}/invocations"
},
"PayloadFormatVersion": "2.0"
}
},
"getSignedS3Route": {
"Type": "AWS::ApiGatewayV2::Route",
"DependsOn": ["getSignedS3Integration"],
"Properties": {
"ApiId": { "Ref": "api" },
"RouteKey": "POST /getSignedS3",
"AuthorizationType": "NONE",
"Target": { "Fn::Sub": "integrations/${getSignedS3Integration}" }
}
}
}
}
After spending hours debugging this, I found that the problem was in my Lambda permission. I need to use the correct path in the permission.
This does not work:
arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${api}/*/*
This does work:
arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${api}/*/*/getSignedS3
I believe I could scope it even more to this:
arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${api}/*/POST/getSignedS3
This fixed all my problems and shows the correct path in the lambda web console.

Cloudformation Lambda function, environment variables not available, input is not available

Not sure where I am doing wrong. Below is my lambda code and cloudformation template.
Below is my lambda function:
import os
import boto3
def quickstart_lambda_handler(event, context):
print("event={}".format(event)) # nothing shows as k1:v1
print(os.environ) # nothing show in output as var1
print("environment variable var1: " + os.environ['var1'])
json_str = "{\"a1\":\"b1\"}"
bucket_name = "my-s3-bucket"
file_name = "qs.json"
s3_path = "cf-quickstart/" + file_name
s3 = boto3.resource("s3")
s3.Bucket(bucket_name).put_object(Key=s3_path, Body=json_str)
print("object stored in s3")
return s3_path
My cloud formation template is as below for lambda function and associated rule.
"QSLERole": {
"Description" : "Quick Start Lambda Execution Role",
"Type": "AWS::IAM::Role",
"Properties": {
"RoleName" : "QSLERole",
"AssumeRolePolicyDocument": {
"Version" : "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [ "lambda.amazonaws.com" ]
},
"Action": [ "sts:AssumeRole" ]
}]
},
"Path": "/",
"Policies": [
{
"PolicyName": "root",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["logs:*"],
"Resource": "arn:aws:logs:*:*:*"
},
{
"Effect": "Allow",
"Action": "s3:PutObject",
"Resource": "*"
}
]
}
}]
}
},
"QSLambdaF": {
"Description" : "Quick Start Lambda Function",
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"S3Bucket": "my-s3-bucket",
"S3Key": "generate-quickstartjson.zip"
},
"Handler": "generate-quickstartjson.quickstart_lambda_handler",
"Runtime": "python2.7",
"Timeout": "30",
"Environment" : {
"Variables" : {
"var1" : "var1 value"
}
},
"Role": {
"Fn::GetAtt": [
"QSLERole",
"Arn"
]
}
}
},
"ScheduledRule": {
"Description" :"Cloud Watch Quick Start Event Rule",
"DependsOn" : [
"QSLambdaF","EC2Instance"],
"Type": "AWS::Events::Rule",
"Properties" : {
"Description" : "CloudWatch Event for generating output",
"ScheduleExpression" : "rate(1 minute)",
"State": "ENABLED",
"Targets" : [
{
"Arn": { "Fn::GetAtt": [
"QSLambdaF", "Arn"] },
"Detail" : {
"test" : "value"
},
"Input": "{\"k1\":\"v1\"}",
"Id" : "QSScheduledRuleV1"
}
]
}
},
"PEILambda": {
"Description" : "Permission For Events To Invoke Lambda Function",
"Type": "AWS::Lambda::Permission",
"Properties" : {
"FunctionName": { "Ref": "QSLambdaF"},
"Action": "lambda:InvokeFunction",
"Principal": "events.amazonaws.com",
"SourceArn": { "Fn::GetAtt": [
"ScheduledRule", "Arn"] }
}
},
--- ec2 instance creation below with security group
Niether environment variables are available nor Input fields are available in lambda lambda.
"Input": "{\"k1\":\"v1\"}",
Please let me know where I am wrong. Thanks for the help.
works well as is. I was using wrong template file :))

How to invoke a series of API calls to an application in an AWS instance using cloudformation

Is there a way to create a cloudformation template, which invokes REST API calls to an EC2 instance ?
The use case is to modify the configuration of the application without having to use update stack and user-data, because user-data updation is disruptive.
I did search through all the documentation and found that this could be done by calling an AWS lambda. However, unable to get the right combination of CFM template and invocation properties.
Adding a simple lambda, which works stand-alone :
from __future__ import print_function
import requests
def handler(event, context):
r1=requests.get('https://google.com')
message = r1.text
return {
'message' : message
}
This is named as ltest.py, and packaged into ltest.zip with requests module, etc. ltest.zip is then called in the CFM template :
{
"AWSTemplateFormatVersion" : "2010-09-09",
"Description" : "Test",
"Parameters": {
"ModuleName" : {
"Description" : "The name of the Python file",
"Type" : "String",
"Default" : "ltest"
},
"S3Bucket" : {
"Description" : "The name of the bucket that contains your packaged source",
"Type" : "String",
"Default" : "abhinav-temp"
},
"S3Key" : {
"Description" : "The name of the ZIP package",
"Type" : "String",
"Default" : "ltest.zip"
}
},
"Resources" : {
"AMIInfo": {
"Type": "Custom::AMIInfo",
"Properties": {
"ServiceToken": { "Fn::GetAtt" : ["AMIInfoFunction", "Arn"] }
}
},
"AMIInfoFunction": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"S3Bucket": { "Ref": "S3Bucket" },
"S3Key": { "Ref": "S3Key" }
},
"Handler": { "Fn::Join" : [ "", [{ "Ref": "ModuleName" },".handler"] ]},
"Role": { "Fn::GetAtt" : ["LambdaExecutionRole", "Arn"] },
"Runtime": "python2.7",
"Timeout": "30"
}
},
"LambdaExecutionRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"Service": ["lambda.amazonaws.com"]},
"Action": ["sts:AssumeRole"]
}]
},
"Path": "/",
"Policies": [{
"PolicyName": "root",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"],
"Resource": "arn:aws:logs:*:*:*"
},
{
"Effect": "Allow",
"Action": ["ec2:DescribeImages"],
"Resource": "*"
}]
}
}]
}
}
},
"Outputs" : {
"AMIID" : {
"Description": "Result",
"Value" : { "Fn::GetAtt": [ "AMIInfo", "message" ] }
}
}
}
The result of the above (with variations of the Fn::GetAtt call) is that the Lambda gets instantiated, but the AMIInfo call is stuck in "CREATE_FUNCTION".
The stack also does not get deleted properly.
I would attack this with Lambda, but it seems as though you already thought of that and might be dismissing it.
A little bit of a hack, but could you add Files to the instance via Metadata where the source is the REST url?
e.g.
"Type": "AWS::EC2::Instance",
"Metadata": {
"AWS::CloudFormation::Init": {
"configSets": {
"CallREST": [ "CallREST" ]
},
"CallREST": { "files":
{ "c://cfn//junk//rest1output.txt": { "source": "https://myinstance.com/RESTAPI/Rest1/Action1" } } },
}
}
To fix your lambda you need to signal SUCCESS. When CloudFormation creates (and runs) the Lambda, it expected that the Lambda signal success. This is the reason you are getting the stuck "CREATE_IN_PROGRESS"
At the bottom of http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-code.html is a function named "send" to help you signal success.
and here's my attempt to integrate it into your function AS PSUEDOCODE without testing it, but you should get the idea.
from __future__ import print_function
import requests
def handler(event, context):
r1=requests.get('https://google.com')
message = r1.text
# signal complete to CFN
# send(event, context, responseStatus, responseData, physicalResourceId)
send(..., ..., SUCCESS, ...)
return {
'message' : message
}
Lambda triggered by the event. Lifecycle hooks can be helpful.
You can hack CoudFormation, but please mind: it is not designed for this.