---
- name: Create
  hosts: localhost
  connection: local
  gather_facts: false
  no_log: "{{ molecule_no_log }}"

  tasks:
    - name: Include molecule tasks
      ansible.builtin.include_tasks:
        file: tasks/vars.yml

    - name: Create security group
      openstack.cloud.security_group:
        name: "molecule-test-{{ item.security_group.name }}-{{ uuid }}"
        description: "{{ item.security_group.description | default('Molecule Test') }}"
      register: security_group
      when:
        - item.security_group is defined
        - item.security_group.name is defined
        - item.security_group.create | default(true)
      loop: "{{ molecule_yml.platforms }}"

    - name: Create security group rules
      openstack.cloud.security_group_rule:
        security_group: "molecule-test-{{ item.0.security_group.name }}-{{ uuid }}"
        protocol: "{{ item.1.proto }}"
        ethertype: "{{ item.1.type | default('IPv4', true) }}"
        port_range_min: "{{ item.1.port_min | default(item.1.port, true) | int }}"
        port_range_max: "{{ item.1.port_max | default(item.1.port, true) | int }}"
      when:
        - item.0.security_group is defined
        - item.0.security_group.create | default(true)
        - "'rules' in item.0.security_group"
      loop: "{{ molecule_yml.platforms | subelements('security_group.rules', skip_missing=True) }}"

    - name: Create network
      openstack.cloud.network:
        name: "molecule-test-{{ item.network.name }}-{{ uuid }}"
        state: present
        external: "{{ item.network.external | default(omit) }}"
      when:
        - item.network is defined
        - item.network.name is defined
        - item.network.create | default(true)
      loop: "{{ molecule_yml.platforms }}"

    - name: Create subnet in network
      openstack.cloud.subnet:
        name: "molecule-test-{{ item.network.subnet.name }}-{{ uuid }}"
        state: present
        network_name: "molecule-test-{{ item.network.name }}-{{ uuid }}"
        cidr: "{{ item.network.subnet.cidr }}"
        ip_version: "{{ iitem.network.subnet.ipv | default(4) | int }}"
        dns_nameservers: "{{ item.network.subnet.dns_nameservers | default(omit) }}"
        host_routes: "{{ item.network.subnet.host_routes | default(omit) }}"
      when:
        - item.network is defined
        - item.network.name is defined
        - item.network.create | default(true)
        - item.network.subnet is defined
        - item.network.subnet.name is defined
      loop: "{{ molecule_yml.platforms }}"

    - name: Create Router
      openstack.cloud.router:
        name: "molecule-test-{{ item.network.router.name }}-{{ uuid }}"
        state: present
        network: "{{ item.network.router.ext_network | default(omit) }}"
        enable_snat: "{{ item.network.router.snat | default(omit) }}"
        interfaces:
          - net: "molecule-test-{{ item.network.name }}-{{ uuid }}"
            subnet: "molecule-test-{{ item.network.subnet.name }}-{{ uuid }}"
      when:
        - item.network is defined
        - item.network.name is defined
        - item.network.create | default(true)
        - item.network.router is defined
        - item.network.router.name is defined
        - item.network.subnet is defined
        - item.network.subnet.name is defined
      loop: "{{ molecule_yml.platforms }}"

    - name: Create ssh key
      openstack.cloud.keypair:
        name: "{{ key_name }}"
        state: present
      register: key_pair

    - name: Persist identity file
      ansible.builtin.copy:
        dest: "{{ identity_file }}"
        content: "{{ key_pair.keypair.private_key }}"
        mode: "0600"
      when: key_pair is changed # noqa no-handler

    - name: Create openstack instance
      openstack.cloud.server:
        state: present
        name: "molecule-test-{{ item.name }}-{{ uuid }}"
        description: "{{ item.description | default('Molecule test instance') }}"
        image: "{{ item.image }}"
        key_name: "{{ key_name }}"
        flavor: "{{ item.flavor }}"
        floating_ip_pools: "{{ item.floating_ip_pools if item.floating_ip_pools is defined and item.floating_ip_pools | length > 0 else omit }}"
        auto_ip: "{{ item.auto_ip if item.auto_ip is defined else omit }}"
        boot_from_volume: "{{ true if item.volume is defined and item.volume.size else false }}"
        terminate_volume: "{{ true if item.volume is defined and item.volume.size else false }}"
        volume_size: "{{ item.volume.size if item.volume is defined and item.volume.size else omit }}"
        network: >-
          {{
            'molecule-test-' + item.network.name + '-' + uuid
            if item.network is defined and item.network.name and (item.network.create | default(true))
            else item.network.name
            if item.network is defined and item.network.name and not (item.network.create | default(true))
            else 'public'
          }}
        security_groups:
          - >-
            {{
              'molecule-test-' + item.security_group.name + '-' + uuid
              if item.security_group is defined and item.security_group.name and (item.security_group.create | default(true))
              else item.security_group.name
              if item.security_group is defined and item.security_group.name and not (item.security_group.create | default(true))
              else 'default'
            }}
        meta:
          user: "{{ item.user }}"
          molecule_instance: "{{ item.name }}"
          network: >-
            {{
              'molecule-test-' + item.network.name + '-' + uuid
              if item.network is defined and item.network.name and (item.network.create | default(true))
              else item.network.name
              if item.network is defined and item.network.name and not (item.network.create | default(true))
              else 'public'
            }}
      loop: "{{ molecule_yml.platforms }}"

    - name: Create molecule instances configuration
      block:
        - name: Initialize an empty list for storing all instances
          ansible.builtin.set_fact:
            all_instances: []

        - name: Retrieve server information
          openstack.cloud.server_info:
            server: "molecule-test-*-{{ uuid }}"
          register: server_info

        - name: Include server_addr tasks
          ansible.builtin.include_tasks: "tasks/server_addr.yml"
          loop: "{{ server_info.servers }}"

        - name: Wipe out instance config
          ansible.builtin.set_fact:
            instance_conf: {}

        - name: Convert instance config dict to a list
          ansible.builtin.set_fact:
            instance_conf: "{{ all_instances | map(attribute='ansible_facts.instance_conf_dict') | list }}"

        - name: Dump instance config
          ansible.builtin.copy:
            content: "{{ instance_conf }}"
            dest: "{{ molecule_instance_config }}"
            mode: "0600"

        - name: Wait for SSH
          ansible.builtin.wait_for:
            port: 22
            host: "{{ item.address }}"
            search_regex: SSH
            delay: 10
          loop: "{{ lookup('file', molecule_instance_config) | from_yaml }}"
