---
- block:
  - name: set connection information for all tasks
    set_fact:
      aws_connection_info: &aws_connection_info
        aws_access_key: "{{ aws_access_key }}"
        aws_secret_key: "{{ aws_secret_key }}"
        region: "{{ aws_region }}"
        security_token: "{{ security_token }}"
    no_log: true

  - name: retrieve caller facts
    aws_caller_info:
      <<: *aws_connection_info
    register: test_caller_facts

  - name: ensure IAM role exists
    iam_role:
      <<: *aws_connection_info
      name: "test-secrets-manager-role"
      assume_role_policy_document: "{{ lookup('file','secretsmanager-trust-policy.json') }}"
      state: present
      create_instance_profile: no
      managed_policy:
        - 'arn:aws:iam::aws:policy/SecretsManagerReadWrite'
    register: iam_role_output
    ignore_errors: yes

  # CI does not remove the role and comparing policies has a bug on Python3; fall back to use iam_role_info
  - name: get IAM role
    iam_role_info:
      <<: *aws_connection_info
      name: "test-secrets-manager-role"
    when: iam_role_output is failed
    register: iam_role_info

  - name: set iam_role_output
    set_fact:
      iam_role_output: "{{ iam_role_info.iam_roles[0] }}"
    when: iam_role_info is defined

  - name: create a temporary directory
    tempfile:
      state: directory
    register: tmp

  - name: move lambda into place for upload
    copy:
      src: "files/hello_world.zip"
      dest: "{{ tmp.path }}/hello_world.zip"

  - name: dummy lambda for testing
    lambda:
      <<: *aws_connection_info
      name: "hello-world-{{ resource_prefix }}"
      state: present
      zip_file: "{{ tmp.path }}/hello_world.zip"
      runtime: 'python2.7'
      role: "{{ iam_role_output.arn }}"
      handler: 'hello_world.lambda_handler'
    register: lambda_output
    until: not lambda_output.failed
    retries: 10
    delay: 5

  - debug:
      var: lambda_output

  # ============================================================
  # Module parameter testing
  # ============================================================
  - name: test with no parameters
    aws_secret:
    register: result
    ignore_errors: true
    check_mode: true

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

  # ============================================================
  # Creation/Deletion testing
  # ============================================================
  - name: add secret to AWS Secrets Manager
    aws_secret:
      <<: *aws_connection_info
      name: "test-secret-string-{{ resource_prefix }}"
      state: present
      secret_type: 'string'
      secret: "{{ super_secret_string }}"
    register: result

  - name: assert correct keys are returned
    assert:
      that:
        - result.changed
        - result.arn is not none
        - result.name is not none
        - result.tags is not none
        - result.version_ids_to_stages is not none

  - name: no changes to secret
    aws_secret:
      <<: *aws_connection_info
      name: "test-secret-string-{{ resource_prefix }}"
      state: present
      secret_type: 'string'
      secret: "{{ super_secret_string }}"
    register: result

  - name: assert correct keys are returned
    assert:
      that:
        - not result.changed
        - result.arn is not none

  - name: make change to secret
    aws_secret:
      <<: *aws_connection_info
      name: "test-secret-string-{{ resource_prefix }}"
      description: 'this is a change to this secret'
      state: present
      secret_type: 'string'
      secret: "{{ super_secret_string }}"
    register: result

  - debug:
      var: result

  - name: assert correct keys are returned
    assert:
      that:
        - result.changed
        - result.arn is not none
        - result.name is not none
        - result.tags is not none
        - result.version_ids_to_stages is not none

  - name: add tags to secret
    aws_secret:
      <<: *aws_connection_info
      name: "test-secret-string-{{ resource_prefix }}"
      description: 'this is a change to this secret'
      state: present
      secret_type: 'string'
      secret: "{{ super_secret_string }}"
      tags:
        Foo: 'Bar'
        Test: 'Tag'
    register: result

  - name: assert correct keys are returned
    assert:
      that:
        - result.changed

  - name: remove tags from secret
    aws_secret:
      <<: *aws_connection_info
      name: "test-secret-string-{{ resource_prefix }}"
      description: 'this is a change to this secret'
      state: present
      secret_type: 'string'
      secret: "{{ super_secret_string }}"
    register: result

  - name: assert correct keys are returned
    assert:
      that:
        - result.changed

  - name: lambda policy for secrets manager
    lambda_policy:
      <<: *aws_connection_info
      state: present
      function_name: "hello-world-{{ resource_prefix }}"
      statement_id: LambdaSecretsManagerTestPolicy
      action: 'lambda:InvokeFunction'
      principal: "secretsmanager.amazonaws.com"

  - name: add rotation lambda to secret
    aws_secret:
      <<: *aws_connection_info
      name: "test-secret-string-{{ resource_prefix }}"
      description: 'this is a change to this secret'
      state: present
      secret_type: 'string'
      secret: "{{ super_secret_string }}"
      rotation_lambda: "arn:aws:lambda:{{ aws_region }}:{{ test_caller_facts.account }}:function:hello-world-{{ resource_prefix }}"
    register: result
    retries: 100
    delay: 5
    until: not result.failed

  - name: assert correct keys are returned
    assert:
      that:
        - result.changed

  - name: remove rotation lambda from secret
    aws_secret:
      <<: *aws_connection_info
      name: "test-secret-string-{{ resource_prefix }}"
      description: 'this is a change to this secret'
      state: present
      secret_type: 'string'
      secret: "{{ super_secret_string }}"
    register: result

  - name: assert correct keys are returned
    assert:
      that:
        - result.changed

  always:
  - name: remove secret
    aws_secret:
      <<: *aws_connection_info
      name: "test-secret-string-{{ resource_prefix }}"
      state: absent
      secret_type: 'string'
      secret: "{{ super_secret_string }}"
      recovery_window: 0
    ignore_errors: yes

  - name: remove lambda policy
    lambda_policy:
      <<: *aws_connection_info
      state: absent
      function_name: "hello-world-{{ resource_prefix }}"
      statement_id: lambda-secretsmanager-test-policy
      action: lambda:InvokeFunction
      principal: secretsmanager.amazonaws.com
    ignore_errors: yes

  - name: remove dummy lambda
    lambda:
      <<: *aws_connection_info
      name: "hello-world-{{ resource_prefix }}"
      state: absent
      zip_file: "{{ tmp.path }}/hello_world.zip"
      runtime: 'python2.7'
      role: "test-secrets-manager-role"
      handler: 'hello_world.lambda_handler'
    ignore_errors: yes

  # CI does not remove the IAM role
  - name: remove IAM role
    iam_role:
      <<: *aws_connection_info
      name: "test-secrets-manager-role"
      assume_role_policy_document: "{{ lookup('file','secretsmanager-trust-policy.json') }}"
      state: absent
      create_instance_profile: no
      managed_policy:
        - 'arn:aws:iam::aws:policy/SecretsManagerReadWrite'
    ignore_errors: yes

  - name: remove temporary dir
    file:
      path: "{{ tmp.path }}"
      state: absent
