Repository: localstack/localstack

Issue:
samlocal not returning on second and later deploys
### Is there an existing issue for this?

- [X] I have searched the existing issues

### Current Behavior

When executing samlocal deploy twice without updating the template it gets stuck after the deploy step (before the step of the output is shown)

Also i left it running for long time checking if it could finish and around 2 hours laters a kinesis stacktrace appeared on the logs on the docker container

```
localstack_main  | 2022-05-26T09:14:21.135:INFO:localstack.services.kinesis.kinesis_mock_server: [io-compute-1] WARN  2022-05-26 09:14:21,132 k.m.cache.Cache x-amzn-RequestId=3a527f8b-dcd4-11ec-ac09-ad4f3aa847a9, action=GetRecords, contextId=3a527f8a-dcd4-11ec-ac09-ad4f3aa847a9, x-amz-id-2=WLxUzW0heAIF5/pAXeHZEM0qejb1MRVum6fgYxuWPz146y+KGwkjmNwjv9IWngSM8RaihKhqcdibbhN4kruU+3p8/FlKZnTp, contentType=application/x-amz-json-1.1 - Getting records was unuccessful
localstack_main  | 2022-05-26T09:14:21.135:INFO:localstack.services.kinesis.kinesis_mock_server: kinesis.mock.ExpiredIteratorException: The shard iterator has expired. Shard iterators are only valid for 300 seconds
localstack_main  | 2022-05-26T09:14:21.135:INFO:localstack.services.kinesis.kinesis_mock_server: at kinesis.mock.models.ShardIterator.parse(ShardIterator.scala:58)
localstack_main  | 2022-05-26T09:14:21.136:INFO:localstack.services.kinesis.kinesis_mock_server: at kinesis.mock.api.GetRecordsRequest.$anonfun$getRecords$1(GetRecordsRequest.scala:24)
localstack_main  | 2022-05-26T09:14:21.136:INFO:localstack.services.kinesis.kinesis_mock_server: at cats.effect.IOFiber.runLoop(IOFiber.scala:358)
localstack_main  | 2022-05-26T09:14:21.136:INFO:localstack.services.kinesis.kinesis_mock_server: at cats.effect.IOFiber.asyncContinueSuccessfulR(IOFiber.scala:1338)
localstack_main  | 2022-05-26T09:14:21.136:INFO:localstack.services.kinesis.kinesis_mock_server: at cats.effect.IOFiber.run(IOFiber.scala:140)
localstack_main  | 2022-05-26T09:14:21.136:INFO:localstack.services.kinesis.kinesis_mock_server: at cats.effect.unsafe.WorkerThread.run(WorkerThread.scala:549)
localstack_main  | 2022-05-26T09:14:21.136:INFO:localstack.services.kinesis.kinesis_mock_server: at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:519)
localstack_main  | 2022-05-26T09:14:21.136:INFO:localstack.services.kinesis.kinesis_mock_server: at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:192)
localstack_main  | 2022-05-26T09:14:21.140:DEBUG:localstack.services.dynamodbstreams.provider: Shard iterator for underlying kinesis stream expired
localstack_main  | 2022-05-26T09:14:21.146:INFO:localstack.utils.threads: Thread run method <bound method StreamEventSourceListener._listen_to_shard_and_invoke_lambda of <localstack.services.awslambda.event_source_listeners.dynamodb_event_source_listener.DynamoDBEventSourceListener object at 0x7fa9b98dbb50>>({'function_arn': 'arn:aws:lambda:us-west-2:000000000000:function:sandbox-events-generator-worker', 'stream_arn': 'arn:aws:dynamodb:us-west-2:000000000000:table/sandbox-events-generator-jobs/stream/2022-05-26T07:20:41.621', 'batch_size': 1, 'parallelization_factor': 1, 'lock_discriminator': '60cf3f5b-11af-4b81-840b-c62920e5f0cb/arn:aws:dynamodb:us-west-2:000000000000:table/sandbox-events-generator-jobs/stream/2022-05-26T07:20:41.621/shardId-00000001653500000000-000000000000', 'shard_id': 'shardId-00000001653500000000-000000000000', 'stream_client': <botocore.client.DynamoDBStreams object at 0x7fa9bc321810>, 'shard_iterator': 'AAAAAAAAAAEqli29q/ZrvGK0Qv58Ys0UOaNNnguVf1262Mr190addTsT21HR/XdUWnOyHg1FUUW4R774Gy1X2lmyJQMqkTKuh5nVySaVOmGBrjNRHabrLqpzejZqpTYba8lThyNRgs95fCdid2O4GmMSpaBEXElMSDpWQ/LU/Hb5NG3P0pInAfuajJsFpH8TjqTbNHNf3EBxC0OYM1EfSBu183HSLUkECOBmWfp87OOWPH+WiWiWzQ==', 'failure_destination': None, 'max_num_retries': inf}) failed: An error occurred (ExpiredIteratorException) when calling the GetRecords operation: Shard iterator has expired Traceback (most recent call last):
localstack_main  |   File "/opt/code/localstack/localstack/utils/threads.py", line 39, in run
localstack_main  |     result = self.func(self.params, **kwargs)
localstack_main  |   File "/opt/code/localstack/localstack/services/awslambda/event_source_listeners/stream_event_source_listener.py", line 182, in _listen_to_shard_and_invoke_lambda
localstack_main  |     records_response = stream_client.get_records(
localstack_main  |   File "/opt/code/localstack/.venv/lib/python3.10/site-packages/botocore/client.py", line 508, in _api_call
localstack_main  |     return self._make_api_call(operation_name, kwargs)
localstack_main  |   File "/opt/code/localstack/.venv/lib/python3.10/site-packages/botocore/client.py", line 911, in _make_api_call
localstack_main  |     raise error_class(parsed_response, operation_name)
localstack_main  | botocore.errorfactory.ExpiredIteratorException: An error occurred (ExpiredIteratorException) when calling the GetRecords operation: Shard iterator has expired
```

### Expected Behavior

the command finishes properly like in the first run

### How are you starting LocalStack?

With a docker-compose file

### Steps To Reproduce

#### How are you starting localstack (e.g., `bin/localstack` command, arguments, or `docker-compose.yml`)

docker-compose up -d

docker-compose.yml:

```
version: "3.8"

services:
  localstack:
    container_name: "${LOCALSTACK_DOCKER_NAME-localstack_main}"
    image: localstack/localstack:latest
    network_mode: bridge
    ports:
      - "127.0.0.1:53:53"                # only required for Pro (DNS)
      - "127.0.0.1:53:53/udp"            # only required for Pro (DNS)
      - "127.0.0.1:443:443"              # only required for Pro (LocalStack HTTPS Edge Proxy)
      - "127.0.0.1:4510-4559:4510-4559"  # external service port range
      - "127.0.0.1:4566:4566"            # LocalStack Edge Proxy
    environment:
      - SERVICES=dynamodb,cloudformation,lambda,s3,sts,apigateway,iam
      - DEBUG=1
      - HOST_TMP_FOLDER=${TMPDIR:-/tmp/}localstack
      - DOCKER_HOST=unix:///var/run/docker.sock
    volumes:
      - "${TMPDIR:-/tmp}/localstack:/tmp/localstack"
      - "/var/run/docker.sock:/var/run/docker.sock"
    networks:
      net1:
        ipv4_address: 10.10.100.3
networks:
  net1:
    driver: bridge
    enable_ipv6: false
    ipam:
      config:
      - subnet: 10.10.100.0/24
        gateway: 10.10.100.32
```

template.yaml

```
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  test-sam
  
  SAM Template for test

Parameters:
  Environment:
    Type: String
    Default: sandbox
  Project:
    Type: String
    Default: project
  Component:
    Type: String
    Default: component
  DynamoDBUrl:
    Type: String
    Default: LOCALSTACK_HOSTNAME
  UseLocalstack:
    Type: String
    Default: 'true'
    AllowedValues: [true, false]

Conditions:
  UseLocalStack: !Equals [!Ref UseLocalstack, 'true']

# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
  Function:
    Timeout: 360
    Environment:
      Variables:
        REGION: !Ref "AWS::Region"
        ENVIRONMENT: !Ref Environment
        PROJECT: !Ref Project
        COMPONENT: !Ref Component
        DYNAMO_DB_JOB_TABLE: !Ref JobTable
        DYNAMO_DB_URL: !Ref DynamoDBUrl

Resources:
  TestFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Join [ "-", [ !Ref Environment, !Ref Component, "api" ] ]
      CodeUri: api/
      Handler: api
      Runtime: go1.x
      Architectures:
        - x86_64
      Tracing: Active
      Events:
        CatchAll:
          Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
          Properties:
            Path: /{proxy+}
            Method: ANY
      Environment:
        Variables:
          API_GATEWAY_V1_ENDPOINT: !Sub "http://localhost:4566/restapis/${ApiGatewayIdV1}/"
      Policies:
        - DynamoDBCrudPolicy:
            TableName: !Ref JobTable
        - AmazonAPIGatewayInvokeFullAccess

  WorkerFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Join [ "-", [ !Ref Environment, !Ref Component, "worker" ] ]
      CodeUri: worker/
      Handler: worker
      Runtime: go1.x
      Architectures:
        - x86_64
      MemorySize: 512
      Timeout: 180
      Tracing: Active
      Events:
        JobTable:
          Type: DynamoDB
          Properties:
            Stream: !GetAtt JobTable.StreamArn
            StartingPosition: TRIM_HORIZON
            BatchSize: 1
      Environment:
        Variables:
          API_GATEWAY_ENDPOINT: !Sub "http://localhost:4566/restapis/${ApiGatewayIdV2}/"
             
          API_GATEWAY_BULK_ENDPOINT: !Sub "http://localhost:4566/restapis/${ApiGatewayIdV2}/"
      Policies:
        - DynamoDBCrudPolicy:
            TableName: !Ref JobTable
        - AmazonSNSFullAccess
        - AmazonAPIGatewayInvokeFullAccess

  JobTable:
    Type: AWS::DynamoDB::Table
    Properties:
      TableName: !Join [ "-", [ !Ref Environment, !Ref Component, "jobs" ] ]
      AttributeDefinitions:
        - AttributeName: Id
          AttributeType: S
      KeySchema:
        - AttributeName: Id
          KeyType: HASH
      BillingMode: PAY_PER_REQUEST
      StreamSpecification:
        StreamViewType: NEW_IMAGE


Outputs:
  # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function
  # Find out more about other implicit resources you can reference within SAM
  # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api
  EventsGeneratorAPI:
    Description: "API Gateway endpoint URL for Prod environment for First Function"
    Value: !Sub "http://localhost:4566/restapis/${ServerlessRestApi}/Prod/api/"

```

#### Client commands (e.g., AWS SDK code snippet, or sequence of "awslocal" commands)

    awslocal s3 mb s3://mybucket


### Environment

```markdown
- OS: 

MacOS Monterey 12.4

- LocalStack: 
LocalStack version: 0.14.3.1
LocalStack Docker container id: 95b639ae197e
LocalStack build date: 2022-05-25
LocalStack build git hash: 2a564393
```


### Anything else?

_No response_


Discussion:
I'm seeing this issue as well. My sam cli hangs on

```
 Waiting for stack create/update to complete
```

and my localstack output hangs on

```
localstack_main | 2022-06-22T15:44:46.888:INFO:localstack.utils.cloudformation.template_deployer: Updating resource <my-function-name> of type Lambda::Function
localstack_main | 2022-06-22T15:44:47.500:INFO:localstack.utils.cloudformation.template_deployer: Updating resource <my-function-name-role> of type IAM::Role
```
I am also experiencing a similar problem. The first `samlocal deploy` succeeds, but any subsequent `deploy` hangs even when no template changes have been made. I’m not sure if this is related, but I thought I would share my observations in case they help.

Local environment:

```
macOS Monterey (Darwin 21.5.0)

% samlocal --version
SAM CLI, version 1.53.0

% localstack --version
1.0.3
```

Localstack is being started with `localstack start --no-banner -d`. These are the results of the first `deploy`:

```
2022-08-04 13:15:39 - Waiting for stack create/update to complete

CloudFormation events from stack operations (refresh every 0.5 seconds)
-----------------------------------------------------------------------------------------------------------------------------
ResourceStatus                  ResourceType                    LogicalResourceId               ResourceStatusReason
-----------------------------------------------------------------------------------------------------------------------------
CREATE_COMPLETE                 AWS::CloudFormation::Stack      DatabaseTable                   -
CREATE_COMPLETE                 AWS::CloudFormation::Stack      test-project                    -
-----------------------------------------------------------------------------------------------------------------------------

Successfully created/updated stack - test-project in us-west-2
```

Here are the results of all further deployments where it “hangs” until the timeout.

```
2022-08-04 13:16:08 - Waiting for stack create/update to complete

CloudFormation events from stack operations (refresh every 0.5 seconds)
-----------------------------------------------------------------------------------------------------------------------------
ResourceStatus                  ResourceType                    LogicalResourceId               ResourceStatusReason
-----------------------------------------------------------------------------------------------------------------------------
UPDATE_COMPLETE                 AWS::CloudFormation::Stack      DatabaseTable                   -
CREATE_COMPLETE                 AWS::CloudFormation::Stack      test-project                    -
-----------------------------------------------------------------------------------------------------------------------------

Error: Failed to create/update the stack: test-project, Waiter StackUpdateComplete failed: Max attempts exceeded
```

While the `samlocal deploy` appears to be hanging prior to the timeout, the client is actually sending describe-stacks requests:

```
2022-08-04T20:16:14.193  INFO --- [   asgi_gw_0] localstack.request.aws     : AWS cloudformation.DescribeStacks => 200
2022-08-04T20:16:19.211  INFO --- [   asgi_gw_0] localstack.request.aws     : AWS cloudformation.DescribeStacks => 200
…
```

The stack status during this polling period shows as `CREATE_COMPLETE`.

```
            "StackStatus": "CREATE_COMPLETE",
            "StackStatusReason": "Deployment succeeded",
```

It seems that in my case, the `sam` client is polling for a stack status of `UPDATE_COMPLETE` while the stack is set to `CREATE_COMPLETE`. I tested this by temporarily modifying the `samcli/lib/deploy/deployer.py` waiter.

```
        # Pick the right waiter
        if stack_operation == "CREATE":
            waiter = self._client.get_waiter("stack_create_complete")
        elif stack_operation == "UPDATE":
            waiter = self._client.get_waiter("stack_update_complete")
```

When I change the **“UPDATE”** `get_waiter` from `stack_update_complete` to `stack_create_complete`, all further `samlocal deploy` commands complete successfully.

I hope this information helps.
Thanks for reporting @acampoh @ahahn95 @edevenport , and apologies for the long delay on this one. We have now added a couple of enhancements in CloudFormation, to improve the integration with SAM/`samlocal`. Can you please pull the `latest` Docker image and give it another try? Please keep us posted on how it goes.. Thanks!
Would it be fair to say that `samlocal` isn't that well supported and we should instead use `awslocal cloudformation`? I'm experiencing this problem, and others (step functions don't persist) with v1.0.0 but I'm using `samlocal package` and `samlocal deploy`. Perhaps I should just use `awslocal cloudformation` directly?
Unfortunately this issue is a dead end for me. I've done a docker pull of the latest, I've ensured everything is in the same region, all to no avail. If I do a `sam deploy` to a fresh localstack, it works the first time, but subsequent deploys are hit and miss, and I can't depend on localstack for time critical work. It's a pity, it would have really made my local development easy.
Hi @djpentz , can you please share a small, isolated example of your SAM template, to help us replicate the issue you've been facing..? Thanks!

Regarding `samlocal` vs `awslocal cloudformation` - both are effectively mapping to CloudFormation deployments under the covers, so there may be some slight differences (e.g., how SAM transforms the template), but in the end it should not make too much of a difference. If you can share your use case, we'll be happy to look into it. 👍 
Hi @djpentz, quick follow-up - can you please provide a short update on this issue, have you been able to get it working in the meantime? Please let us know if the problem persists, or if we can close this issue.. Thanks!

Resolving patch:
diff --git a/localstack/utils/cloudformation/template_deployer.py b/localstack/utils/cloudformation/template_deployer.py
--- a/localstack/utils/cloudformation/template_deployer.py
+++ b/localstack/utils/cloudformation/template_deployer.py
@@ -1066,7 +1066,11 @@ def deploy_stack(self):
             raise
 
     def apply_change_set(self, change_set):
-        action = "UPDATE" if change_set.stack.status == "CREATE_COMPLETE" else "CREATE"
+        action = (
+            "UPDATE"
+            if change_set.stack.status in {"CREATE_COMPLETE", "UPDATE_COMPLETE"}
+            else "CREATE"
+        )
         change_set.stack.set_stack_status(f"{action}_IN_PROGRESS")
 
         # update attributes that the stack inherits from the changeset


Test patch:
diff --git a/tests/integration/cloudformation/api/test_stacks.py b/tests/integration/cloudformation/api/test_stacks.py
--- a/tests/integration/cloudformation/api/test_stacks.py
+++ b/tests/integration/cloudformation/api/test_stacks.py
@@ -426,3 +426,78 @@ def test_prevent_resource_deletion(deploy_cfn_template, cfn_client, sns_client,
     cfn_client.delete_stack(StackName=stack.stack_name)
 
     sns_client.get_topic_attributes(TopicArn=stack.outputs["TopicArn"])
+
+
+@pytest.mark.aws_validated
+@pytest.mark.skip_snapshot_verify(
+    paths=[
+        # parameters may be out of order
+        "$..Stacks..Parameters",
+    ]
+)
+def test_updating_an_updated_stack_sets_status(deploy_cfn_template, cfn_client, snapshot):
+    """
+    The status of a stack that has been updated twice should be "UPDATE_COMPLETE"
+    """
+    snapshot.add_transformer(snapshot.transform.cloudformation_api())
+
+    # need multiple templates to support updates to the stack
+    template_1 = load_file(
+        os.path.join(os.path.dirname(__file__), "../../templates/stack_update_1.yaml")
+    )
+    template_2 = load_file(
+        os.path.join(os.path.dirname(__file__), "../../templates/stack_update_2.yaml")
+    )
+    template_3 = load_file(
+        os.path.join(os.path.dirname(__file__), "../../templates/stack_update_3.yaml")
+    )
+
+    topic_1_name = f"topic-1-{short_uid()}"
+    topic_2_name = f"topic-2-{short_uid()}"
+    topic_3_name = f"topic-3-{short_uid()}"
+    snapshot.add_transformers_list(
+        [
+            snapshot.transform.regex(topic_1_name, "topic-1"),
+            snapshot.transform.regex(topic_2_name, "topic-2"),
+            snapshot.transform.regex(topic_3_name, "topic-3"),
+        ]
+    )
+
+    parameters = {
+        "Topic1Name": topic_1_name,
+        "Topic2Name": topic_2_name,
+        "Topic3Name": topic_3_name,
+    }
+
+    def wait_for(waiter_type: str) -> None:
+        cfn_client.get_waiter(waiter_type).wait(
+            StackName=stack.stack_name,
+            WaiterConfig={
+                "Delay": 5,
+                "MaxAttempts": 5,
+            },
+        )
+
+    stack = deploy_cfn_template(template=template_1, parameters=parameters)
+    wait_for("stack_create_complete")
+
+    # update the stack
+    deploy_cfn_template(
+        template=template_2,
+        is_update=True,
+        stack_name=stack.stack_name,
+        parameters=parameters,
+    )
+    wait_for("stack_update_complete")
+
+    # update the stack again
+    deploy_cfn_template(
+        template=template_3,
+        is_update=True,
+        stack_name=stack.stack_name,
+        parameters=parameters,
+    )
+    wait_for("stack_update_complete")
+
+    res = cfn_client.describe_stacks(StackName=stack.stack_name)
+    snapshot.match("describe-result", res)
diff --git a/tests/integration/cloudformation/api/test_stacks.snapshot.json b/tests/integration/cloudformation/api/test_stacks.snapshot.json
--- a/tests/integration/cloudformation/api/test_stacks.snapshot.json
+++ b/tests/integration/cloudformation/api/test_stacks.snapshot.json
@@ -440,5 +440,53 @@
         }
       }
     }
+  },
+  "tests/integration/cloudformation/api/test_stacks.py::test_updating_an_updated_stack_sets_status": {
+    "recorded-date": "02-12-2022, 11:19:41",
+    "recorded-content": {
+      "describe-result": {
+        "Stacks": [
+          {
+            "Capabilities": [
+              "CAPABILITY_AUTO_EXPAND",
+              "CAPABILITY_IAM",
+              "CAPABILITY_NAMED_IAM"
+            ],
+            "ChangeSetId": "arn:aws:cloudformation:<region>:111111111111:changeSet/<resource:1>",
+            "CreationTime": "datetime",
+            "DisableRollback": false,
+            "DriftInformation": {
+              "StackDriftStatus": "NOT_CHECKED"
+            },
+            "EnableTerminationProtection": false,
+            "LastUpdatedTime": "datetime",
+            "NotificationARNs": [],
+            "Parameters": [
+              {
+                "ParameterKey": "Topic2Name",
+                "ParameterValue": "topic-2"
+              },
+              {
+                "ParameterKey": "Topic1Name",
+                "ParameterValue": "topic-1"
+              },
+              {
+                "ParameterKey": "Topic3Name",
+                "ParameterValue": "topic-3"
+              }
+            ],
+            "RollbackConfiguration": {},
+            "StackId": "arn:aws:cloudformation:<region>:111111111111:stack/<stack-name:1>/<resource:2>",
+            "StackName": "<stack-name:1>",
+            "StackStatus": "UPDATE_COMPLETE",
+            "Tags": []
+          }
+        ],
+        "ResponseMetadata": {
+          "HTTPHeaders": {},
+          "HTTPStatusCode": 200
+        }
+      }
+    }
   }
-}
\ No newline at end of file
+}
diff --git a/tests/integration/templates/stack_update_1.yaml b/tests/integration/templates/stack_update_1.yaml
new file mode 100644
--- /dev/null
+++ b/tests/integration/templates/stack_update_1.yaml
@@ -0,0 +1,15 @@
+AWSTemplateFormatVersion: '2010-09-09'
+Parameters:
+  Topic1Name:
+    Type: String
+  Topic2Name:
+    Type: String
+  Topic3Name:
+    Type: String
+Resources:
+  topic1:
+    Type: AWS::SNS::Topic
+    Properties:
+      TopicName: !Ref Topic1Name
+    UpdateReplacePolicy: Delete
+    DeletionPolicy: Delete
diff --git a/tests/integration/templates/stack_update_2.yaml b/tests/integration/templates/stack_update_2.yaml
new file mode 100644
--- /dev/null
+++ b/tests/integration/templates/stack_update_2.yaml
@@ -0,0 +1,21 @@
+AWSTemplateFormatVersion: '2010-09-09'
+Parameters:
+  Topic1Name:
+    Type: String
+  Topic2Name:
+    Type: String
+  Topic3Name:
+    Type: String
+Resources:
+  topic1:
+    Type: AWS::SNS::Topic
+    Properties:
+      TopicName: !Ref Topic1Name
+    UpdateReplacePolicy: Delete
+    DeletionPolicy: Delete
+  topic2:
+    Type: AWS::SNS::Topic
+    Properties:
+      TopicName: !Ref Topic2Name
+    UpdateReplacePolicy: Delete
+    DeletionPolicy: Delete
diff --git a/tests/integration/templates/stack_update_3.yaml b/tests/integration/templates/stack_update_3.yaml
new file mode 100644
--- /dev/null
+++ b/tests/integration/templates/stack_update_3.yaml
@@ -0,0 +1,27 @@
+AWSTemplateFormatVersion: '2010-09-09'
+Parameters:
+  Topic1Name:
+    Type: String
+  Topic2Name:
+    Type: String
+  Topic3Name:
+    Type: String
+Resources:
+  topic1:
+    Type: AWS::SNS::Topic
+    Properties:
+      TopicName: !Ref Topic1Name
+    UpdateReplacePolicy: Delete
+    DeletionPolicy: Delete
+  topic2:
+    Type: AWS::SNS::Topic
+    Properties:
+      TopicName: !Ref Topic2Name
+    UpdateReplacePolicy: Delete
+    DeletionPolicy: Delete
+  topic3:
+    Type: AWS::SNS::Topic
+    Properties:
+      TopicName: !Ref Topic3Name
+    UpdateReplacePolicy: Delete
+    DeletionPolicy: Delete