---
- name: Create
  hosts: localhost
  connection: local
  gather_facts: false
  no_log: "{{ molecule_no_log }}"
  become: "{{ not (item.rootless | default(true)) }}"
  vars:
    podman_exec: "{{ lookup('env','MOLECULE_PODMAN_EXECUTABLE') | default('podman', true) }}"
  tasks:
    - name: Get passwd entries for USER env
      ansible.builtin.getent:
        database: passwd
        key: "{{ lookup('env', 'USER') }}"

    - name: Get shell async_dir
      ansible.builtin.set_fact:
        _shell_async_dir: >-
          {{ lookup('ansible.builtin.config', 'async_dir', plugin_type='shell', plugin_name='sh')
             | regex_replace('^~', ansible_facts.getent_passwd[lookup('env', 'USER')][4]) }}

    - name: Set async_dir for HOME env
      ansible.builtin.set_fact:
        ansible_async_dir: >-
          {{ _shell_async_dir
             | regex_replace('^' + ansible_facts.getent_passwd[lookup('env', 'USER')][4], lookup('env', 'HOME')) }}
      when: lookup('env', 'HOME') != ansible_facts.getent_passwd[lookup('env', 'USER')][4]

    - name: Log into a container registry
      containers.podman.podman_login:
        certdir: >-
          {% if lookup('env', 'DOCKER_CERT_PATH') %}
          {{ item.cert_path | default(lookup('env', 'DOCKER_CERT_PATH') + '/cert.pem') }}
          {% endif %}
        executable: "{{ podman_exec }}"
        username: "{{ item.registry.credentials.username }}"
        password: "{{ item.registry.credentials.password }}"
        registry: "{{ item.registry.url }}"
        tlsverify: "{{ item.registry.tls_verify | default(lookup('env', 'DOCKER_TLS_VERIFY')) or false }}"
      loop: "{{ molecule_yml.platforms }}"
      loop_control:
        label: >-
          "{{ item.name }} registry username:
          {{ item.registry.credentials.username | default('None specified') }}"
      when:
        - item.registry is defined
        - item.registry.url is truthy
        - item.registry.credentials is defined
        - item.registry.credentials.username is defined
      changed_when: false

    - 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: "Dockerfile: {{ item.dockerfile | default('None specified') }}"
      register: dockerfile_stats

    - name: Create Dockerfiles from image names
      ansible.builtin.template:
        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:
        index_var: i
        label: >-
          "Dockerfile: {{ item.dockerfile | default('None specified') }};
          Image: {{ item.image | default('None specified') }}"
      when: not item.pre_build_image | default(false)
      register: platforms

    - name: Discover local Podman images
      containers.podman.podman_image_info:
        name: "molecule_local/{{ item.item.name }}"
        executable: "{{ podman_exec }}"
      with_items: "{{ platforms.results }}"
      loop_control:
        label: "{{ item.item.name | default('None specified') }}"
      when:
        - not item.pre_build_image | default(false)
      register: podman_images

    - name: Build an Ansible compatible image # noqa: no-handler
      containers.podman.podman_image:
        build:
          extra_args: >-
            {% if item.item.buildargs is defined %}{% for i, k in item.item.buildargs.items() %}--build-arg={{ i }}={{ k }}{% endfor %}{% endif %}
            {% if item.item.pull is defined %}--pull={{ item.item.pull }}{% endif %}
          file: "{{ item.dest }}"
        name: "molecule_local/{{ item.item.image }}"
        executable: "{{ podman_exec }}"
        path: "{{ molecule_scenario_directory }}"
        pull: "{{ item.item.pull | default(omit) }}"
      loop: "{{ platforms.results }}"
      loop_control:
        label: "{{ item.item.image | default('None specified') }}"
      when:
        - platforms.changed or podman_images.results | map(attribute='images') | select('equalto', []) | list | count >= 0
        - not item.item.pre_build_image | default(false)
      register: result
      until: result is not failed
      retries: 3
      delay: 30
      no_log: false
      changed_when: false

    - 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 }} command:
          {{ item.command | default('None specified') }}"
      when: item.override_command | default(true)

    - name: Discover local podman networks
      containers.podman.podman_network_info:
        name: "{{ item.network }}"
        executable: "{{ podman_exec }}"
      loop: "{{ molecule_yml.platforms | flatten(levels=1) }}"
      loop_control:
        extended: true
        label: "{{ item.name }}: {{ item.network | default('None specified') }}"
      register: podman_network
      when:
        - item.network is defined
        - ansible_loop.first
      failed_when: false

    - name: Create podman network dedicated to this scenario
      containers.podman.podman_network:
        name: "{{ podman_network.results[0].ansible_loop.allitems[0].network }}"
        executable: "{{ podman_exec }}"
        subnet: "{{ podman_network.results[0].ansible_loop.allitems[0].subnet | default(omit) }}"
      when:
        - podman_network.results[0].msg is defined
        # podman message changed at some point in time
        - "'no such network' in podman_network.results[0].msg or 'network not found' in podman_network.results[0].msg"
        - podman_network.results[0].networks is undefined
        - "podman_network.results[0].ansible_loop.allitems[0].network not in ['bridge', 'none', 'host', 'ns', 'private', 'slirp4netns']"

    - name: Create molecule instance(s)
      containers.podman.podman_container:
        name: "{{ item.name }}"
        cap_add: "{{ item.capabilities | default(omit) }}"
        cmd_args: "{{ molecule_podman_args | reject('none') | reject('equalto', '') | list + item.extra_opts | default([]) }}"
        command: "{{ (command_directives_dict | default({}))[item.name] | default('') }}"
        detach: "{{ item.detach | default(omit) }}"
        device: "{{ item.devices | default(omit) }}"
        dns: "{{ item.dns_servers | default(omit) }}"
        env: "{{ item.env | default(omit) }}"
        etc_hosts: "{{ item.etc_hosts | default(omit) }}"
        executable: "{{ podman_exec }}"
        expose: "{{ item.exposed_ports | default(omit) }}"
        hostname: "{{ item.hostname | default(item.name) }}"
        image: "{{ item.pre_build_image | default(false) | ternary('', 'molecule_local/') }}{{ item.image }}"
        ip: "{{ item.ip | default(omit) }}"
        label:
          owner: "molecule" # keep in sync with ../driver.py:Podman.reset()
        network: "{{ item.network | default(omit) }}"
        pid: "{{ item.pid_mode | default(omit) }}"
        privileged: "{{ item.privileged | default(omit) }}"
        publish: "{{ item.published_ports | default(omit) }}"
        security_opt: "{{ item.security_opts | default(omit) }}"
        systemd: "{{ item.systemd | default(omit) }}"
        tmpfs: "{{ item.tmpfs | default(omit) }}"
        tty: "{{ item.tty | default(omit) }}"
        ulimits: "{{ item.ulimits | default(omit) }}"
        volume: "{{ item.volumes | default(omit) }}"
        state: started
      register: server
      changed_when: false
      with_items: "{{ molecule_yml.platforms }}"
      loop_control:
        label: "{{ item.name }}"
      async: 7200
      poll: 0
      vars:
        molecule_podman_args:
          - "{% if item.cgroup_manager is defined %}--cgroup-manager={{ item.cgroup_manager }}{% endif %}"
          - >-
            {% if item.restart_policy is defined %}
            --restart={{ item.restart_policy }}{% if item.restart_retries is defined %}:{{ item.restart_retries }}{% endif %}
            {% endif %}
          - "{% if item.storage_opt is defined %}--storage-opt={{ item.storage_opt }}{% endif %}"
          - "{% if item.storage_driver is defined %}--storage-driver={{ item.storage_driver }}{% endif %}"

    - name: Wait for instance(s) creation to complete
      become: "{{ not item.item.rootless | default(omit) }}"
      ansible.builtin.async_status:
        jid: "{{ item.ansible_job_id }}"
      register: podman_jobs
      until: podman_jobs is finished
      retries: 300
      with_items: "{{ server.results }}"
      loop_control:
        label: "{{ item.item.name | default('Unnamed') }}"
