---
#
#  Author: Michael De La Rue
#  based on ec2_key.yml + lambda.py

- block:

    - name: set up AWS credentials
      set_fact:
        aws_connection_info: &aws_connection_info
          aws_region: '{{ aws_region }}'
          aws_access_key: '{{ aws_access_key }}'
          aws_secret_key: '{{ aws_secret_key }}'
          security_token: '{{ security_token }}'
      no_log: yes

    # ============================================================
    - name: test with no parameters
      lambda_policy:
      register: result
      ignore_errors: true

    - name: assert failure when called with no parameters
      assert:
        that:
           - 'result.failed'
           - 'result.msg.startswith("missing required arguments: ")'

    # ============================================================
    - name: test with all required dummy parameters but no region
      lambda_policy:
        statement_id: dummy
        principal: api_fakeway
        action: fake:do_something_fake
        function_name: dummy_fake_function
      ignore_errors: true
      register: result

    - name: assert failure and appropriate message when called without region
      assert:
        that:
           - 'result.failed'
           - '"region must be specified" in result.msg'

    # ============================================================
    - name: test with all required dummy parameters but no region
      lambda_policy:
        statement_id: dummy
        principal: api_fakeway
        action: fake:do_something_fake
        function_name: dummy_fake_function
        region: null
      ignore_errors: true
      register: result

    - name: assert failure and appropriate message when called false region region
      assert:
        that:
           - 'result.failed'
           - '"region must be specified" in result.msg'

    # ============================================================
    - name: test exceptions generated by forcing bad ec2 url
      lambda_policy:
        function_name: "{{ lambda_function_name }}"
        state: present
        statement_id: api-gateway-invoke-lambdas
        action: lambda:InvokeFunction
        principal: apigateway.amazonaws.com
        source_arn: "arn:aws:execute-api:no-north-0:1234567:*/*"
        ec2_url: https://noexist.example.com
        ec2_region: 'no-north-0'
        ec2_access_key: 'iamnotreallyanaccesskey'
        ec2_secret_key: 'thisisabadsecretkey'
        security_token: 'andthisisabadsecuritytoken'
      register: result
      ignore_errors: true

    - name: assert lambda manages to respond as expected
      assert:
        that:
           - 'result is failed'
           - 'result.msg != "MODULE FAILURE"'
           - 'result.changed == False'

    # ============================================================
    # direct zip file upload
    - name: move lambda into place for archive module
      copy:
        src: "mini_http_lambda.py"
        dest: "{{output_dir}}/mini_http_lambda.py"

    - name: bundle lambda into a zip
      archive:
        format: zip
        path: "{{output_dir}}/mini_http_lambda.py"
        dest: "{{output_dir}}/mini_http_lambda.zip"
      register: zip_res

    # This should exist, but there's no expectation that the test user should be able to
    # create/update this role, merely validate that it's there.
    # Use ansible -m iam_role -a 'name=ansible_lambda_role
    # assume_role_policy_document={{ lookup("file", "test/integration/targets/lambda_policy/files/minimal_trust_policy.json", convert_data=False) }}
    # ' -vvv localhost
    # to create this through more privileged credentials before running this test suite.
    - name: create minimal lambda role
      iam_role:
        name: ansible_lambda_role
        assume_role_policy_document: "{{ lookup('file', 'minimal_trust_policy.json', convert_data=False) }}"
        create_instance_profile: no
        <<: *aws_connection_info
      register: iam_role

    - name: wait 10 seconds for role to become available
      pause:
        seconds: 10
      when: iam_role.changed

    - name: test state=present - upload the lambda
      lambda:
        name: "{{lambda_function_name}}"
        runtime: "python3.9"
        handler: "mini_http_lambda.handler"
        role: "ansible_lambda_role"
        zip_file: "{{zip_res.dest}}"
        <<: *aws_connection_info
      register: lambda_result

    - name: get the aws account ID for use in future commands
      aws_caller_info:
        <<: *aws_connection_info
      register: aws_caller_info

    - name: register lambda uri for use in template
      set_fact:
        mini_lambda_uri: "arn:aws:apigateway:{{ aws_region }}:lambda:path/2015-03-31/functions/arn:aws:lambda:{{ aws_region }}:{{ aws_caller_info.account }}:function:{{ lambda_result.configuration.function_name }}/invocations"

    - name: build API file
      template:
        src: endpoint-test-swagger-api.yml.j2
        dest: "{{output_dir}}/endpoint-test-swagger-api.yml.j2"

    - name: deploy new API
      aws_api_gateway:
        api_file: "{{output_dir}}/endpoint-test-swagger-api.yml.j2"
        stage: "lambdabased"
        <<: *aws_connection_info
      register: create_result

    - name: register api id for later
      set_fact:
        api_id: "{{ create_result.api_id }}"

    - name: check API fails with permissions failure
      uri:
        url: "https://{{create_result.api_id}}.execute-api.{{aws_region}}.amazonaws.com/lambdabased/mini/Mr_Ansible_Tester"
      register: unauth_uri_result
      ignore_errors: true

    - name: assert internal server error due to permissions
      assert:
        that:
          - unauth_uri_result is failed
          - 'unauth_uri_result.status == 500'

    - name: give api gateway execute permissions on lambda
      lambda_policy:
        function_name: "{{ lambda_function_name }}"
        state: present
        statement_id: api-gateway-invoke-lambdas
        action: lambda:InvokeFunction
        principal: apigateway.amazonaws.com
        source_arn: "arn:aws:execute-api:{{ aws_region }}:{{ aws_caller_info.account }}:*/*"
        <<: *aws_connection_info

    - name: try again but with ARN
      lambda_policy:
        function_name: "{{ lambda_result.configuration.function_arn }}"
        state: present
        statement_id: api-gateway-invoke-lambdas
        action: lambda:InvokeFunction
        principal: apigateway.amazonaws.com
        source_arn: "arn:aws:execute-api:{{ aws_region }}:{{ aws_caller_info.account }}:*/*"
        <<: *aws_connection_info

    - name: check API works with execute permissions
      uri:
        url: "https://{{create_result.api_id}}.execute-api.{{aws_region}}.amazonaws.com/lambdabased/mini/Mr_Ansible_Tester"
      register: uri_result

    - name: assert API works success
      assert:
        that:
           - 'uri_result'


    - name: deploy new API
      aws_api_gateway:
        api_file: "{{output_dir}}/endpoint-test-swagger-api.yml.j2"
        stage: "lambdabased"
        <<: *aws_connection_info
      register: create_result
      ignore_errors: true


  always:

    # ============================================================
    - name: destroy lambda for test cleanup if created
      lambda:
        name: "{{lambda_function_name}}"
        <<: *aws_connection_info
        state: absent
      register: result
      ignore_errors: yes

    - name: destroy API for test cleanup if created
      aws_api_gateway:
        state: absent
        api_id: '{{api_id}}'
        <<: *aws_connection_info
      register: destroy_result
      ignore_errors: yes
