Repository: aws/chalice

Issue:
Error creating Lambda event source mapping: Function does not exist
Another terraform packaging issue here, when using additional resources (sqs queues or s3 buckets) that are created outside of the chalice application, but packaged and deployed together with terraform. There seems to be a missing dependency between the lambda permission and the lambda function. Additionally there seems no way to define the dependency between the bucket notification and the bucket itself:
```
"aws_lambda_function": {
    "lambda_function_name": {
        "function_name": "lambda_function_name",
        "role": "${aws_iam_role.default-role.arn}",
        ...
    },
"aws_s3_bucket_notification": {
    "project-bucket-name_notify": {
        "bucket": "project-bucket-name",
        "lambda_function": [
            {
                "events": [
                    "s3:ObjectCreated:*"
                ],
                "lambda_function_arn": "${aws_lambda_function.lambda_function_name.arn}"
            }
        ]
    }
},
"aws_lambda_permission": {
    "lambda_function_name-s3event": {
        "action": "lambda:InvokeFunction",
        "function_name": "lambda_function_name",
        "source_arn": "arn:*:s3:::project-bucket-name"
        ...
    }...
}
```
&&
```
resource "aws_s3_bucket" "project_bucket" {
    bucket = "project-bucket-name"
    ...
}
```

This produces the following errors on first deploy (not on subsequent deploys):
```
Error: Error putting S3 notification configuration: InvalidArgument: Unable to validate the following destination configurations
	status code: 400...

Error: Error creating Lambda event source mapping: InvalidParameterValueException: Function does not exist
{
  RespMetadata: {
    StatusCode: 400,...
  },
  Message_: "Function does not exist",...
}
```

Adding a dependency to the permission resolves the error `Error creating Lambda event source mapping`:
```
"aws_lambda_permission": {
    "read_mail-s3event": {
        "action": "lambda:InvokeFunction",
        "function_name": "lambda_function_name",
        "source_arn": "arn:*:s3:::project-bucket-name"
        "depends_on": ["aws_lambda_function.lambda_function_name"]
    },
}
```

Discussion:
kapilt: not sure why ci went awol

Patch:
diff --git a/chalice/package.py b/chalice/package.py
index f04c4f1..5319b51 100644
--- a/chalice/package.py
+++ b/chalice/package.py
@@ -893,7 +893,7 @@ class TerraformGenerator(TemplateGenerator):
             resource.resource_name] = {
             'statement_id': resource.resource_name,
             'action': 'lambda:InvokeFunction',
-            'function_name': resource.lambda_function.function_name,
+            'function_name': self._fref(resource.lambda_function),
             'principal': self._options.service_principal('s3'),
             'source_arn': ('arn:${data.aws_partition.chalice.partition}:'
                            's3:::%s' % resource.bucket)
@@ -908,7 +908,7 @@ class TerraformGenerator(TemplateGenerator):
                 ":%(account_id)s:%(queue)s",
                 queue=resource.queue),
             'batch_size': resource.batch_size,
-            'function_name': resource.lambda_function.function_name,
+            'function_name': self._fref(resource.lambda_function)
         }
 
     def _generate_kinesiseventsource(self, resource, template):
@@ -921,7 +921,7 @@ class TerraformGenerator(TemplateGenerator):
                 stream=resource.stream),
             'batch_size': resource.batch_size,
             'starting_position': resource.starting_position,
-            'function_name': resource.lambda_function.function_name,
+            'function_name': self._fref(resource.lambda_function)
         }
 
     def _generate_dynamodbeventsource(self, resource, template):
@@ -931,7 +931,7 @@ class TerraformGenerator(TemplateGenerator):
             'event_source_arn': resource.stream_arn,
             'batch_size': resource.batch_size,
             'starting_position': resource.starting_position,
-            'function_name': resource.lambda_function.function_name,
+            'function_name': self._fref(resource.lambda_function),
         }
 
     def _generate_snslambdasubscription(self, resource, template):
@@ -952,7 +952,7 @@ class TerraformGenerator(TemplateGenerator):
         }
         template['resource'].setdefault('aws_lambda_permission', {})[
             resource.resource_name] = {
-            'function_name': resource.lambda_function.function_name,
+            'function_name': self._fref(resource.lambda_function),
             'action': 'lambda:InvokeFunction',
             'principal': self._options.service_principal('sns'),
             'source_arn': topic_arn
@@ -994,7 +994,7 @@ class TerraformGenerator(TemplateGenerator):
         template['resource'].setdefault(
             'aws_lambda_permission', {})[
             resource.resource_name] = {
-            'function_name': resource.lambda_function.function_name,
+            'function_name': self._fref(resource.lambda_function),
             'action': 'lambda:InvokeFunction',
             'principal': self._options.service_principal('events'),
             'source_arn': "${aws_cloudwatch_event_rule.%s.arn}" % (
@@ -1112,7 +1112,7 @@ class TerraformGenerator(TemplateGenerator):
 
         template['resource'].setdefault('aws_lambda_permission', {})[
             resource.resource_name + '_invoke'] = {
-            'function_name': resource.lambda_function.function_name,
+            'function_name': self._fref(resource.lambda_function),
             'action': 'lambda:InvokeFunction',
             'principal': self._options.service_principal('apigateway'),
             'source_arn':
@@ -1134,7 +1134,7 @@ class TerraformGenerator(TemplateGenerator):
         for auth in resource.authorizers:
             template['resource']['aws_lambda_permission'][
                 auth.resource_name + '_invoke'] = {
-                'function_name': auth.function_name,
+                'function_name': self._fref(auth),
                 'action': 'lambda:InvokeFunction',
                 'principal': self._options.service_principal('apigateway'),
                 'source_arn': (


Test patch:
diff --git a/tests/unit/test_package.py b/tests/unit/test_package.py
index 4f33fc1..bca19c8 100644
--- a/tests/unit/test_package.py
+++ b/tests/unit/test_package.py
@@ -515,7 +515,7 @@ class TestTerraformTemplate(TemplateTestBase):
         assert resources['aws_lambda_function']
         # Along with permission to invoke from API Gateway.
         assert list(resources['aws_lambda_permission'].values())[0] == {
-            'function_name': 'sample_app-dev',
+            'function_name': '${aws_lambda_function.api_handler.arn}',
             'action': 'lambda:InvokeFunction',
             'principal': 'apigateway.amazonaws.com',
             'source_arn': (
@@ -561,7 +561,7 @@ class TestTerraformTemplate(TemplateTestBase):
         # Along with permission to invoke from API Gateway.
         assert resources['aws_lambda_permission']['myauth_invoke'] == {
             'action': 'lambda:InvokeFunction',
-            'function_name': 'sample_app-dev-myauth',
+            'function_name': '${aws_lambda_function.myauth.arn}',
             'principal': 'apigateway.amazonaws.com',
             'source_arn': (
                 '${aws_api_gateway_rest_api.rest_api.execution_arn}/*')
@@ -640,7 +640,7 @@ class TestTerraformTemplate(TemplateTestBase):
         assert template['resource']['aws_lambda_permission'][
                    'handler-s3event'] == {
                    'action': 'lambda:InvokeFunction',
-                   'function_name': 'sample_app-dev-handler',
+                   'function_name': '${aws_lambda_function.handler.arn}',
                    'principal': 's3.amazonaws.com',
                    'source_arn': (
                        'arn:${data.aws_partition.chalice.partition}:s3:::foo'),
@@ -701,7 +701,7 @@ class TestTerraformTemplate(TemplateTestBase):
 
         assert template['resource']['aws_lambda_permission'][
                    'handler-sns-subscription'] == {
-                   'function_name': 'sample_app-dev-handler',
+                   'function_name': '${aws_lambda_function.handler.arn}',
                    'action': 'lambda:InvokeFunction',
                    'principal': 'sns.amazonaws.com',
                    'source_arn': 'arn:aws:sns:space-leo-1:1234567890:foo'
@@ -725,7 +725,7 @@ class TestTerraformTemplate(TemplateTestBase):
                        'arn:${data.aws_partition.chalice.partition}:sqs'
                        ':${data.aws_region.chalice.name}:'
                        '${data.aws_caller_identity.chalice.account_id}:foo'),
-                   'function_name': 'sample_app-dev-handler',
+                   'function_name': '${aws_lambda_function.handler.arn}',
                    'batch_size': 5
                }
 
@@ -749,7 +749,7 @@ class TestTerraformTemplate(TemplateTestBase):
                        ':${data.aws_region.chalice.name}:'
                        '${data.aws_caller_identity.chalice.account_id}'
                        ':stream/mystream'),
-                   'function_name': 'sample_app-dev-handler',
+                   'function_name': '${aws_lambda_function.handler.arn}',
                    'starting_position': 'TRIM_HORIZON',
                    'batch_size': 5
                }
@@ -771,7 +771,7 @@ class TestTerraformTemplate(TemplateTestBase):
                    'aws_lambda_event_source_mapping'][
                    'handler-dynamodb-event-source'] == {
                        'event_source_arn': 'arn:aws:...:stream',
-                       'function_name': 'sample_app-dev-handler',
+                       'function_name': '${aws_lambda_function.handler.arn}',
                        'starting_position': 'TRIM_HORIZON',
                        'batch_size': 5
                    }