Can CloudFormation Create a PipeLine Manual Approval Action through Template? - aws-cloudformation

Reading through this https://docs.aws.amazon.com/codepipeline/latest/userguide/approvals-action-add.html
it sounds like you can only create a manual approval step through the UI Console or through CLI BUT NOT through CloudFormation Template?
Edgar

Actually, CloudFormation does support this.
You just need to set Provider for resource ActionTypeId (Pipeline -> Stage -> Action -> ActionTypeId) as Manual and that's it. More info about provider type - here.
Examle:
DeliveryPipeline:
Properties:
...
Stages:
...
- Actions:
- ActionTypeId:
Category: Approval
Owner: AWS
Provider: Manual
Version: '1'
Configuration:
NotificationArn: <<arn>>
InputArtifacts: []
Name: TestApproval
RunOrder: 1
Name: Development_Approval
...
Type: AWS::CodePipeline::Pipeline

Related

Why does cloudformation give "Invalid method response 200" error, but manual deployment work? (AWS API Gateway Websocket)

I am getting this error when I deploy a simple websocket mock route.
Execution failed due to configuration error: Output mapping refers to an invalid method response: 200
First of all, I'm a little confused about what method response means, as in Websocket API, the terminology used is Route Response and Integration Response. I'm guessing this is referring to the Route Response.
The resources I have are:
Websocket API
Stage
Deployment
$connect route
$connect integration with mock (default maps to {"statusCode": 200})
$connect integration response (just passes the integration through)
$connect route response
The funny part is: to fix this, all I have to do is go to the console and click deploy API. I don't have to change any configuration. But that is not a good solution for me, as I want to run this on a CI/CD pipeline.
I'm guessing the problem is with the Route Response, as that is not configurable from the console. So something must be going on behind the scenes during console deployment, which I am missing during cloudformation deployment. Any ideas how to solve this?
Here's my Cloudformation Template.
Resources:
testWsApiBackendWsApi40DF2EE8:
Type: AWS::ApiGatewayV2::Api
Properties:
Name: testWsApi
ProtocolType: WEBSOCKET
RouteSelectionExpression: $request.body.action
testWsApiApiDeployment423ACBB9:
Type: AWS::ApiGatewayV2::Deployment
Properties:
ApiId:
Fn::GetAtt:
- testWsApiBackendWsApi40DF2EE8
- ApiId
DependsOn:
- MockWithAuthAwsStackwsMockRoute04DB7577
testWsApiApiStageF40CAAE0:
Type: AWS::ApiGatewayV2::Stage
Properties:
ApiId:
Fn::GetAtt:
- testWsApiBackendWsApi40DF2EE8
- ApiId
StageName: production
DeploymentId:
Fn::GetAtt:
- testWsApiApiDeployment423ACBB9
- DeploymentId
MockWithAuthAwsStackwsMockRoute04DB7577:
Type: AWS::ApiGatewayV2::Route
Properties:
ApiId:
Fn::GetAtt:
- testWsApiBackendWsApi40DF2EE8
- ApiId
RouteKey: $connect
Target:
Fn::Join:
- ""
- - integrations/
- Ref: MockWithAuthAwsStackwsMockIntegration36E7A460
MockWithAuthAwsStackwsMockIntegration36E7A460:
Type: AWS::ApiGatewayV2::Integration
Properties:
ApiId:
Fn::GetAtt:
- testWsApiBackendWsApi40DF2EE8
- ApiId
IntegrationType: MOCK
PassthroughBehavior: WHEN_NO_TEMPLATES
RequestTemplates:
$default: '{"statusCode":200}'
TemplateSelectionExpression: \$default
MockWithAuthAwsStackwsMockRouteResponseAEE0B8ED:
Type: AWS::ApiGatewayV2::RouteResponse
Properties:
ApiId:
Fn::GetAtt:
- testWsApiBackendWsApi40DF2EE8
- ApiId
RouteId:
Ref: MockWithAuthAwsStackwsMockRoute04DB7577
RouteResponseKey: $default
MockWithAuthAwsStackwsMockIntegrationResponse85928773:
Type: AWS::ApiGatewayV2::IntegrationResponse
Properties:
ApiId:
Fn::GetAtt:
- testWsApiBackendWsApi40DF2EE8
- ApiId
IntegrationId:
Ref: MockWithAuthAwsStackwsMockIntegration36E7A460
IntegrationResponseKey: $default
TemplateSelectionExpression: \$default
P.S I am actually using AWS CDK. The above template is the result of cdk synth. Let me know if you want to see the CDK code.
The reason why manual deployment using console works, while using cloudformation causes errors occasionally, is due to the order in which these resources are created. In the console, this is the order followed:
Routes, Integrations and Responses are created
They are associated with a stage
They are deployed to the specified stage
When using cloudformation, the order of creation of resources gets mixed up, resulting in them not being wired up properly. It seems that you have wired up the deployment to depend on the route being created first. You also need to make sure that the stage is created before the deployment. For this you could add an explicit DependsOn attribute, or an implicit reference to the stage within the deployment; perhaps in the stageName attribute as !Ref StageResource.
Or you could save the trouble and just add an autoDeploy: true to your stage, which will take care of the linking and order on its own.

How to access a multi branch resource attribute in a concourse job?

I'm using multi branch resourcing in a concourse pipeline like so:
resources:
- name: my-resource
type: git-multibranch
source:
uri: git#github.com.../my-resource
branches: 'feature/.*'
private_key: ...
ignore-branches: ''
How can I access the branch the resource is on at the time the job runs? like so:
jobs:
...
outputs:
- name: my-resource
params:
GIT_BRANCH: {BRANCH-GOES-HERE}
I'm looking to access it via something like my-resource.branch but haven't found any thing that works yet

Serverless CloudFormation template error instance of Fn::GetAtt references undefined resource

I'm trying to setup a new repo and I keep getting the error
The CloudFormation template is invalid: Template error: instance of Fn::GetAtt
references undefined resource uatLambdaRole
in my uat stage, however the dev stage with the exact same format works fine.
I have a resource file for each of these environments.
dev
devLambdaRole:
Type: AWS::IAM::Role
Properties:
RoleName: dev-lambda-role # The name of the role to be created in aws
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AWSLambdaFullAccess
#Documentation states the below policy is included automatically when you add VPC configuration but it is currently bugged.
- arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole
uat
uatLambdaRole:
Type: AWS::IAM::Role
Properties:
RoleName: uat-lambda-role # The name of the role to be created in aws
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AWSLambdaFullAccess
#Documentation states the below policy is included automatically when you add VPC configuration but it is currently bugged.
- arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole
In my serverless.yml my role is defined as
role: ${self:custom.stage}LambdaRole
and the stage is set as
custom:
stage: ${opt:stage, self:provider.stage}
Running serverless deploy --stage dev --verbose succeeds, but running serverless deploy --stage uat --verbose fails with the error. Can anyone see what I'm doing wrong? The uat resource was copied directly from the dev one with only the stage name change.
Here is a screenshot of the directory the resource files are in
I had the same issue, eventually I discovered that my SQS queue name wasn't the same in all 3 places. The following 3 places that the SQS name should match are shown below:
...
functions:
mylambda:
handler: sqsHandler.handler
events:
- sqs:
arn:
Fn::GetAtt:
- mySqsName # <= Make sure that these match
- Arn
resources:
Resources:
mySqsName: # <= Make sure that these match
Type: "AWS::SQS::Queue"
Properties:
QueueName: "mySqsName" # <= Make sure that these match
FifoQueue: true
Ended up here with the same error message. My issue ended up being that I got the "resource" and "Resource" keys in serverless.yml backwards.
Correct:
resources: # <-- lowercase "r" first
Resources: # <-- uppercase "R" second
LambdaRole:
Type: AWS::IAM::Role
Properties:
...
🤦‍♂️
I missed copying a key part of my config here, the actual reference to my Resources file
resources:
Resources: ${file(./serverless-resources/${self:provider.stage}-resources.yml)}
The issue was that I had copied this from a guide and had accientally used self:provider.stage rather than self:custom.stage. When I changed this, it could then deploy.
Indentation Issue
In general, when YAML isn't working I start by checking the indentation.
I hit this issue in my case one of my resources was indented too much, therefore, putting the resource in the wrong node/object. The resources should be two indents in as they're in node resources sub-node Resources
For more info on this see yaml docs

Need to configure serverless resource output to get api gateway api id

I have a serverless project that is creating an API Gateway API amongst other things. One of the functions in the project needs to generate a URL for an API endpoint.
My plan is to get the API ID using a resource output in serverless.yml then create the URL and pass it through to the lambda function as an env parameter.
My problem/question is how to get the API ID as a cloud formation output in serverless.yml?
I've tried:
resources:
Outputs:
RESTApiId:
Description: The id of the API created in the API gateway
Value:
Ref: name-of-api
but this give the error:
The CloudFormation template is invalid: Unresolved resource dependencies [name-of-api] in the Outputs block of the template
You can write something like this in the serverless.yml file:
provider:
region: ${opt:region, 'eu-west-1'}
stage: ${opt:stage, 'dev'}
environment:
REST_API_URL:
Fn::Join:
- ""
- - "https://"
- Ref: "ApiGatewayRestApi"
- ".execute-api."
- ${self:provider.region}
- Ref: "AWS::URLSuffix"
- "/"
- ${self:provider.stage}"
Now you can call serverless with optional commandline options --stage and/or --region to override the defaults defined above, e.g:
serverless deploy --stage production --region us-east-1
In your code you can then use the environment variable REST_API_URL
node.js:
const restApiUrl = process.env.REST_API_URL;
python:
import os
rest_api_url = os.environ['REST_API_URL']
Java:
String restApiUrl = System.getenv("REST_API_URL");
The serverless framework has a documentation page on how they generate names for resources.
See. AWS CloudFormation Resource Reference
So the generated RestAPI resource is called ApiGatewayRestApi.
Unfortunately, the documentation doesn't mention it:
resources:
Outputs:
apiGatewayHttpApiId:
Value:
Ref: HttpApi
Export:
Name: YourAppHttpApiId

Conditionally create CodePipeline actions based on CloudFormation conditions

Enable / disable sections of a CloudFormation for CodePipeline using Conditionals:
This creates a manual notification action once staging has been built and passed Runscope tests:
- InputArtifacts: []
Name: !Join ["",[!Ref GitHubRepository, "-prd-approval"]]
ActionTypeId:
Category: Approval
Owner: AWS
Version: '1'
Provider: Manual
OutputArtifacts: []
Configuration:
NotificationArn: !GetAtt ["SNSApprovalNotification", "Outputs.SNSTopicArn"]
ExternalEntityLink: OutputTestUrl
RunOrder: 3
How to enable/disable this like other CloudFormation resources with a Condition: .
Action steps don't recognize Condition: param
I could make 2 copies of the whole pipeline code one with and one without and then toggle which pipeline I create but it seems like there should be a better way.
You should be able to accomplish this by conditionally inserting the AWS::CodePipeline::Pipeline Resource's Action into the Actions list using the Fn::If Intrinsic Function referencing your Conditions element, returning the Action when the Condition is true and AWS::NoValue (which removes the property, in this case removing the item from the list) when it is not true:
- !If
- IsProdCondition
- InputArtifacts: []
Name: !Join ["",[!Ref GitHubRepository, "-prd-approval"]]
ActionTypeId:
Category: Approval
Owner: AWS
Version: '1'
Provider: Manual
OutputArtifacts: []
Configuration:
NotificationArn: !GetAtt ["SNSApprovalNotification", "Outputs.SNSTopicArn"]
ExternalEntityLink: OutputTestUrl
RunOrder: 3
- !Ref AWS::NoValue