---
- name: Test kolla-ansible role extras
  hosts: localhost
  connection: local
  tasks:
    - name: Add a seed host to the inventory
      add_host:
        name: test-seed
        groups: seed

    - name: Add a controller host to the inventory
      add_host:
        name: test-controller
        groups: controllers

    - name: Add a compute host to the inventory
      add_host:
        name: test-compute
        groups: compute

    - name: Create a temporary directory
      tempfile:
        state: directory
      register: tempfile_result

    - name: Create directory for custom overcloud foo group vars
      file:
        path: "{{ tempfile_result.path ~ '/etc/kayobe/kolla/inventory/group_vars/foo_group' }}"
        state: directory

    - name: Create extra globals file
      copy:
        content: |
          ---
          extra-global-1: "extra-val-1"
          extra-global-2: "extra-val-2"
        dest: "{{ tempfile_result.path ~ '/etc/kayobe/kolla/globals.yml' }}"

    - name: Create custom overcloud foo group vars
      copy:
        dest: "{{ tempfile_result.path ~ '/etc/kayobe/kolla/inventory/group_vars/foo_group/all' }}"
        content: |
          ---
          foo_port: "1234"

    - name: Create custom overcloud bar group vars
      copy:
        dest: "{{ tempfile_result.path ~ '/etc/kayobe/kolla/inventory/group_vars/bar_group' }}"
        content: |
          ---
          bar_port: "4567"

    - name: Create directory for custom CA certificates
      file:
        path: "{{ tempfile_result.path }}/etc/kayobe/kolla/certificates/ca"
        state: directory

    - name: Create custom CA certificate
      copy:
        dest: "{{ tempfile_result.path }}/etc/kayobe/kolla/certificates/ca/foo.crt"
        content: |
          bogus CA certificate

    - name: Create custom backend certificate
      copy:
        dest: "{{ tempfile_result.path }}/etc/kayobe/kolla/certificates/backend-cert.pem"
        content: |
          bogus backend certificate

    - block:
        - name: Test the kolla-ansible role with default values
          include_role:
            name: ../../kolla-ansible
          vars:
            kolla_ansible_source_path: "{{ temp_path }}/src"
            kolla_ansible_ctl_install_type: "source"
            kolla_ansible_source_url: "http://github.com/openstack/kolla-ansible"
            kolla_ansible_source_version: "{{ openstack_branch }}"
            kolla_ansible_venv: "{{ temp_path }}/venv"
            kolla_ansible_vault_password: "fake-password"
            kolla_config_path: "{{ temp_path }}/etc/kolla"
            kolla_overcloud_group_vars_path: "{{ temp_path }}/etc/kayobe/kolla/inventory/group_vars"
            kolla_node_custom_config_path: "{{ temp_path }}/etc/kolla/config"
            kolla_ansible_passwords_path: "{{ temp_path }}/passwords.yml"
            # Config.
            kolla_ansible_user: "fake-user"
            kolla_ansible_group: "fake-group"
            kolla_base_distro: "fake-distro"
            kolla_install_type: "fake-install-type"
            kolla_docker_namespace: "fake-namespace"
            kolla_docker_registry: "fake-registry"
            kolla_docker_registry_username: "fake-username"
            kolla_openstack_release: "fake-release"
            kolla_internal_vip_address: "10.0.0.1"
            kolla_internal_fqdn: "fake.internal.fqdn"
            kolla_external_vip_address: "10.0.0.2"
            kolla_external_fqdn: "fake.external.fqdn"
            # Inventory mapping.
            kolla_overcloud_inventory_top_level_group_map:
              control:
                groups:
                  - controllers
              compute:
                groups:
                  - compute
            kolla_overcloud_inventory_kolla_top_level_groups:
              - "control"
              - "compute"
            kolla_neutron_ml2_type_drivers:
              - "fake-ml2-type-1"
              - "fake-ml2-type-2"
            kolla_neutron_ml2_tenant_network_types:
              - "fake-ml2-tenant-type-1"
              - "fake-ml2-tenant-type-2"
            kolla_ansible_certificates_path: "{{ temp_path }}/etc/kayobe/kolla/certificates"
            kolla_enable_tls_external: True
            kolla_external_fqdn_cert: "{{ temp_path }}/etc/kolla/certificates/external.pem"
            kolla_external_tls_cert: |
              bogus external certificate
            kolla_enable_tls_internal: True
            kolla_internal_fqdn_cert: "{{ temp_path }}/etc/kolla/certificates/internal.pem"
            kolla_internal_tls_cert: |
              bogus internal certificate
            kolla_openstack_logging_debug: True
            grafana_local_admin_user_name: "grafana-admin"
            kolla_inspector_dhcp_pool_start: "1.2.3.4"
            kolla_inspector_dhcp_pool_end: "1.2.3.5"
            kolla_inspector_netmask: "255.255.255.0"
            kolla_inspector_default_gateway: "1.2.3.6"
            # Enable everything.
            kolla_enable_aodh: True
            kolla_enable_barbican: True
            kolla_enable_blazar: True
            kolla_enable_ceilometer: True
            kolla_enable_central_logging: True
            kolla_enable_cinder: True
            kolla_enable_cinder_backend_hnas_iscsi: True
            kolla_enable_cinder_backend_hnas_nfs: True
            kolla_enable_cinder_backend_iscsi: True
            kolla_enable_cinder_backend_lvm: True
            kolla_enable_cinder_backend_nfs: True
            kolla_enable_cloudkitty: True
            kolla_enable_designate: True
            kolla_enable_elasticsearch: True
            kolla_enable_etcd: True
            kolla_enable_freezer: True
            kolla_enable_gnocchi: True
            kolla_enable_grafana: True
            kolla_enable_haproxy: True
            kolla_enable_heat: True
            kolla_enable_horizon: True
            kolla_enable_influxdb: True
            kolla_enable_ironic: True
            kolla_enable_ironic_neutron_agent: True
            kolla_enable_kafka: True
            kolla_enable_kibana: True
            kolla_enable_kuryr: True
            kolla_enable_magnum: True
            kolla_enable_manila: True
            kolla_enable_manila_backend_generic: True
            kolla_enable_manila_backend_hnas: True
            kolla_enable_mariadb: True
            kolla_enable_mistral: True
            kolla_enable_monasca: True
            kolla_enable_murano: True
            kolla_enable_multipathd: True
            kolla_enable_neutron_agent_ha: True
            kolla_enable_neutron_bgp_dragent: True
            kolla_enable_neutron_dvr: True
            kolla_enable_neutron_provider_networks: True
            kolla_enable_neutron_qos: True
            kolla_enable_neutron_vpnaas: True
            kolla_enable_nova_serialconsole_proxy: True
            kolla_enable_octavia: True
            kolla_enable_osprofiler: True
            kolla_enable_prometheus: True
            kolla_enable_sahara: True
            kolla_enable_senlin: True
            kolla_enable_skydive: True
            kolla_enable_solum: True
            kolla_enable_storm: True
            kolla_enable_swift: True
            kolla_enable_tacker: True
            kolla_enable_telegraf: True
            kolla_enable_trove: True
            kolla_enable_watcher: True
            kolla_enable_zookeeper: True
            kolla_enable_zun: True
            kolla_globals_paths_extra:
              - "{{ tempfile_result.path ~ '/etc/kayobe/' }}"
            kolla_ansible_custom_passwords:
              custom-password-1: "custom-password-1"
              custom-password-2: "custom-password-2"
            kolla_nova_compute_ironic_host: "controller1"
            apt_cache_valid_time: 3600

        - name: Verify kolla-ansible installation
          shell: ". {{ temp_path }}/venv/bin/activate && kolla-ansible -h"
          changed_when: False

        - name: Verify ansible installation
          command: "{{ temp_path }}/venv/bin/ansible -h"
          changed_when: False

        - name: Validate variables are absent from globals.yml
          debug:
            var: globals_yml
          vars:
            # NOTE: Can't use set_fact for this, as it causes kolla-ansible
            # Jinja expressions to be evaluated.
            globals_yml: "{{ lookup('file', temp_path ~ '/etc/kolla/globals.yml') | from_yaml }}"

        - name: Validate globals.yml contents
          assert:
            that:
              - item.key in globals_yml
              - globals_yml[item.key] == item.value
            msg: >
              Unexpected value for variable "{{ item.key }}" in globals.yml.
              Expected "{{ item.value }}", actual
              "{{ globals_yml.get(item.key, '<missing>') }}".
          with_dict: "{{ expected_variables }}"
          vars:
            # NOTE: Can't use set_fact for this, as it causes kolla-ansible
            # Jinja expressions to be evaluated.
            globals_yml: "{{ lookup('file', temp_path ~ '/etc/kolla/globals.yml') | from_yaml }}"
            expected_variables:
              config_strategy: "COPY_ALWAYS"
              kolla_user: "fake-user"
              kolla_group: "fake-group"
              kolla_base_distro: "fake-distro"
              kolla_install_type: "fake-install-type"
              openstack_release: "fake-release"
              kolla_internal_vip_address: "10.0.0.1"
              kolla_internal_fqdn: "fake.internal.fqdn"
              kolla_external_vip_address: "10.0.0.2"
              kolla_external_fqdn: "fake.external.fqdn"
              node_custom_config: "{{ temp_path }}/etc/kolla/config"
              docker_namespace: "fake-namespace"
              docker_registry: "fake-registry"
              docker_registry_username: "fake-username"
              neutron_plugin_agent: "openvswitch"
              kolla_enable_tls_external: True
              kolla_external_fqdn_cert: "{{ temp_path }}/etc/kolla/certificates/external.pem"
              kolla_enable_tls_internal: True
              kolla_internal_fqdn_cert: "{{ temp_path }}/etc/kolla/certificates/internal.pem"
              openstack_logging_debug: True
              grafana_admin_username: "grafana-admin"
              ironic_dnsmasq_dhcp_range: "1.2.3.4,1.2.3.5,255.255.255.0"
              ironic_dnsmasq_default_gateway: "1.2.3.6"
              # NOTE: The following options are not present in globals.yml.
              # It's possible this is related to the use of hostvars and
              # include_role, caused by something like
              # https://github.com/ansible/ansible/issues/19305.
              #enable_aodh: True
              #enable_barbican: True
              #enable_blazar: True
              #enable_ceilometer: True
              #enable_central_logging: True
              #enable_cinder: True
              #enable_cinder_backend_iscsi: True
              #enable_cinder_backend_hnas_iscsi: True
              #enable_cinder_backend_hnas_nfs: True
              #enable_cinder_backend_lvm: True
              #enable_cinder_backend_nfs: True
              #enable_cloudkitty: True
              #enable_designate: True
              #enable_elasticsearch: True
              #enable_etcd: True
              #enable_freezer: True
              #enable_gnocchi: True
              #enable_grafana: True
              #enable_haproxy: True
              #enable_heat: True
              #enable_horizon: True
              #enable_influxdb: True
              #enable_ironic: True
              #enable_ironic_neutron_agent: True
              #enable_kafka: True
              #enable_kibana: True
              #enable_kuryr: True
              #enable_magnum: True
              #enable_manila: True
              #enable_manila_backend_generic: True
              #enable_manila_backend_hnas: True
              #enable_mariadb: True
              #enable_mistral: True
              #enable_monasca: True
              #enable_murano: True
              #enable_multipathd: True
              #enable_neutron_agent_ha: True
              #enable_neutron_bgp_dragent: True
              #enable_neutron_dvr: True
              #enable_neutron_provider_networks: True
              #enable_neutron_qos: True
              #enable_neutron_vpnaas: True
              #enable_nova_serialconsole_proxy: True
              #enable_octavia: True
              #enable_osprofiler: True
              #enable_prometheus: True
              #enable_sahara: True
              #enable_skydive: True
              #enable_solum: True
              #enable_senlin: True
              #enable_storm: True
              #enable_swift: True
              #enable_tacker: True
              #enable_telegraf: True
              #enable_trove: True
              #enable_watcher: True
              #enable_zookeeper: True
              #enable_zun: True
              extra-global-1: "extra-val-1"
              extra-global-2: "extra-val-2"

        - name: Validate variables are absent from globals.yml
          assert:
            that: item not in globals_yml
            msg: >
              Unexpected variable "{{ item }}" found in globals.yml, value
              "{{ globals_yml.get(item) }}".
          with_items: "{{ unexpected_variables }}"
          vars:
            # NOTE: Can't use set_fact for this, as it causes kolla-ansible
            # Jinja expressions to be evaluated.
            globals_yml: "{{ lookup('file', temp_path ~ '/etc/kolla/globals.yml') | from_yaml }}"
            unexpected_variables:
              - enable_glance
              - enable_ironic
              - enable_neutron
              - enable_nova
              - network_interface
              - api_interface
              - kolla_external_vip_interface
              - storage_interface
              - cluster_interface
              - swift_storage_interface
              - swift_replication_interface
              - provision_interface
              - ironic_dnsmasq_interface
              - dns_interface
              - tunnel_interface
              - bifrost_network_interface
              - neutron_external_interface
              - neutron_bridge_name

        - name: Create a vault password file
          copy:
            content: "fake-password"
            dest: "{{ temp_path ~ '/vault-pass' }}"

        - name: Decrypt passwords.yml
          command: ansible-vault decrypt --vault-password-file {{ temp_path ~ '/vault-pass' }} {{ temp_path ~ '/etc/kolla/passwords.yml' }}
          changed_when: False

        - name: Validate passwords.yml contents
          assert:
            that: item in passwords_yml
            msg: >
              Expected variable "{{ item }}" not present in passwords.yml.
          with_items: "{{ expected_variables }}"
          vars:
            # NOTE: Can't use set_fact for this, as it causes kolla-ansible
            # Jinja expressions to be evaluated.
            passwords_yml: "{{ lookup('file', temp_path ~ '/etc/kolla/passwords.yml') | from_yaml }}"
            expected_variables:
              - database_password
              - custom-password-1
              - custom-password-2

        - name: Validate passwords.yml custom passwords
          assert:
            that:
              - item.key in passwords_yml
              - passwords_yml[item.key] == item.value
            msg: >
              Expected custom password "{{ item.key }}" not present in passwords.yml.
          with_dict: "{{ expected_variables }}"
          vars:
            # NOTE: Can't use set_fact for this, as it causes kolla-ansible
            # Jinja expressions to be evaluated.
            passwords_yml: "{{ lookup('file', temp_path ~ '/etc/kolla/passwords.yml') | from_yaml }}"
            expected_variables:
              custom-password-1: custom-password-1
              custom-password-2: custom-password-2

        - name: Check whether inventory files exist
          stat:
            path: "{{ temp_path ~ '/etc/kolla/inventory/' ~ item ~ '/hosts' }}"
          with_items:
            - seed
            - overcloud
          register: inventory_stat

        - name: Validate inventory files
          assert:
            that:
              - item.stat.exists
              - item.stat.size > 0
            msg: >
              Inventory file {{ item.item }} was not found.
          with_items: "{{ inventory_stat.results }}"

        - name: Read inventory files
          slurp:
            src: "{{ item.stat.path }}"
          with_items: "{{ inventory_stat.results }}"
          register: inventory_slurp

        - name: Validate seed inventory file contents
          vars:
            inventory_lines: "{{ (inventory_slurp.results[0].content | b64decode).splitlines() }}"
          assert:
            that: item in inventory_lines
          with_items:
            - test-seed

        - name: Validate overcloud inventory file contents
          vars:
            inventory_lines: "{{ (inventory_slurp.results[1].content | b64decode).splitlines() }}"
          assert:
            that: item in inventory_lines
          with_items:
            - test-controller
            - test-compute

        - name: Check whether inventory group vars files exist
          stat:
            path: "{{ temp_path ~ '/etc/kolla/inventory/overcloud/group_vars/' ~ item }}"
          with_items:
            - foo_group/all
            - bar_group
          register: group_vars_stat

        - name: Validate inventory group vars files
          assert:
            that:
              - item.stat.exists
              - item.stat.size > 0
            msg: >
              Inventory file {{ item.item }} was not found.
          with_items: "{{ group_vars_stat.results }}"

        - name: Read inventory group vars files
          slurp:
            src: "{{ item.stat.path }}"
          with_items: "{{ group_vars_stat.results }}"
          register: group_vars_slurp

        - name: Validate inventory group vars file contents
          assert:
            that:
              - group_vars_content is defined
              - group_vars_content == item.1
          with_together:
            - "{{ group_vars_slurp.results }}"
            - "{{ expected_contents }}"
          vars:
            group_vars_content: "{{ item.0.content | b64decode }}"
            expected_contents:
              - |
                ---
                foo_port: "1234"
              - |
                ---
                bar_port: "4567"

        - name: Check whether API certificate files exist
          stat:
            path: "{{ temp_path ~ '/etc/kolla/certificates/' ~ item }}"
          with_items:
            - external.pem
            - internal.pem
          register: certificates_stat

        - name: Validate API certificates files
          assert:
            that:
              - item.stat.exists
              - item.stat.size > 0
            msg: >
              API certificate file {{ item.item }} was not found.
          with_items: "{{ certificates_stat.results }}"

        - name: Read API certificate files
          slurp:
            src: "{{ item.stat.path }}"
          with_items: "{{ certificates_stat.results }}"
          register: certificates_slurp

        - name: Validate API certificate file contents
          assert:
            that:
              - certificates_content is defined
              - certificates_content == item.1
          with_together:
            - "{{ certificates_slurp.results }}"
            - "{{ expected_contents }}"
          vars:
            certificates_content: "{{ item.0.content | b64decode }}"
            expected_contents:
              - |
                bogus external certificate
              - |
                bogus internal certificate

        - name: Check whether custom certificate files exist
          stat:
            path: "{{ temp_path ~ '/etc/kolla/certificates/' ~ item }}"
          with_items:
            - ca/foo.crt
            - backend-cert.pem
          register: certificates_stat

        - name: Validate custom certificates files
          assert:
            that:
              - item.stat.exists
              - item.stat.size > 0
            msg: >
              Custom certificate file {{ item.item }} was not found.
          with_items: "{{ certificates_stat.results }}"

        - name: Read custom certificate files
          slurp:
            src: "{{ item.stat.path }}"
          with_items: "{{ certificates_stat.results }}"
          register: certificates_slurp

        - name: Validate custom certificate file contents
          assert:
            that:
              - certificates_content is defined
              - certificates_content == item.1
          with_together:
            - "{{ certificates_slurp.results }}"
            - "{{ expected_contents }}"
          vars:
            certificates_content: "{{ item.0.content | b64decode }}"
            expected_contents:
              - |
                bogus CA certificate
              - |
                bogus backend certificate
      always:
        - name: Ensure the temporary directory is removed
          file:
            path: "{{ temp_path }}"
            state: absent

        - name: Refresh the inventory
          meta: refresh_inventory
      rescue:
        - name: Flag that a failure occurred
          set_fact:
            test_failures: "{{ test_failures | default(0) | int + 1 }}"
      vars:
        temp_path: "{{ tempfile_result.path }}"
