---
- name: Create
  hosts: localhost
  connection: local
  gather_facts: false
  no_log: "{{ molecule_no_log }}"
  vars:
    molecule_labels:
      owner: molecule
  tags:
    - always
  tasks:
    - name: Set async_dir for HOME env
      ansible.builtin.set_fact:
        ansible_async_dir: "{{ lookup('env', 'HOME') }}/.ansible_async/"
      when: lookup('env', 'HOME') is truthy

    - name: Log into a Docker registry
      community.docker.docker_login:
        username: "{{ item.registry.credentials.username }}"
        password: "{{ item.registry.credentials.password }}"
        email: "{{ item.registry.credentials.email | default(omit) }}"
        registry: "{{ item.registry.url }}"
        docker_host: "{{ item.docker_host | default(lookup('env', 'DOCKER_HOST') or 'unix://var/run/docker.sock') }}"
        cacert_path: "{{ item.cacert_path | default((lookup('env', 'DOCKER_CERT_PATH') + '/ca.pem') if lookup('env', 'DOCKER_CERT_PATH') else omit) }}"
        cert_path: "{{ item.cert_path | default((lookup('env', 'DOCKER_CERT_PATH') + '/cert.pem') if lookup('env', 'DOCKER_CERT_PATH') else omit) }}"
        key_path: "{{ item.key_path | default((lookup('env', 'DOCKER_CERT_PATH') + '/key.pem') if lookup('env', 'DOCKER_CERT_PATH') else omit) }}"
        tls_verify: "{{ item.tls_verify | default(lookup('env', 'DOCKER_TLS_VERIFY')) or false }}"
      with_items: "{{ molecule_yml.platforms }}"
      loop_control:
        label: "{{ item.registry.url | default(item.name) }}"
      when:
        - item.registry is defined
        - item.registry.url is truthy
        - item.registry.credentials is defined
        - item.registry.credentials.username is defined
      no_log: true

    - name: Check presence of custom Dockerfiles
      ansible.builtin.stat:
        path: "{{ molecule_scenario_directory + '/' + (item.dockerfile | default('Dockerfile.j2')) }}"
      loop: "{{ molecule_yml.platforms }}"
      loop_control:
        label: "{{ item.name }}"
      register: dockerfile_stats

    - name: Create Dockerfiles from image names
      ansible.builtin.template:
        # when using embedded playbooks the dockerfile is alongside them
        src: "{%- if dockerfile_stats.results[i].stat.exists -%}\
          {{ molecule_scenario_directory + '/' + (item.dockerfile | default('Dockerfile.j2')) }}\
          {%- else -%}\
          {{ playbook_dir + '/Dockerfile.j2' }}\
          {%- endif -%}"
        dest: "{{ molecule_ephemeral_directory }}/Dockerfile_{{ item.image | regex_replace('[^a-zA-Z0-9_]', '_') }}"
        mode: "0600"
      loop: "{{ molecule_yml.platforms }}"
      loop_control:
        label: "{{ item.name }}"
        index_var: i
      when: not item.pre_build_image | default(false)
      register: platforms

    - name: Synchronization the context
      ansible.posix.synchronize:
        src: "{%- if dockerfile_stats.results[i].stat.exists -%}\
          {{ molecule_scenario_directory + '/' }}\
          {%- else -%}\
          {{ playbook_dir + '/' }}\
          {%- endif -%}"
        dest: "{{ molecule_ephemeral_directory }}"
        rsync_opts:
          - "--exclude=molecule.yml"
      loop: "{{ molecule_yml.platforms }}"
      loop_control:
        label: "{{ item.name }}"
        index_var: i
      when: not item.pre_build_image | default(false)
      delegate_to: localhost

    - name: Discover local Docker images
      community.docker.docker_image_info:
        name: "molecule_local/{{ item.item.name }}"
        docker_host: "{{ item.item.docker_host | default(lookup('env', 'DOCKER_HOST') or 'unix://var/run/docker.sock') }}"
        cacert_path: "{{ item.cacert_path | default((lookup('env', 'DOCKER_CERT_PATH') + '/ca.pem') if lookup('env', 'DOCKER_CERT_PATH') else omit) }}"
        cert_path: "{{ item.cert_path | default((lookup('env', 'DOCKER_CERT_PATH') + '/cert.pem') if lookup('env', 'DOCKER_CERT_PATH') else omit) }}"
        key_path: "{{ item.key_path | default((lookup('env', 'DOCKER_CERT_PATH') + '/key.pem') if lookup('env', 'DOCKER_CERT_PATH') else omit) }}"
        tls_verify: "{{ item.tls_verify | default(lookup('env', 'DOCKER_TLS_VERIFY')) or false }}"
      with_items: "{{ platforms.results }}"
      loop_control:
        label: "{{ item.item.docker_host | default(lookup('env', 'DOCKER_HOST') or 'unix://var/run/docker.sock') }}"
      when:
        - not item.pre_build_image | default(false)
      register: docker_images

    - name: Create docker network(s)
      ansible.builtin.include_tasks: tasks/create_network.yml
      with_items: "{{ molecule_yml.platforms | molecule_get_docker_networks(molecule_labels) }}"
      loop_control:
        label: "{{ item.name }}"
      no_log: false

    - name: Build an Ansible compatible image (new) # noqa: no-handler
      when:
        - platforms.changed or docker_images.results | map(attribute='images') | select('equalto', []) | list | count >= 0
        - not item.item.pre_build_image | default(false)
      community.docker.docker_image:
        build:
          path: "{{ molecule_ephemeral_directory }}"
          dockerfile: "{{ item.invocation.module_args.dest }}"
          pull: "{{ item.item.pull | default(true) }}"
          network: "{{ item.item.network_mode | default(omit) }}"
          args: "{{ item.item.buildargs | default(omit) }}"
          platform: "{{ item.item.platform | default(omit) }}"
          cache_from: "{{ item.item.cache_from | default(omit) }}"
        name: "molecule_local/{{ item.item.image }}"
        docker_host: "{{ item.item.docker_host | default(lookup('env', 'DOCKER_HOST') or 'unix://var/run/docker.sock') }}"
        cacert_path: "{{ item.cacert_path | default((lookup('env', 'DOCKER_CERT_PATH') + '/ca.pem') if lookup('env', 'DOCKER_CERT_PATH') else omit) }}"
        cert_path: "{{ item.cert_path | default((lookup('env', 'DOCKER_CERT_PATH') + '/cert.pem') if lookup('env', 'DOCKER_CERT_PATH') else omit) }}"
        key_path: "{{ item.key_path | default((lookup('env', 'DOCKER_CERT_PATH') + '/key.pem') if lookup('env', 'DOCKER_CERT_PATH') else omit) }}"
        tls_verify: "{{ item.tls_verify | default(lookup('env', 'DOCKER_TLS_VERIFY')) or false }}"
        force_source: "{{ item.item.force | default(true) }}"
        source: build
      with_items: "{{ platforms.results }}"
      loop_control:
        label: "molecule_local/{{ item.item.image }}"
      no_log: false
      register: result
      until: result is not failed
      retries: 3
      delay: 30

    - name: Determine the CMD directives
      ansible.builtin.set_fact:
        command_directives_dict: >-
          {{ command_directives_dict | default({}) |
             combine({item.name: item.command | default('bash -c "while true; do sleep 10000; done"')})
          }}
      with_items: "{{ molecule_yml.platforms }}"
      loop_control:
        label: "{{ item.name }}"
      when: item.override_command | default(true)

    - name: Create molecule instance(s)
      community.docker.docker_container:
        name: "{{ item.name }}"
        docker_host: "{{ item.docker_host | default(lookup('env', 'DOCKER_HOST') or 'unix://var/run/docker.sock') }}"
        cacert_path: "{{ item.cacert_path | default((lookup('env', 'DOCKER_CERT_PATH') + '/ca.pem') if lookup('env', 'DOCKER_CERT_PATH') else omit) }}"
        cert_path: "{{ item.cert_path | default((lookup('env', 'DOCKER_CERT_PATH') + '/cert.pem') if lookup('env', 'DOCKER_CERT_PATH') else omit) }}"
        key_path: "{{ item.key_path | default((lookup('env', 'DOCKER_CERT_PATH') + '/key.pem') if lookup('env', 'DOCKER_CERT_PATH') else omit) }}"
        tls_verify: "{{ item.tls_verify | default(lookup('env', 'DOCKER_TLS_VERIFY')) or false }}"
        hostname: "{{ item.hostname | default(item.name) }}"
        image: "{{ item.pre_build_image | default(false) | ternary('', 'molecule_local/') }}{{ item.image }}"
        pull: "{{ item.pull | default(omit) }}"
        memory: "{{ item.memory | default(omit) }}"
        memory_swap: "{{ item.memory_swap | default(omit) }}"
        state: started
        recreate: false
        log_driver: json-file
        command: "{{ (command_directives_dict | default({}))[item.name] | default(omit) }}"
        command_handling: "{{ item.command_handling | default('compatibility') }}"
        user: "{{ item.user | default(omit) }}"
        pid_mode: "{{ item.pid_mode | default(omit) }}"
        runtime: "{{ item.runtime | default(omit) }}"
        privileged: "{{ item.privileged | default(omit) }}"
        security_opts: "{{ item.security_opts | default(omit) }}"
        devices: "{{ item.devices | default(omit) }}"
        links: "{{ item.links | default(omit) }}"
        volumes: "{{ item.volumes | default(omit) }}"
        mounts: "{{ item.mounts | default(omit) }}"
        tmpfs: "{{ item.tmpfs | default(omit) }}"
        capabilities: "{{ item.capabilities | default(omit) }}"
        sysctls: "{{ item.sysctls | default(omit) }}"
        exposed_ports: "{{ item.exposed_ports | default(omit) }}"
        published_ports: "{{ item.published_ports | default(omit) }}"
        ulimits: "{{ item.ulimits | default(omit) }}"
        networks: "{{ item.networks | default(omit) }}"
        network_mode: "{{ item.network_mode | default(omit) }}"
        networks_cli_compatible: "{{ item.networks_cli_compatible | default(true) }}"
        purge_networks: "{{ item.purge_networks | default(omit) }}"
        dns_servers: "{{ item.dns_servers | default(omit) }}"
        etc_hosts: "{{ item.etc_hosts | default(omit) }}"
        env: "{{ item.env | default(omit) }}"
        restart_policy: "{{ item.restart_policy | default(omit) }}"
        restart_retries: "{{ item.restart_retries | default(omit) }}"
        tty: "{{ item.tty | default(omit) }}"
        labels: "{{ molecule_labels | combine(item.labels | default({})) }}"
        container_default_behavior: >-
          {{ item.container_default_behavior
             | default('compatibility' if ansible_version.full is version_compare('2.10', '>=') else omit) }}
        stop_signal: "{{ item.stop_signal | default(omit) }}"
        kill_signal: "{{ item.kill_signal | default(omit) }}"
        cgroupns_mode: "{{ item.cgroupns_mode | default(omit) }}"
        shm_size: "{{ item.shm_size | default(omit) }}"
        platform: "{{ item.platform | default(omit) }}"
        comparisons:
          platform: ignore
      register: server
      with_items: "{{ molecule_yml.platforms }}"
      loop_control:
        label: "{{ item.name }}"
      no_log: false
      async: 7200
      poll: 0

    - name: Wait for instance(s) creation to complete
      ansible.builtin.async_status:
        jid: "{{ item.ansible_job_id }}"
      register: docker_jobs
      until: docker_jobs is finished
      retries: 300
      with_items: "{{ server.results }}"
      loop_control:
        label: "{{ item.item.name }}"
