---
- name: Launch instance(s)
  hosts: localhost
  become: no
  connection: local
  gather_facts: no
  vars_files:
  - vars.yml
  tasks:
  # TODO: Write an Ansible module for dealing with HEAT stacks
  #       Dealing with the outputs is currently terrible

  - name: Check OpenStack stack
    command: 'heat stack-show openshift-ansible-{{ cluster_id }}-stack'
    register: stack_show_result
    changed_when: false
    failed_when: stack_show_result.rc != 0 and 'Stack not found' not in stack_show_result.stderr

  - set_fact:
      heat_stack_action: 'stack-create'
    when: stack_show_result.rc == 1
  - set_fact:
      heat_stack_action: 'stack-update'
    when: stack_show_result.rc == 0

  - name: Create or Update OpenStack Stack
    command: 'heat {{ heat_stack_action }} -f {{ openstack_infra_heat_stack }}
             --timeout {{ openstack_heat_timeout }}
             -P cluster_env={{ cluster_env }}
             -P cluster_id={{ cluster_id }}
             -P subnet_24_prefix={{ openstack_subnet_24_prefix }}
             -P dns_nameservers={{ openstack_network_dns | join(",") }}
             -P external_net={{ openstack_network_external_net }}
             -P ssh_public_key="{{ openstack_ssh_public_key }}"
             -P ssh_incoming={{ openstack_ssh_access_from }}
             -P node_port_incoming={{ openstack_node_port_access_from }}
             -P num_etcd={{ num_etcd }}
             -P num_masters={{ num_masters }}
             -P num_nodes={{ num_nodes }}
             -P num_infra={{ num_infra }}
             -P etcd_image={{ deployment_vars[deployment_type].image }}
             -P master_image={{ deployment_vars[deployment_type].image }}
             -P node_image={{ deployment_vars[deployment_type].image }}
             -P infra_image={{ deployment_vars[deployment_type].image }}
             -P etcd_flavor={{ openstack_flavor["etcd"] }}
             -P master_flavor={{ openstack_flavor["master"] }}
             -P node_flavor={{ openstack_flavor["node"] }}
             -P infra_flavor={{ openstack_flavor["infra"] }}
             openshift-ansible-{{ cluster_id }}-stack'
    args:
      chdir: '{{ playbook_dir }}'

  - name: Wait for OpenStack Stack readiness
    shell: 'heat stack-show openshift-ansible-{{ cluster_id }}-stack | awk ''$2 == "stack_status" {print $4}'''
    register: stack_show_status_result
    until: stack_show_status_result.stdout not in ['CREATE_IN_PROGRESS', 'UPDATE_IN_PROGRESS']
    retries: 30
    delay: 5

  - name: Display the stack resources
    command: 'heat resource-list openshift-ansible-{{ cluster_id }}-stack'
    register: stack_resource_list_result
    when: stack_show_status_result.stdout not in ['CREATE_COMPLETE', 'UPDATE_COMPLETE']

  - name: Display the stack status
    command: 'heat stack-show openshift-ansible-{{ cluster_id }}-stack'
    register: stack_show_result
    when: stack_show_status_result.stdout not in ['CREATE_COMPLETE', 'UPDATE_COMPLETE']

  - name: Delete the stack
    command: 'heat stack-delete openshift-ansible-{{ cluster_id }}-stack'
    when: stack_show_status_result.stdout not in ['CREATE_COMPLETE', 'UPDATE_COMPLETE']

  - fail:
      msg: |

        +--------------------------------------+
        |   ^                                  |
        |  /!\ Failed to create the heat stack |
        | /___\                                |
        +--------------------------------------+

        Here is the list of stack resources and their status:
        {{ stack_resource_list_result.stdout }}

        Here is the status of the stack:
        {{ stack_show_result.stdout }}

          ^   Failed to create the heat stack
         /!\
        /___\ Please check the `stack_status_reason` line in the above array to know why.
    when: stack_show_status_result.stdout not in ['CREATE_COMPLETE', 'UPDATE_COMPLETE']

  - name: Read OpenStack Stack outputs
    command: 'heat stack-show openshift-ansible-{{ cluster_id }}-stack'
    register: stack_show_result

  - set_fact:
      parsed_outputs: "{{ stack_show_result | oo_parse_heat_stack_outputs }}"

  - name: Add new etcd instances groups and variables
    add_host:
      hostname: '{{ item[0] }}'
      ansible_ssh_host: '{{ item[2] }}'
      ansible_ssh_user: "{{ deployment_vars[deployment_type].ssh_user }}"
      ansible_become: "{{ deployment_vars[deployment_type].become }}"
      groups: 'meta-environment_{{ cluster_env }}, meta-host-type_etcd, meta-sub-host-type_default, meta-clusterid_{{ cluster_id }}'
      openshift_node_labels:
        type: "etcd"
      openstack:
        public_v4: '{{ item[2] }}'
        private_v4: '{{ item[1] }}'
    with_together:
    - '{{ parsed_outputs.etcd_names }}'
    - '{{ parsed_outputs.etcd_ips }}'
    - '{{ parsed_outputs.etcd_floating_ips }}'

  - name: Add new master instances groups and variables
    add_host:
      hostname: '{{ item[0] }}'
      ansible_ssh_host: '{{ item[2] }}'
      ansible_ssh_user: "{{ deployment_vars[deployment_type].ssh_user }}"
      ansible_become: "{{ deployment_vars[deployment_type].become }}"
      groups: 'meta-environment_{{ cluster_env }}, meta-host-type_master, meta-sub-host-type_default, meta-clusterid_{{ cluster_id }}'
      openshift_node_labels:
        type: "master"
      openstack:
        public_v4: '{{ item[2] }}'
        private_v4: '{{ item[1] }}'
    with_together:
    - '{{ parsed_outputs.master_names }}'
    - '{{ parsed_outputs.master_ips }}'
    - '{{ parsed_outputs.master_floating_ips }}'

  - name: Add new node instances groups and variables
    add_host:
      hostname: '{{ item[0] }}'
      ansible_ssh_host: '{{ item[2] }}'
      ansible_ssh_user: "{{ deployment_vars[deployment_type].ssh_user }}"
      ansible_become: "{{ deployment_vars[deployment_type].become }}"
      groups: 'meta-environment_{{ cluster_env }}, meta-host-type_node, meta-sub-host-type_compute, meta-clusterid_{{ cluster_id }}'
      openshift_node_labels:
        type: "compute"
      openstack:
        public_v4: '{{ item[2] }}'
        private_v4: '{{ item[1] }}'
    with_together:
    - '{{ parsed_outputs.node_names }}'
    - '{{ parsed_outputs.node_ips }}'
    - '{{ parsed_outputs.node_floating_ips }}'

  - name: Add new infra instances groups and variables
    add_host:
      hostname: '{{ item[0] }}'
      ansible_ssh_host: '{{ item[2] }}'
      ansible_ssh_user: "{{ deployment_vars[deployment_type].ssh_user }}"
      ansible_become: "{{ deployment_vars[deployment_type].become }}"
      groups: 'meta-environment_{{ cluster_env }}, meta-host-type_node, meta-sub-host-type_infra, meta-clusterid_{{ cluster_id }}'
      openshift_node_labels:
        type: "infra"
      openstack:
        public_v4: '{{ item[2] }}'
        private_v4: '{{ item[1] }}'
    with_together:
    - '{{ parsed_outputs.infra_names }}'
    - '{{ parsed_outputs.infra_ips }}'
    - '{{ parsed_outputs.infra_floating_ips }}'

  - name: Wait for ssh
    wait_for:
      host: '{{ item }}'
      port: 22
    with_flattened:
    - '{{ parsed_outputs.master_floating_ips }}'
    - '{{ parsed_outputs.node_floating_ips }}'
    - '{{ parsed_outputs.infra_floating_ips }}'

  - name: Wait for user setup
    command: 'ssh -o StrictHostKeyChecking=no -o PasswordAuthentication=no -o ConnectTimeout=10 -o UserKnownHostsFile=/dev/null {{ deployment_vars[deployment_type].ssh_user }}@{{ item }} echo {{ deployment_vars[deployment_type].ssh_user }} user is setup'
    register: result
    until: result.rc == 0
    retries: 30
    delay: 1
    with_flattened:
    - '{{ parsed_outputs.master_floating_ips }}'
    - '{{ parsed_outputs.node_floating_ips }}'
    - '{{ parsed_outputs.infra_floating_ips }}'

- include: update.yml

- include: list.yml
