How do I make Cloudformation reprocess a template using a macro when parameters change? - aws-cloudformation

I have a Cloudformation template that uses a custom Macro to generate part of the template. The lambda for the Macro uses template parameters (via the templateParameterValues field in the incoming event) to generate the template fragment.
When I change the Cloudformation Stack's parameters, I get an error:
The submitted information didn't contain changes. Submit different information to create a change set.
If I use the CLI I get a similar error:
An error occurred (ValidationError) when calling the UpdateStack operation: No updates are to be performed.
The parameters I am changing are only used by the Macro, not the rest of the template.
How can I make Cloudformation reprocess the template with the macro when I update these parameters?

After working with AWS Support I learned that you must supply the template again in order for the macro to be re-processed.
Even if it is the same exact template it will cause the macros to be reprocessed.
You can do this via the Console UI (by uploading the template file again) or the CLI (by passing the template / template URL again).

I recently came across this when using the count macro to create instances.
I found i was able to modify just the parameters used just by the macro by moving that part of the template to a nested stack and passing the parameters through.
It does involve a bit more work to setup by having the separate stacks, but it did allow me to modify just the parameters of the parent stack how i wanted.

Related

Data Fusion - Argument defined in Argument Setter Plugin Supersedes Runtime Arguments intermittently

Using Data Fusion Argument Setter, I've defined all parameters in it for a reusable pipeline. While executing it, I provide runtime arguments for some parameters which are different from default arguments provided in the JSON URL embedded in Argument Setter.
But a number of times, the pipeline ends up taking the default values from Argument Setter URL instead of Runtime Arguments causing failures.
This behavior is not consistent in every pipeline I create - which confirms that Runtime arguments are supposed to supersede any prior value defined for an argument.
The workarounds I use is by deleting the plugin and re-adding it for every new pipeline. But that defeats the purpose of creating a re-usable pipeline.
Has anyone experienced this issue ?
Current Runtime Options
This wiki https://cloud.google.com/data-fusion/docs/tutorials/reusable-pipeline provides the sample of how to create re-usable pipeline using Argument Setter. From there, it seems like the runtime arguments was used to notify the data fusion pipeline to use the macro from Argument Setter URL. Argument Setter is a type of Action plugin that allows one to create reusable pipelines by dynamically substituting the configurations that can be served by an HTTP Server. It looks like no matter how you change the runtime arguments, as long as long the same marco can be read when pipeline is running, the arguments will be override.

What's the best way to consume Parameter Store value in AWS CDK

I am having problems using SSM valueForStringParameter method in CDK. It's working the first time I deploy the stack, but it is not picking up updates to the parameter value when I redeploy the stack because CloudFormation template hasn't changed and so CloudFormation thinks there were no updates, even if SSM parameter has changed.
For the context, I am deploying stack via CodePipeline, where I run cdk synth first, and then use CloudFormationCreateUpdateStackAction action to deploy template.
Anyone knows how to work around that? The only other option that I know will work is to switch to a custom resource lambda that calls SSM and returns value using aws-sdk, but that feels like a overly complicated option.
Update 1
I cannot use ValueFromLookupbecause value is only updated at runtime as part of cloudformation deployment by another stack (I deploy both stacks in CodePipeline, in 2 different regions), so synthesis time lookup would result in stale value.
All the valueOf* and from* methods work by adding a CloudFormation parameter. As you figured out already, changing the parameter value does not change the template and no change will be triggered.
What you probably want to use instead is the method valueFromLookup. Lookups are executed during synth and the result is put into the generated CFN template.
ssm.StringParameter.valueFromLookup(this, 'param-name');
But be aware, lookups are stored in the cdk.context.json. If you have commited that file to your repo, you need to erase that key via cdk context -e ... before synth/diff/deploy.
Since you cannot use lookup functions and the most common way to pass config to cdk is through context variables, I can only suggest dirty workarounds.
For example, you could create a dummy parameter in your stack to bump every time there's deployment.
var deploymentId = new CfnParameter(this, "deploymentId", new CfnParameterProps() { Type = "String", Description = "Deployment Id" });
SetParameterValue(deploymentId, this.Node.GetContext("deploymentId").ToString());
and when you synthesize the CF, you could generate an ID:
cdk synth -c deploymentId=$(uuidgen)
If you can avoid the "environment agnostic" syth and you really need an immutable artifact to deploy across multiple environments, you could use the built package from your cdk, for example, the npm package containing your cdk. Therefore, you could deploy it in each environment by overwriting the context parameters instead of using ssm parameters store.
See https://docs.aws.amazon.com/cdk/latest/guide/get_ssm_value.html, you can use method valueFromLookup which gets you parameter store value at synthesis time, when value is different from previous one, this shall trigger CF stack update.
However, I was under impression that valueForStringParameter should work on updated ssm parameter values as well, based on https://aws.amazon.com/blogs/mt/integrating-aws-cloudformation-with-aws-systems-manager-parameter-store/ Example 2:

How to pass nested Stack outputs to another step in Octopus Deploy

In my Octopus project, the first step launches a bunch of nested stacks implemented with cloudformation.
I need to share the outputs of the master stack launched from Octopus, how can I do that?
Thanks.
The output variables from the CloudFormation template will be available to later steps the same as any other Octopus output variable, this is mentioned in the first paragraph of the documentation page.
Output variables can be accessed a number of different ways, depending on where you are accessing them, for example, in Powershell they can be accessed via the parameters dictionary $OctopusParameters["Octopus.Action[Step Name].Output.VariableName"].
You can also access them using the Variable Binding syntax, #{Octopus.Action[Step Name].Output.VariableName}
More information about output variables is available in the docs.

Why does GetAttr not work on cloudformation template parameters?

Have a collection of cloudformation templates in a parent-child relationship and want to pass an AWS::IAM::Role into the parameters of a child stack and use GetAttr to get the Arn.
This fails validation because can only call GetAttr on resources, not on parameters.
Anyone know/guess why this is designed in this way?
It's not a problem as it can be worked around by just passing the Arn into the stack, I'm just curious really
What Fn::GetAttr and Parameters are trying to do in AWS CloudFormation is fundamentally different. As per AWS docs:
The intrinsic function Fn::GetAtt returns the value of an attribute
from a resource in the template.
[1] http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-getatt.html
You can use the optional Parameters section to pass values into your
template when you create a stack. With parameters, you can create
templates that are customized each time you create a stack.
[2] http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html
I believe your confusion is stemming from the fact that you're trying to think of this in terms of the object-oriented/some other programming paradigm, where Resources and Parameters are some kind of objects and Fn::GetAttr is a generic function which retrieves the value of a reference that's passed in as an argument.
In my case, I wanted to access the resource attributes like ARN and Name in the nested stack. If I pass resource string and use GetAtt to get these, I dont need to pass them as two parameters. With this limitation, I had to pass them as two parameters.

How do I associate a CoffeeScript file with a view?

Just installed rails 3.1 rc1 and am trying to grok the best way to manage javascript with the new asset pipeline
By default all coffeescript is compiled into a single application.js file, this is a good thing.
Each seperate coffee script file is appended to the js file and wrapped in an anonymous function which is executed via the call method
A common scenario would be to use some jquery to turn various forms into ajax forms, update UI, etc...
Many of these scripts will be specific to a controller or action, I am trying to grok the 'conventional' way to handle this,
since everything is wrapped in an anonymous function how do I only execute just
the code for a particular controller / action, by default all of the anonymous functions are being executed
I did play around with some hacks where I load the controller and action name into js variables and then in
coffeescript check those to conditionally run code, I don't like that very much
my initial thought was that each coffee file would contain a js namespace/object and I would call the specific ones from the view,
going to spike this using the default_bare = true configuration
see How can I use option "--bare" in Rails 3.1 for CoffeeScript?
EDIT
Looking around some more: this looks like it might be the correct approach - "Can't find variable" error with Rails 3.1 and Coffeescript
There are two common approaches:
Make behavior conditional on the presence of a particular element. For instance, code to run a signup sheet should be prefaced with something like
if $('#signup').length > 0
Make behavior conditional on a class on the body element. You can set the body class using ERB. This is often desirable for stylesheets as well. The code would be something like
if $('body').hasClass 'user'
gistyle is a simple gem that helps you running action-specific javascript codes.
By following its setup, you set some data attributes in your body element, representing the current controller and action names. Then it will only call that action when the corresponding view is loaded.