Cross referencing Stacks using export variable - amazon-web-services

Given that I have following stacks -
Stack-A
Output variable with export name output-resource-1
Stack-B
Has a parameter named base-stack-name which will be initialized to Stack-A during sam deploy
Stack-C
Has parameter named 'parent-stack-name' which will be initialized to 'Stack-B' during sam deploy
Now in Stack-C, I am trying to use resource exported in Stack-A. However Stack-C parameters can only accept one stack name as a parameter which is 'Stack-B'.
Idea is to use the reference to Stack-A available in Stack-B to access the export variable in Stack-A while creating Stack-C.
So I tried using something like this
Output section of Stack-A definition
StackAResource:
Description: StackAResource.
Value:
Fn::GetAtt: Database.Endpoint
Export:
Name:
Fn::Sub: ${AWS::StackName}-outout-resource-1
Stack-C definition where above exported resource is trying to be accessed.
Stack-C has a parameter named parent-stack-name
- Name: SomeResource
Value:
Fn::ImportValue:
Fn::Sub:
- ${stackAexportvariable}-output-resource-1
- stackAexportvariable:
Fn::Sub: ${parent-stack-name}-base-stack-name
The sam deploy for Stack-C keeps failing and I am not sure how I can get this to work. Any pointers would be appreciated.
I could easily add another parameter for Stack-C base-stack-name and access the exported variable. However as Stack-C is already accepting parent-stack-name, which has the information about base-stack-name , trying to get rid of additional user input.

Related

How do I solve this Serverless.yml ssm dynamic path creation problem?

Fairly new to Serverless and am having problems creating a dynamic path to an SSM parameter..... I have tried a fair few ideas but am sure that this is really close but its not quite there....
I'm trying to generate an ssm path as a custom variable that will then be used to populate a value for a Lambda function.
Here's the custom variable code
custom
securityGroupSsmPath:
dev: "${self:service}/${self:custom.stage}/rds/lambdasecuritygroup"
other: "${self:service}/${env:SHARED_INFRASTRUCTURE_ENV}/rds/lambdasecuritygroup"
securityGroupId: ${ssm:, "${self:custom.securityGroupSsmPath.${env:SHARED_INFRASTRUCTURE_ENV}, self:custom.securityGroupSsmPath.other}"}
And here is where it is referenced in the function
functions:
someLambda:
handler: build/handlers/someLambda/handler.handler
timeout: 60
memorySize: 256
vpc:
securityGroupIds:
- ${self:custom.securityGroupId}
And here is the error output. It seems like it is not resolving the ssm parameter
Serverless Error ----------------------------------------
Cannot resolve serverless.yml: Variables resolution errored with:
- Cannot resolve variable at "custom.securityGroupId": Parameter name: can't be prefixed with "ssm" (case-insensitive). If formed as a path, it can consist of sub-paths divided by slash symbol; each sub-path can be formed as a mix of letters, numbers and the following 3 symbols .-_
All help much appreciated,
Thanks!
Sam
In the end we tried numerous implementations and the issue seemed to boil down to trying to both retrieve the ssm value for securityGroupId and also parse and default the second variable within it.
The solution ended up being as follows where we removed the parsing/default variable from within ssm step. Additionally we had to remove some of the double quotes on the custom vars:-
custom
securityGroupSsmPath:
dev: ${self:service}/${self:custom.stage}/rds/lambdasecuritygroup
other: ${self:service}/${env:SHARED_INFRASTRUCTURE_ENV}/rds/lambdasecuritygroup
securityGroupId: ${self:custom.securityGroupSsmPath.${env:SHARED_INFRASTRUCTURE_ENV}, self:custom.securityGroupSsmPath.other}
functions:
someLambda:
handler: build/handlers/someLambda/handler.handler
timeout: 60
memorySize: 256
vpc:
securityGroupIds:
- ${ssm:/${self:custom.securityGroupId}}

Referencing serverless stack name after pseudo parameters plugin deprecation

I'm wondering what is the correct way to reference AWS Cloudformation pseudo parameters in a serverless.yml now that pseudo parameter plugin has been deprecated.
All pseudo parameters are not available with the dollar sign syntax (e.g. ${aws:stackName} is not) in a similar manner as ${aws:region} is, for example. The serverless documentation on pseudo parameters is very short and I am not sure I fully understand it. I have tried to use Ref: "AWS::StackName", but when I try to generate an output
Fn::Sub:
- "${Stack}-someOutputResourceName"
- Stack:
Ref: "AWS::StackName"
, I get an error with [...]/Fn::Sub/1/Stack] 'null' values are not allowed in templates.
The pseudo-plugin page claims that
All functionalities as provided by this plugin are now supported by Serverless Framework natively
If this is true, how should I go about using pseudo-parameters?
It seems that while the above method does not work, I am able to use the pseudo variable directly without using Ref:
Name: !Sub "${AWS::StackName}-someOutputResourceName"

YAML Syntax for ImportValue into CFN Parameter Default

I'm struggling with the YAML syntax to import a value that was exported by another CFN stack into the default value of a parameter in a new stack.
What I have at the moment is:
Parameters:
DBEndpoint:
Description: Hostname endpoint for RDS Database
Type: String
Default: Fn::ImportValue: 'db-endpoint'
Where db-endpoint is the value exported by the following YAML template snippet:
Outputs:
dbhost:
Description: "RDS Endpoint Address"
Value: !GetAtt DB.Endpoint.Address
Export:
Name: db-endpoint
The export works fine, but I get a parse error (Template format error: YAML not well-formed. ) when trying to load the template with the ImportValue line.
Update:
I have the YAML parsing correctly now, I think, but now get a new error.
With
Parameters:
DBEndpoint:
Description: Hostname endpoint for RDS Database
Type: String
Default: !ImportValue 'db-endpoint'
I get an error Template format error: Every Default member must be a string..
So, it seems closer, but still not working.
This answer implies this might not even be possible... is that the case?
!ImportValue 'db-endpoint' can't be used in Parameters. It can only be used in Resources and Outputs of your template. You have to "manually" (aka, outside of CloudFormation, e.g. by a wrapper script) set the default value of DBEndpoint to the actual value of your db-endpoint.

Value of property does not match type Number YML

I am trying to pass a parameter through the aws cloudformation deploy command like this:
aws cloudformation deploy --template-file sam-template.packaged.yaml --parameter-overrides ExcTime=12345
But it fails deploying because it is complaining that the ExcTime parameter is a string and it needs to be a number. Is it the command casting all the parameters as string? And if so, how can I pass a parameter of type number to the YML file through that command?
The yml file:
ApiKey:
Type: AWS::AppSync::ApiKey
Properties:
ApiId: !GetAtt AppSyncApi.ApiId
Expires: ${ExcTime}
Thank You all!
To refer to your parameter, you should use:
Expires: !Ref ExcTime
So i figured out why. The --parameter-overrides Param=value only accepts strings
--parameter-overrides (list) A list of parameter structures that
specify input parameters for your stack template. If you're updating
a stack and you don't specify a parameter, the command uses the
stack's existing value. For new stacks, you must specify parameters
that don't have a default value. Syntax:
ParameterKey1=ParameterValue1 ParameterKey2=ParameterValue2 ...(string).
https://docs.aws.amazon.com/cli/latest/reference/cloudformation/deploy/index.html
To pass a number, You need to specify that the value is a number in the sam template like this:
Parameters:
YourParam:
Type: Number
Description: Bla bla bla
And then You can use it as a number in the template. For example
Expires: !Ref YourParam

AWS Serverless Error for Provider variables - Trying to populate non string value into a string for variable

I am using Serverless framework.
I have created Cognito user pool in one stack and importing it into second stack.
When I assign the value of the Cognito User pool ID created in the first stack, to the environment variable it works.
But when I try to use it while creating a ARN for Cognito Authorizer, it doesn't work.
I get an error - Trying to populate non string value into a string for variable
Here is the snippet of my serverless.yml file.
service: myservice
plugins:
- serverless-pseudo-parameters
provider:
name: aws
runtime: go1.x
stage: dev
region: us-east-1
cognitoUserPoolId :
Fn::ImportValue: cloudformation-resources-${self:provider.stage}-CognitoUserPool
cognitoAppClientId :
Fn::ImportValue: cloudformation-resources-${self:provider.stage}-CognitoUserPoolClient
custom:
environment:
COGNITO_USER_POOL_ID : ${self:provider.cognitoUserPoolId}
COGNITO_APP_CLIENT_ID: ${self:provider.cognitoAppClientId}
functions:
myfunction:
handler: bin/handlers/myfunction
package:
exclude:
- "**/**"
include:
- ./bin/handlers/myfunction
events:
- http:
path: mypath
method: put
authorizer:
name: cognitoapiauthorizer
arn: arn:aws:cognito-idp:#{AWS::Region}:#{AWS::AccountId}:userpool/${self:provider.cognitoUserPoolId}
cors: true
Any issues related to indentation or the way it is being used in another variable like ARN?
I see you're trying to resolve the error Trying to populate non string value into a string for variable. In my experience, this means that the variable is empty. What happens if you hardcode the cognitoUserPoolId at the end of the ARN? Is the error resolved? I suspect it would be. Moving forward from there, you should take a closer look at how you declare that variable. Your usage of Fn::ImportValue may not working as intended.
Also, I would definitely run your YAML through a validator. There are too many extra blank lines, and extra spaces before the colons e.g. COGNITO_USER_POOL_ID : ${self:provider.cognitoUserPoolId}. These may be causing problems. Keep your YAML formatting tidy.