Skip to content

Commit

Permalink
lambda_event: Add support for FunctionResponseTypes (ansible-collecti…
Browse files Browse the repository at this point in the history
…ons#1209)

lambda_event: Add support for FunctionResponseTypes

SUMMARY

Resolves ansible-collections#1081
Added support to set FunctionResponseTypes when creating lambda event source mappings

ISSUE TYPE


Feature Pull Request

COMPONENT NAME

lambda_event
ADDITIONAL INFORMATION


Can be tested using below playbook (needs a dynamo db table and lambda function with appropriate access/policy/role)

---
- name: lambda_event
  hosts: localhost
  gather_facts: false
  tasks:
    - name: Create DynamoDB stream event mapping (trigger)
      amazon.aws.lambda_event:
        state: present
        event_source: stream
        function_name: my-test-function
        source_params:
          source_arn: arn:aws:dynamodb:us-east-2:721234567890:table/my-test-table/stream/2022-10-26T17:55:25.232
          enabled: True
          batch_size: 500
          starting_position: LATEST
          function_response_types:
            - ReportBatchItemFailures
      register: event

    - name: Get info on above trigger
      command: 'aws lambda get-event-source-mapping --uuid {{ event.events.uuid }}'
      environment:
        AWS_ACCESS_KEY_ID: "{{ aws_access_key }}"
        AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}"
        AWS_SESSION_TOKEN: "{{ security_token | default('') }}"
        AWS_DEFAULT_REGION: "{{ aws_region }}"
      register: my_function_details

    - name: convert it to an object
      set_fact:
        my_function_details_obj: "{{ my_function_details.stdout | from_json }}"

    - assert:
        that:
          - my_function_details_obj.FunctionResponseTypes is defined
          - my_function_details_obj.FunctionResponseTypes | length > 0
          - my_function_details_obj.FunctionResponseTypes[0] == "ReportBatchItemFailures"

Reviewed-by: Bikouo Aubin <None>
Reviewed-by: Mike Graves <mgraves@redhat.com>
Reviewed-by: Mandar Kulkarni <mandar242@gmail.com>
Reviewed-by: Alina Buzachis <None>
Reviewed-by: Gonéri Le Bouder <goneri@lebouder.net>
Reviewed-by: GomathiselviS <None>
  • Loading branch information
mandar242 authored and alinabuzachis committed Apr 27, 2023
1 parent 67bc04d commit 9528072
Show file tree
Hide file tree
Showing 10 changed files with 339 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
minor_changes:
- lambda_event - Added support to set FunctionResponseTypes when creating lambda event source mappings (https://github.com/ansible-collections/amazon.aws/pull/1209).
32 changes: 28 additions & 4 deletions plugins/modules/lambda_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@
- Required when I(event_source=stream).
choices: [TRIM_HORIZON,LATEST]
type: str
function_response_types:
description:
- (Streams and Amazon SQS) A list of current response type enums applied to the event source mapping.
type: list
elements: str
choices: [ReportBatchItemFailures]
version_added: 5.2.0
required: true
type: dict
extends_documentation_fragment:
Expand All @@ -97,10 +104,25 @@
function_name: "{{ function_name }}"
alias: Dev
source_params:
source_arn: arn:aws:dynamodb:us-east-1:123456789012:table/tableName/stream/2016-03-19T19:51:37.457
enabled: True
batch_size: 100
starting_position: TRIM_HORIZON
source_arn: arn:aws:dynamodb:us-east-1:123456789012:table/tableName/stream/2016-03-19T19:51:37.457
enabled: True
batch_size: 100
starting_position: TRIM_HORIZON
register: event
# Example that creates a lambda event notification for a DynamoDB stream
- name: DynamoDB stream event mapping
amazon.aws.lambda_event:
state: present
event_source: stream
function_name: "{{ function_name }}"
source_params:
source_arn: arn:aws:dynamodb:us-east-1:123456789012:table/tableName/stream/2016-03-19T19:51:37.457
enabled: True
batch_size: 100
starting_position: LATEST
function_response_types:
- ReportBatchItemFailures
register: event
- name: Show source event
Expand Down Expand Up @@ -344,6 +366,8 @@ def lambda_event_stream(module, aws):
api_params.update(Enabled=source_param_enabled)
if source_params.get('batch_size'):
api_params.update(BatchSize=source_params.get('batch_size'))
if source_params.get('function_response_types'):
api_params.update(FunctionResponseTypes=source_params.get('function_response_types'))

try:
if not module.check_mode:
Expand Down
1 change: 1 addition & 0 deletions tests/integration/targets/lambda_event/aliases
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cloud/aws
10 changes: 10 additions & 0 deletions tests/integration/targets/lambda_event/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# defaults file for lambda integration test
# IAM role names have to be less than 64 characters
# we hash the resource_prefix to get a shorter, unique string
lambda_function_name: 'test-lambda-{{ tiny_prefix }}'
lambda_role_name: ansible-test-{{ tiny_prefix }}-lambda

dynamodb_table_name: ansible-test-{{ tiny_prefix }}

lambda_python_runtime: python3.9
lambda_python_handler: mini_lambda.handler
48 changes: 48 additions & 0 deletions tests/integration/targets/lambda_event/files/mini_lambda.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

import json
import os


def handler(event, context):
"""
The handler function is the function which gets called each time
the lambda is run.
"""
# printing goes to the cloudwatch log allowing us to simply debug the lambda if we can find
# the log entry.
print("got event:\n" + json.dumps(event))

# if the name parameter isn't present this can throw an exception
# which will result in an amazon chosen failure from the lambda
# which can be completely fine.

name = event["name"]

# we can use environment variables as part of the configuration of the lambda
# which can change the behaviour of the lambda without needing a new upload

extra = os.environ.get("EXTRA_MESSAGE")
if extra is not None and len(extra) > 0:
greeting = "hello {0}. {1}".format(name, extra)
else:
greeting = "hello " + name

return {"message": greeting}


def main():
"""
This main function will normally never be called during normal
lambda use. It is here for testing the lambda program only.
"""
event = {"name": "james"}
context = None
print(handler(event, context))


if __name__ == '__main__':
main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
5 changes: 5 additions & 0 deletions tests/integration/targets/lambda_event/meta/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
dependencies:
- role: setup_remote_tmp_dir
- role: setup_botocore_pip
vars:
botocore_version: 1.21.51
117 changes: 117 additions & 0 deletions tests/integration/targets/lambda_event/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
- name: set connection information for AWS modules and run tests
module_defaults:
group/aws:
aws_access_key: '{{ aws_access_key }}'
aws_secret_key: '{{ aws_secret_key }}'
security_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region }}'
collections:
- community.general
block:

- name: Create test resources setup
import_tasks: setup.yml

# TEST CREATE LAMBDA EVENT ========================================================================================
- name: Create DynamoDB stream event mapping (trigger) - check_mode
amazon.aws.lambda_event:
state: present
event_source: stream
function_arn: '{{ lambda_function_arn }}'
source_params:
source_arn: '{{ dynamo_stream_arn }}'
enabled: True
batch_size: 500
starting_position: LATEST
function_response_types:
- ReportBatchItemFailures
check_mode: true
register: create_lambda_event_result

- assert:
that:
- create_lambda_event_result is changed
- create_lambda_event_result is not failed
- '"lambda:CreateEventSourceMapping" not in create_lambda_event_result.resource_actions'

- name: Create DynamoDB stream event mapping (trigger)
amazon.aws.lambda_event:
state: present
event_source: stream
function_arn: '{{ lambda_function_arn }}'
source_params:
source_arn: '{{ dynamo_stream_arn }}'
enabled: True
batch_size: 500
starting_position: LATEST
function_response_types:
- ReportBatchItemFailures
register: create_lambda_event_result

- name: Get info on above trigger
command: 'aws lambda get-event-source-mapping --uuid {{ create_lambda_event_result.events.uuid }}'
environment:
AWS_ACCESS_KEY_ID: "{{ aws_access_key }}"
AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}"
AWS_SESSION_TOKEN: "{{ security_token | default('') }}"
AWS_DEFAULT_REGION: "{{ aws_region }}"
register: lambda_function_details

- name: convert it to an object
set_fact:
lambda_function_details_obj: "{{ lambda_function_details.stdout | from_json }}"

- assert:
that:
- lambda_function_details_obj.FunctionResponseTypes is defined
- lambda_function_details_obj.FunctionResponseTypes | length > 0
- lambda_function_details_obj.FunctionResponseTypes[0] == "ReportBatchItemFailures"
- '"lambda:CreateEventSourceMapping" in create_lambda_event_result.resource_actions'

- name: Create DynamoDB stream event mapping (trigger) - check_mode - idempotency
amazon.aws.lambda_event:
state: present
event_source: stream
function_arn: '{{ lambda_function_arn }}'
source_params:
source_arn: '{{ dynamo_stream_arn }}'
enabled: True
batch_size: 500
starting_position: LATEST
function_response_types:
- ReportBatchItemFailures
check_mode: true
register: create_lambda_event_result

- assert:
that:
- create_lambda_event_result is not changed
- create_lambda_event_result is not failed
- '"lambda:CreateEventSourceMapping" not in create_lambda_event_result.resource_actions'

- name: Create DynamoDB stream event mapping (trigger) - idempotency
amazon.aws.lambda_event:
state: present
event_source: stream
function_arn: '{{ lambda_function_arn }}'
source_params:
source_arn: '{{ dynamo_stream_arn }}'
enabled: True
batch_size: 500
starting_position: LATEST
function_response_types:
- ReportBatchItemFailures
register: create_lambda_event_result

- assert:
that:
- create_lambda_event_result is not changed
- create_lambda_event_result is not failed
- '"lambda:CreateEventSourceMapping" not in create_lambda_event_result.resource_actions'


# ========================================================================================

always:
- name: Clean up test resources setup
import_tasks: teardown.yml
83 changes: 83 additions & 0 deletions tests/integration/targets/lambda_event/tasks/setup.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
---
- debug: msg="Starting test setup......"

# CREATE DYNAMO DB TABLE
- name: Create minimal dynamo table
community.aws.dynamodb_table:
name: "{{ dynamodb_table_name }}"
hash_key_name: id
hash_key_type: STRING
tags:
Usage: Created By Integration Test
register: create_table_result

# ENABLE DYNAMODB STREAM AND GET STREAM ARN
- name: Enable DynamoDB stream (currently not supported by community.aws.dynamodb_table)
command: aws dynamodb update-table --table-name "{{ dynamodb_table_name }}" --stream-specification StreamEnabled=True,StreamViewType=KEYS_ONLY
environment:
AWS_ACCESS_KEY_ID: "{{ aws_access_key }}"
AWS_SECRET_ACCESS_KEY: "{{ aws_secret_key }}"
AWS_SESSION_TOKEN: "{{ security_token | default('') }}"
AWS_DEFAULT_REGION: "{{ aws_region }}"
register: enable_stream_result
- name: convert it to an object
set_fact:
enable_stream_result: "{{ enable_stream_result.stdout | from_json }}"
- name: Get DynamoDB stream ARN
set_fact:
dynamo_stream_arn: "{{ enable_stream_result.TableDescription.LatestStreamArn }}"

# CREATE MINIMAL LAMBDA FUNCTION
# https://github.com/ansible/ansible/issues/77257
- name: Set async_dir for HOME env
ansible.builtin.set_fact:
ansible_async_dir: "{{ lookup('env', 'HOME') }}/.ansible_async_{{ tiny_prefix }}/"
when: (lookup('env', 'HOME'))

- name: create minimal lambda role
iam_role:
name: '{{ lambda_role_name }}'
assume_role_policy_document: '{{ lookup("file", "minimal_trust_policy.json")}}'
create_instance_profile: false
managed_policies:
- arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess
- arn:aws:iam::aws:policy/AWSLambdaInvocation-DynamoDB
- arn:aws:iam::aws:policy/service-role/AWSLambdaDynamoDBExecutionRole
register: iam_role
- name: wait 10 seconds for role to become available
pause:
seconds: 10
when: iam_role.changed

- name: move lambda into place for archive module
copy:
src: mini_lambda.py
dest: '{{ output_dir }}/mini_lambda.py'
mode: preserve
- name: bundle lambda into a zip
register: zip_res
archive:
format: zip
path: '{{ output_dir }}/mini_lambda.py'
dest: '{{ output_dir }}/mini_lambda.zip'

- name: test state=present - upload the lambda
lambda:
name: '{{ lambda_function_name }}'
runtime: '{{ lambda_python_runtime }}'
handler: '{{ lambda_python_handler }}'
role: '{{ lambda_role_name }}'
zip_file: '{{ zip_res.dest }}'
architecture: x86_64
register: result
vars:
ansible_python_interpreter: '{{ botocore_virtualenv_interpreter }}'

- name: assert lambda upload succeeded
assert:
that:
- result.changed

- name: Get lambda function ARN
ansible.builtin.set_fact:
lambda_function_arn: "{{ result.configuration.function_arn }}"
33 changes: 33 additions & 0 deletions tests/integration/targets/lambda_event/tasks/teardown.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
- debug: msg="Starting test Teardown......"

- name: Delete DynamoDB stream event mapping (trigger)
amazon.aws.lambda_event:
state: absent
event_source: stream
function_arn: '{{ lambda_function_arn }}'
source_params:
source_arn: "{{ dynamo_stream_arn }}"
enabled: True
batch_size: 500
starting_position: LATEST
function_response_types:
- ReportBatchItemFailures
register: create_lambda_event_result
ignore_errors: true

- name: Delete lambda function
lambda:
name: '{{ lambda_function_name }}'
state: absent

- name: Delete dynamo table
community.aws.dynamodb_table:
name: "{{ dynamodb_table_name }}"
state: absent

- name: Delete the role
community.aws.iam_role:
name: '{{ lambda_role_name }}'
assume_role_policy_document: '{{ lookup("file", "minimal_trust_policy.json")}}'
state: absent

0 comments on commit 9528072

Please sign in to comment.