title: CloudFormation: Create resources if they do not exist, but do not delete them
body: <p>I have the following CloudFormation template. (It is based off default the template created for running C# Web API in AWS Lambda, but that may not be relevant.)</p>
  
  <p>It creates an AWS Lambda function. The template also creates an IAM Role and a DynamoDB table if the names of existing resources are not supplied as arguments.</p>
  
  <p>That part works. If no names are supplied for the role and table, they are created.</p>
  
  <p><strong>The problem exists when I run the template a second time to perform updates:</strong> at this point, my role and table exist, so I provide the names as arguments. However, when CloudFormation runs the second time, the resources it created the first time (the role and table) are deleted.</p>
  
  <p><strong>Is there some way to set up the template such that it will create new resources if they don't exist, but not delete them if they are already present?</strong></p>
  
  <p>I haven't done a lot with CloudFormation, but I did go through the documentation. The closest I found was <a href="http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/protect-stack-resources.html" rel="noreferrer">setting a stack policy</a>, but it doesn't seem to be part of the template. It looks like I would have to do this in the management console after the fact.</p>
  
  <pre><code>{
    "AWSTemplateFormatVersion" : "2010-09-09",
    "Transform" : "AWS::Serverless-2016-10-31",
    "Description" : "...",
  
    "Parameters" : {
      "ShouldCreateTable" : {
        "Type" : "String",        
        "AllowedValues" : ["true", "false"],
        "Description" : "If true then the underlying DynamoDB table will be created with the CloudFormation stack."
      },  
      "TableName" : {
          "Type" : "String",
          "Description" : "Name of DynamoDB table to be used for underlying data store. If left blank a new table will be created.",
          "MinLength" : "0"
      },
      "ShouldCreateRole" : {
        "Type" : "String",        
        "AllowedValues" : ["true", "false"],
        "Description" : "If true then the role for the Lambda function will be created with the CloudFormation stack."
      },  
      "RoleARN" : {
          "Type" : "String",
          "Description" : "ARN of the IAM Role used to run the Lambda function. If left blank a new role will be created.",
          "MinLength" : "0"
      }
    },
  
    "Conditions" : {
      "CreateDynamoTable" : {"Fn::Equals" : [{"Ref" : "ShouldCreateTable"}, "true"]},
      "TableNameGenerated" : {"Fn::Equals" : [{"Ref" : "TableName"}, ""]},
      "CreateRole":{"Fn::Equals" : [{"Ref" : "ShouldCreateRole"}, "true"]},
      "RoleGenerated" : {"Fn::Equals" : [{"Ref" : "RoleARN"}, ""]}
    },
  
    "Resources" : {
  
      "Get" : {
        "Type" : "AWS::Serverless::Function",
        "Properties": {
          ...
          "Role": {"Fn::If" : ["CreateRole", {"Fn::GetAtt":["LambdaRole", "Arn"]}, {"Ref":"RoleARN"}]},
          "Environment" : {
            "Variables" : {
              "AppDynamoTable" : { "Fn::If" : ["CreateDynamoTable", {"Ref":"DynamoTable"}, { "Ref" : "TableName" } ] }
            }
          },
          ...
        }
      },
  
      "LambdaRole":{
          "Type":"AWS::IAM::Role",
          "Condition":"CreateRole",
          "Properties":{
              "ManagedPolicyArns":["arn:aws:iam::aws:policy/AWSLambdaFullAccess"],
              "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",
                                  "Action": [
                                      "dynamodb:Query",
                                      "dynamodb:Scan",
                                      "dynamodb:PutItem",
                                      "dynamodb:GetItem",
                                      "dynamodb:UpdateItem",
                                      "dynamodb:DeleteItem",
                                      "logs:CreateLogGroup",
                                      "logs:CreateLogStream",
                                      "logs:PutLogEvents"
                                  ],
                                  "Resource": [
                                      "*"
                                  ]
                              }
                          ]
                      }
                  }
              ]
          }
      },
  
      "DynamoTable" : {
          "Type" : "AWS::DynamoDB::Table",
          "Condition" : "CreateDynamoTable",
          "Properties" : {
              "TableName" : { "Fn::If" : ["TableNameGenerated", {"Ref" : "AWS::NoValue" }, { "Ref" : "TableName" } ] },
              "AttributeDefinitions": [
                  { "AttributeName" : "id", "AttributeType" : "S" }
              ],
              "KeySchema" : [
                  { "AttributeName" : "id", "KeyType" : "HASH"}
              ],          
              "ProvisionedThroughput" : { "ReadCapacityUnits" : "5", "WriteCapacityUnits" : "5" }
          }
      }
    },
  
    "Outputs" : {
      "UnderlyingDynamoTable" : {
          "Value" : { "Fn::If" : ["CreateDynamoTable", {"Ref":"DynamoTable"}, { "Ref" : "TableName" } ] }
      },
      "LambdaRole" : {
          "Value" : {"Fn::If" : ["CreateRole", {"Fn::GetAtt":["LambdaRole", "Arn"]}, {"Ref":"RoleARN"} ] }
      }
    }
  }
  </code></pre>
  
  <p>I could just remove the creation step and create the resource manually before the API Gateway, but it seems like what I am trying to do should be possible.</p>