while configuring resource configuration , is there any way I can use so that serverless wont create throw any error if resource is already present.
eg. don't throw this error if following resource is already present.
Error : An error occurred: PaymentQueue - dev_payment_cron_queue already exists in stack
resources:
Resources:
PaymentQueue:
Type: "AWS::SQS::Queue"
Properties:
QueueName: ${self:provider.stage}_payment_cron_queue
VisibilityTimeout: 40
Sadly, there is no such way with pure CloudFormation (CFN), as this is not how CFN (or Terraform as a matter of fact) was designed to work. From CFN perspective, a given resource exists and is managed by CFN, or it does not exist at all. There is no middle ground.
If your resource already exist, you have to import it to CFN so that it gets managed by CFN. Alternatively, you have to create custom resource in the form of a lambda function. The function would perform any action you want based on the existing resources, including checking if it exists or not.
Related
I created and deployed a S3 resource (bucket) using cloudformation.
After that i deployed a version without that resource.
Then i deployed a version with the resource.
Since the bucket exists, it gives me an error that it cannot deploy.
This has happened to me before, in past times I deleted the resource and deployed again.
I'm looking for a way to use the resource for future deployments. It is the exact same resource, this is the yaml :
Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub "myBucketName"
Is there anything I can add to the resource, a policy, a unique ID, anything so that i could use the existing resource?
Thanks!
To "use the existing resource" in a CFN, you have to import it. Also its a bad practice to keep modify resources created by CFN outside of CFN. This leads to drift and number of issues, one of which you are experiencing.
I am creating a an AppSync cloudformation and a dashboard and I notice that the ApiId export is finished creation much after.
I create my output like so in a appsync file :
Outputs:
GraphQlApiIdOutput:
Description: Main GraphQl Api ID.
Value:
Fn::GetAtt:
- GraphQlApi
- ApiId
Export:
Name: GraphQlApiIdOutput
In another dashboard file:
CloudwatchDashboard:
Type: AWS::CloudWatch::Dashboard
Properties:
DashboardBody:
{
'Fn::Sub': ['{
...
,{
ApiId:
!ImportValue GraphQlApiIdOutput}]
However, I get the error: No export named GraphQlApiIdOutput found. Rollback requested by user.
The only way I can get around this is by removing the import value first so that the stack creation succeeds and then add in the import value. I notice that there is a waitcondition but none of the resources are external. I also notice that creation policy is only supported for AWS::AutoScaling::AutoScalingGroup, AWS::EC2::Instance, and AWS::CloudFormation::WaitCondition.
Is there a way to wait for resource creation in Cloudformation so that the template does not try to use an output value before it is created in the same stack?
When you have this in your code:
!ImportValue GraphQlApiIdOutput
it means that stack from Template 1 must be created beforehand.
So normally what you do is the following:
Deploy Template 1
When this succeeds, then you deploy your another template file.
The DependsOn is for the resources within same stack, not across different stacks. The same goes for WaitCondition as you wont be able to reference conditions in another template file from Template 1 before the Template 1 stack has been successful created.
Yes, use the DependsOn Attribute:
With the DependsOn attribute you can specify that the creation of a specific resource follows another. When you add a DependsOn attribute to a resource, that resource is created only after the creation of the resource specified in the DependsOn attribute.
The attribute points to another resource in the same stack. If Resource A DependsOn Resource B, then Resource A will only be created once Resource B has finished creation.
Is there a way to create a resource if it doesn't exist and use an existing resource if it does?
resources:
- name: "my-topic"
type: gcp-types/pubsub-v1:projects.topics
properties:
topic: "this-exists-already"
- name: "my-other-resource"
type: 'gcp-types/cloudfunctions-v1:projects.locations.functions'
properties:
functionName: "function"
environmentVariables:
# get a ref to new or already existing topic
my-toptic: "$(ref.my-topic.name)"
Per #kolban's link I think I want to use abandon here. Can I selectively "abandon" a specific resource so I can, for example, attach an accessControl policy to an existing bucket but then NOT delete that bucket if the deployment is deleted?
ABANDON - This removes any references to the resource from the
deployment but does not delete the underlying resource. For example,
abandoning an instance means that it is removed from a deployment but
the instance still exists for you to use.
Edit
Maybe I should use an "action" to assign an acl instead of a resource? Is this the right way and are there examples of this? So DM would essentially just execute an api call to apply an acl out-of-band. That would mean it would leave the acl behind if the deployment is deleted but I'm okay with that.
It looks like I want to do something like this but instead of applying an acl to a specific file I want to set it on the bucket (with an action) https://github.com/GoogleCloudPlatform/deploymentmanager-samples/blob/master/community/storage-bucket-acl/storagebucket-acl.jinja#L29.
If we read this section of the Deployment Manager documentation:
https://cloud.google.com/deployment-manager/docs/deployments/updating-deployments#policies_for_adding_resources
We read about the concept of "create or acquire". The way I read this is that if a resource your configuration says should be created then the default appears to be that if it already exists, it will not cause an error and will be "acquired" for this deployment which I take to mean that it will be as though it had been created.
I have one CFT that creates an EBS volume. Then I have a second CFT that attaches the volume to the instance. I use a Custom Resource which runs a lambda to find the EbsVolumeId and the InstanceId
The 2 CFT's are part of a jenkins pipeline and its possible that the playbook that uses the CFT to create the EBS volume can be skipped and thus there is no EbsVolumeId to reference.
So in the CFT that attaches the EBS volume, I tried adding a Condition
Resources:
MountPoint:
Type: AWS::EC2::VolumeAttachment
Condition: AttachEBS
Properties:
InstanceId: !GetAtt SCSHelper.InstanceId
VolumeId: !GetAtt SCSHelper.EbsVolumeId
The custom resource looks like
SCSHelper:
Type: Custom::SCSHelper
So I have to define the condition before the resources:
Conditions:
AttachEBS: !Not [!Equals http:// !GetAtt SCSHelper.EbsVolumeId , None ]
The problem is the Conditions is failing with:
An error occurred (ValidationError) when calling the CreateStack operation: Template format error: Unresolved dependencies https://forums.aws.amazon.com/. Cannot reference resources in the Conditions block of the template An error occurred (ValidationError) when calling the CreateStack operation: Template format error: Unresolved dependencies https://forums.aws.amazon.com/.
So it appears that the SCSHelper.EbsVolumeId attribute is not available for the condition to use.
Is there a way to make this work or is there a better way to conditionally run the CFT that attaches the EBS volume?
Thanks in advance...
The important section of the Conditions documentation is this
Parameters
Define the input values that you want to evaluate in your conditions. Conditions will result in true or false based on values from these input parameters.
Conditions in CloudFormation can be based on Parameters alone. They can't take in-flight resource values into account, as these values aren't known at compile time.
I know the equivalent to AWS::Lambda::Function is aws_lambda_function
But I'm not sure what the equiv for Custom::LoadLambda
I'm trying to translate the below into Terraform:
CreateRsaKey:
Type: Custom::LoadLambda
Properties:
ServiceToken: # This seems to call another lambda
Fn::GetAtt:
- SolutionHelper
- Arn
Region:
Ref: AWS::Region
The Custom::String Resource Type refers to a Custom Resource. This means that what it does depends on the particular implementation of the Lambda function provided to the ServiceToken property (SolutionHelper in your example). When a Custom Resource is used, the Lambda function is invoked with a Request Object specifying a RequestType of Create/Update/Delete.
The Terraform equivalent of a Custom Resource is a Custom Provider plugin. These are packaged and distributed the same as the standard set of Providers, only less officially. They are built as separate binaries (typically Go packages) auto-discovered by the core Terraform process using a filename convention (terraform-<TYPE>-<NAME>), and are invoked in a subprocess using a custom RPC mechanism. The plugin binary provides through RPC a Provider containing a collection of Resources that implement Create/Read/Update/Delete functions for the resource.
So it's possible to re-implement the functionality of a Lambda-backed Custom Resource within a Terraform Provider Plugin by translating the CloudFormation Create/Update/Delete logic in the Lambda function to the Create/Update/Delete functions in the Terraform Resource (and adding an appropriate Read function). However, it's not a very simple or straightforward process.
you can try using this provider
https://github.com/mobfox/terraform-provider-multiverse