Adapt heat to stack oriented framework

The changes are
- configure jumphost is adapted depending on the deployment
type
- configure target hosts is adapted depending on the deployment
type

Change-Id: I7ff88dfa4c92398d7522494cced04b0232aa0343
diff --git a/playbooks/bootstrap-hwconfig.yaml b/playbooks/bootstrap-hwconfig.yaml
deleted file mode 100644
index f177d84..0000000
--- a/playbooks/bootstrap-hwconfig.yaml
+++ /dev/null
@@ -1,28 +0,0 @@
----
-# ============LICENSE_START=======================================================
-#  Copyright (C) 2019 The Nordix Foundation. All rights reserved.
-# ================================================================================
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# SPDX-License-Identifier: Apache-2.0
-# ============LICENSE_END=========================================================
-
-- hosts: localhost
-  connection: local
-  gather_facts: false
-  become: false
-
-  roles:
-    - role: bootstrap-hwconfig
-
-# vim: set ts=2 sw=2 expandtab:
diff --git a/playbooks/configure-targethosts.yml b/playbooks/configure-targethosts.yml
index 6311861..353f129 100644
--- a/playbooks/configure-targethosts.yml
+++ b/playbooks/configure-targethosts.yml
@@ -18,26 +18,14 @@
 # ============LICENSE_END=========================================================
 
 - hosts: jumphost
-  gather_facts: false
+  gather_facts: true
   become: false
 
-  tasks:
-    - name: Install python and python-dev on jumphost
-      script: "{{ playbook_dir }}/roles/configure-targethosts/files/install-python.sh"
-
-    - name: Copy SSH keys to jumphost for target node access
-      copy:
-        src: "{{ item }}"
-        dest: "/root/.ssh/"
-        owner: "root"
-        group: "root"
-        mode: 0600
-      with_items:
-        - "/home/{{ local_user }}/.ssh/id_rsa"
-        - "/home/{{ local_user }}/.ssh/id_rsa.pub"
+  roles:
+    - role: configure-jumphost
 
 - hosts: baremetal
-  gather_facts: false
+  gather_facts: true
   become: false
 
   roles:
diff --git a/playbooks/roles/bootstrap-hwconfig/tasks/main.yaml b/playbooks/roles/bootstrap-hwconfig/tasks/main.yaml
deleted file mode 100644
index 1aeaa94..0000000
--- a/playbooks/roles/bootstrap-hwconfig/tasks/main.yaml
+++ /dev/null
@@ -1,52 +0,0 @@
----
-# ============LICENSE_START=======================================================
-#  Copyright (C) 2019 The Nordix Foundation. All rights reserved.
-# ================================================================================
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# SPDX-License-Identifier: Apache-2.0
-# ============LICENSE_END=========================================================
-
-- name: Copy Heat templates and IDF file
-  copy:
-    src: "{{ item }}"
-    dest: "{{ config_path }}"
-  with_items:
-    - heat-template.yaml
-    - heat-server.yaml
-    - heat-jumphost.yaml
-    - heat-idf.yaml
-
-- name: Get Heat environment file
-  get_url:
-    url: "{{ heat_env_file }}"
-    dest: "{{ config_path }}/heat-environment.yaml"
-    mode: 0644
-    force: true
-
-- name: Remove existing Heat IDF symlink
-  file:
-    path: "{{ inventory_path }}/group_vars/idf.yaml"
-    state: absent
-  ignore_errors: true
-
-# NOTE: Heat IDF file is linked from config_path to inventory
-# folder in order to ensure we have single IDF
-- name: Link collected Heat IDF file to inventory folder
-  file:
-    src: "{{ config_path }}/heat-idf.yaml"
-    dest: "{{ inventory_path }}/group_vars/all/idf.yaml"
-    state: link
-    force: true
-
-# vim: set ts=2 sw=2 expandtab:
diff --git a/playbooks/roles/configure-jumphost/tasks/main.yaml b/playbooks/roles/configure-jumphost/tasks/main.yaml
new file mode 100644
index 0000000..ed7e844
--- /dev/null
+++ b/playbooks/roles/configure-jumphost/tasks/main.yaml
@@ -0,0 +1,117 @@
+---
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2019 The Nordix Foundation. All rights reserved.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+
+# we need the public IP of the jumphost so we can check if it is reachable
+- name: Get public IP of jumphost from openstack stack output
+  command: "openstack stack output show {{ heat_stack_name }} jumphost_public_ip -c output_value -f json"
+  register: stack_output
+  changed_when: false
+  until: "'output_value' in stack_output.stdout"
+  retries: 10
+  delay: 3
+  environment:
+    PATH: "{{ engine_venv }}/bin"
+  delegate_to: localhost
+  run_once: true
+
+- name: Set public IP of jumphost
+  set_fact:
+    jumphost_public_ip: "{{ stack_output.stdout }}"
+
+- name: Log jumphost public IP to console
+  debug:
+    msg: "Jumphost public IP is {{ jumphost_public_ip.output_value[0] }}"
+  delegate_to: localhost
+  run_once: true
+
+- name: Wait for jumphost to be reachable via SSH
+  wait_for:
+    host: "{{ jumphost_public_ip.output_value[0] }}"
+    port: 22
+    state: started
+    delay: 15
+    connect_timeout: 10
+    timeout: 1000
+  delegate_to: localhost
+
+- name: Copy SSH keys to jumphost for target node access
+  copy:
+    src: "{{ item }}"
+    dest: "/root/.ssh/"
+    owner: "root"
+    group: "root"
+    mode: 0600
+  with_items:
+    - "/home/{{ local_user }}/.ssh/id_rsa"
+    - "/home/{{ local_user }}/.ssh/id_rsa.pub"
+
+# NOTE (fdegir): it looks like the provisioner is the best place
+# to prepare for offline deployments as the way things done for
+# OpenStack based deployments are heavily dependend on the provisioner
+# so we transfer the dependencies to jumphost here and update apt
+# sources.list as well to ensure the rest of the provisioning and
+# installation process stays as is
+- block:
+    - name: Update /etc/hosts with server FQDN
+      lineinfile:
+        path: /etc/hosts
+        regex: '^127\.0\.0\.1'
+        line: "127.0.0.1 localhost {{ server_fqdn }}"
+
+    - name: Ensure /opt/engine exists and empty
+      file:
+        path: /opt/engine
+        state: absent
+        force: true
+      with_items:
+        - absent
+        - directory
+      ignore_errors: true
+
+    # NOTE (fdegir): we need dependencies available on jumphost
+    # before we continue with the rest of the process
+    - name: Synchronize dependencies with jumphost
+      synchronize:
+        src: /opt/engine/offline
+        dest: /opt/engine
+        recursive: true
+        delete: true
+
+    - name: Update /etc/apt/sources.list to use local apt repository
+      template:
+        src: sources.list.j2
+        dest: /etc/apt/sources.list
+        owner: root
+        group: root
+        mode: '0644'
+        backup: true
+  when: execution_mode == "offline-deployment"
+
+# NOTE (fdegir): the python dependencies except python itself may not be
+# available on the instances created on OpenStack so we install them here
+# to ensure the rest of the process does not bother with them
+- name: Install python dependencies
+  action: |
+    {{ ansible_pkg_mgr }} name={{ item }} state=present update_cache=true
+  with_items:
+    - "python3-pip"
+    - "python3-setuptools"
+    - "python3-virtualenv"
+
+# vim: set ts=2 sw=2 expandtab:
diff --git a/playbooks/roles/configure-jumphost/templates/sources.list.j2 b/playbooks/roles/configure-jumphost/templates/sources.list.j2
new file mode 100644
index 0000000..f391c4e
--- /dev/null
+++ b/playbooks/roles/configure-jumphost/templates/sources.list.j2
@@ -0,0 +1 @@
+deb [trusted=yes] file:///opt/engine/offline/pkg amd64/
diff --git a/playbooks/roles/configure-targethosts/files/install-python.sh b/playbooks/roles/configure-targethosts/files/install-python.sh
deleted file mode 100755
index f0b5337..0000000
--- a/playbooks/roles/configure-targethosts/files/install-python.sh
+++ /dev/null
@@ -1,49 +0,0 @@
-#!/bin/bash
-
-# ============LICENSE_START=======================================================
-#  Copyright (C) 2019 The Nordix Foundation. All rights reserved.
-# ================================================================================
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# SPDX-License-Identifier: Apache-2.0
-# ============LICENSE_END=========================================================
-
-set -o errexit
-set -o pipefail
-
-# NOTE: due to stack creation issues on public cloud, installation of python
-# and python-dev has been moved out of heat templates. The reason for this is
-# that during initial boot of the instances, Ansible prerequisites python and
-# python-dev are installed using boot script. Due to the reasons we can not
-# explain and perhaps because of network issues on public cloud, apt fails,
-# complaining about corruption - checksum mismatch. In turn, problematic
-# instance(s) can not send completion signal at the end of boot phase, resulting
-# in timeouts in stack creation thus complete failure of deployments.
-
-source /etc/os-release || source /usr/lib/os-release
-case ${ID,,} in
-  ubuntu|debian)
-    export DEBIAN_FRONTEND=noninteractive
-    sudo -H -E apt update -q=3
-    sudo -H -E apt install -y -q=3 python python-dev
-    ;;
-  rhel|fedora|centos)
-    sudo yum install -y python python-devel
-    ;;
-  *)
-    echo "ERROR: Supported package manager not found.  Supported: apt, dnf, yum, zypper"
-    exit 1
-    ;;
-esac
-
-# vim: set ts=2 sw=2 expandtab:
diff --git a/playbooks/roles/configure-targethosts/tasks/main.yaml b/playbooks/roles/configure-targethosts/tasks/main.yaml
index 5846d7e..9fc89aa 100644
--- a/playbooks/roles/configure-targethosts/tasks/main.yaml
+++ b/playbooks/roles/configure-targethosts/tasks/main.yaml
@@ -17,9 +17,19 @@
 # SPDX-License-Identifier: Apache-2.0
 # ============LICENSE_END=========================================================
 
+- name: Wait for target hosts to be reachable via SSH
+  wait_for:
+    host: "{{ ansible_default_ipv4.address }}"
+    port: 22
+    state: started
+    delay: 15
+    connect_timeout: 10
+    timeout: 1000
+  delegate_to: jumphost
+
 # we need the private/internal IP of the jumphost so the nodes could reach to it
-- name: Get internal IP of jumphost from openstack stack output
-  command: "openstack stack output show {{ stack_name }} jumphost_private_ip -c output_value -f json"
+- name: Get private IP of jumphost from openstack stack output
+  command: "openstack stack output show {{ heat_stack_name }} jumphost_private_ip -c output_value -f json"
   register: stack_output
   changed_when: false
   until: "'output_value' in stack_output.stdout"
@@ -30,31 +40,34 @@
   delegate_to: localhost
   run_once: true
 
-- name: Set IP of jumphost
+- name: Set private IP of jumphost
   set_fact:
-    jumphost_ips: "{{ stack_output.stdout }}"
+    jumphost_private_ip: "{{ stack_output.stdout }}"
 
-- name: Log jumphost IP to console
+- name: Log jumphost private IP to console
   debug:
-    msg: "Jumphost internal IP is {{ jumphost_ips.output_value[0] }}"
+    msg: "Jumphost internal IP is {{ jumphost_private_ip.output_value[0] }}"
+  delegate_to: localhost
+  run_once: true
 
 - name: Update /etc/hosts with server FQDN
-  raw: echo "{{ jumphost_ips.output_value[0] }} {{ server_fqdn }}" >> /etc/hosts
-  args:
-    executable: /bin/bash
-  changed_when: true
-  become: true
+  blockinfile:
+    path: /etc/hosts
+    block: |
+      # private IP of jumphost
+      {{ jumphost_private_ip.output_value[0] }} {{ server_fqdn }}
+    marker: "# {mark} Ansible managed"
 
 # NOTE (fdegir): apt sources.list is only updated for offline deployments
+# NOTE (fdegir): apt sources.list is only updated for offline deployments
 - name: Update /etc/apt/sources.list to use local apt repository
-  raw: echo "deb [trusted=yes] http://{{ server_fqdn }}/pkg amd64/" > /etc/apt/sources.list
-  args:
-    executable: /bin/bash
-  changed_when: true
-  become: true
+  template:
+    src: sources.list.j2
+    dest: /etc/apt/sources.list
+    owner: root
+    group: root
+    mode: '0644'
+    backup: true
   when: execution_mode == "offline-deployment"
 
-- name: Install python and python-dev
-  script: "install-python.sh"
-
 # vim: set ts=2 sw=2 expandtab:
diff --git a/playbooks/roles/configure-targethosts/templates/sources.list.j2 b/playbooks/roles/configure-targethosts/templates/sources.list.j2
new file mode 100644
index 0000000..cfe972c
--- /dev/null
+++ b/playbooks/roles/configure-targethosts/templates/sources.list.j2
@@ -0,0 +1 @@
+deb [trusted=yes] http://{{ server_fqdn }}/pkg amd64/
diff --git a/playbooks/roles/bootstrap-hwconfig/files/heat-environment-city-ubuntu1804.yaml b/playbooks/roles/create-stack/files/heat-environment-city-ubuntu1804.yaml
similarity index 100%
rename from playbooks/roles/bootstrap-hwconfig/files/heat-environment-city-ubuntu1804.yaml
rename to playbooks/roles/create-stack/files/heat-environment-city-ubuntu1804.yaml
diff --git a/playbooks/roles/bootstrap-hwconfig/files/heat-environment-xerces-ubuntu1804.yaml b/playbooks/roles/create-stack/files/heat-environment-xerces-ubuntu1804.yaml
similarity index 100%
rename from playbooks/roles/bootstrap-hwconfig/files/heat-environment-xerces-ubuntu1804.yaml
rename to playbooks/roles/create-stack/files/heat-environment-xerces-ubuntu1804.yaml
diff --git a/playbooks/roles/bootstrap-hwconfig/files/heat-environment.yaml b/playbooks/roles/create-stack/files/heat-environment.yaml
similarity index 100%
rename from playbooks/roles/bootstrap-hwconfig/files/heat-environment.yaml
rename to playbooks/roles/create-stack/files/heat-environment.yaml
diff --git a/playbooks/roles/bootstrap-hwconfig/files/heat-idf.yaml b/playbooks/roles/create-stack/files/heat-idf.yaml
similarity index 100%
rename from playbooks/roles/bootstrap-hwconfig/files/heat-idf.yaml
rename to playbooks/roles/create-stack/files/heat-idf.yaml
diff --git a/playbooks/roles/bootstrap-hwconfig/files/heat-jumphost.yaml b/playbooks/roles/create-stack/files/heat-jumphost.yaml
similarity index 100%
rename from playbooks/roles/bootstrap-hwconfig/files/heat-jumphost.yaml
rename to playbooks/roles/create-stack/files/heat-jumphost.yaml
diff --git a/playbooks/roles/bootstrap-hwconfig/files/heat-server.yaml b/playbooks/roles/create-stack/files/heat-server.yaml
similarity index 100%
rename from playbooks/roles/bootstrap-hwconfig/files/heat-server.yaml
rename to playbooks/roles/create-stack/files/heat-server.yaml
diff --git a/playbooks/roles/bootstrap-hwconfig/files/heat-template.yaml b/playbooks/roles/create-stack/files/heat-template.yaml
similarity index 100%
rename from playbooks/roles/bootstrap-hwconfig/files/heat-template.yaml
rename to playbooks/roles/create-stack/files/heat-template.yaml
diff --git a/playbooks/roles/create-stack/tasks/main.yml b/playbooks/roles/create-stack/tasks/main.yml
index fe710eb..8244fa9 100644
--- a/playbooks/roles/create-stack/tasks/main.yml
+++ b/playbooks/roles/create-stack/tasks/main.yml
@@ -17,9 +17,18 @@
 # SPDX-License-Identifier: Apache-2.0
 # ============LICENSE_END=========================================================
 
+- name: Copy Heat templates
+  copy:
+    src: "{{ item }}"
+    dest: "{{ config_path }}"
+  with_items:
+    - heat-template.yaml
+    - heat-server.yaml
+    - heat-jumphost.yaml
+
 - name: Set keypair name
   set_fact:
-    keypair_name: "keypair-{{ stack_name | regex_replace('\\.', '_') }}"
+    keypair_name: "keypair-{{ heat_stack_name | regex_replace('\\.', '_') }}"
 
 - name: Delete keypair '{{ keypair_name }}'
   os_keypair:
@@ -27,9 +36,9 @@
     state: absent
   ignore_errors: true
 
-- name: Delete stack '{{ stack_name }}'
+- name: Delete stack '{{ heat_stack_name }}'
   os_stack:
-    name: "{{ stack_name }}"
+    name: "{{ heat_stack_name }}"
     state: absent
     wait: true
   ignore_errors: false
@@ -45,13 +54,13 @@
     state: present
     public_key_file: "{{ ansible_env.HOME }}/.ssh/id_rsa.pub"
 
-- name: Create stack '{{ stack_name }}'
+- name: Create stack '{{ heat_stack_name }}'
   os_stack:
-    name: "{{ stack_name }}"
+    name: "{{ heat_stack_name }}"
     state: present
     template: "{{ engine_cache }}/config/heat-template.yaml"
     environment:
-      - "{{ engine_cache }}/config/heat-environment.yaml"
+      - "{{ inventory_path }}/group_vars/all/pdf.yaml"
     parameters:
       keypair: "{{ keypair_name }}"
     wait: true
@@ -63,7 +72,7 @@
     msg: "{{ stack_create_output }}"
 
 - name: Get stack list
-  command: "openstack stack list --property name={{ stack_name }}"
+  command: "openstack stack list --property name={{ heat_stack_name }}"
   when: stack_create_output
   register: stack_list_output
   environment:
diff --git a/playbooks/roles/generate-inventory/tasks/generate-kubespray-inventory.yml b/playbooks/roles/generate-inventory/tasks/generate-kubespray-inventory.yml
index 94e1072..41e51c9 100644
--- a/playbooks/roles/generate-inventory/tasks/generate-kubespray-inventory.yml
+++ b/playbooks/roles/generate-inventory/tasks/generate-kubespray-inventory.yml
@@ -18,7 +18,7 @@
 # ============LICENSE_END=========================================================
 
 - name: Get IP of jumphost
-  command: "openstack stack output show {{ stack_name }} jumphost_public_ip -c output_value -f json"
+  command: "openstack stack output show {{ heat_stack_name }} jumphost_public_ip -c output_value -f json"
   register: stack_output_jumphost_public_ip
   changed_when: false
   until: "'output_value' in stack_output_jumphost_public_ip.stdout"
@@ -28,7 +28,7 @@
     PATH: "{{ engine_venv }}/bin"
 
 - name: Get IPs of master nodes
-  command: "openstack stack output show {{ stack_name }} master_private_ip -c output_value -f json"
+  command: "openstack stack output show {{ heat_stack_name }} master_private_ip -c output_value -f json"
   register: stack_output_master_private_ip
   changed_when: false
   until: "'output_value' in stack_output_master_private_ip.stdout"
@@ -38,7 +38,7 @@
     PATH: "{{ engine_venv }}/bin"
 
 - name: Get IPs of worker nodes
-  command: "openstack stack output show {{ stack_name }} worker_private_ip -c output_value -f json"
+  command: "openstack stack output show {{ heat_stack_name }} worker_private_ip -c output_value -f json"
   register: stack_output_worker_private_ip
   changed_when: false
   until: "'output_value' in stack_output_worker_private_ip.stdout"
diff --git a/playbooks/roles/generate-inventory/tasks/main.yml b/playbooks/roles/generate-inventory/tasks/main.yml
index 2384384..05cc6fb 100644
--- a/playbooks/roles/generate-inventory/tasks/main.yml
+++ b/playbooks/roles/generate-inventory/tasks/main.yml
@@ -19,6 +19,5 @@
 
 # generate kubespray inventory from Heat stack output
 - include: generate-kubespray-inventory.yml
-  when: installer_type == 'kubespray'
 
 # vim: set ts=2 sw=2 expandtab:
diff --git a/provision.sh b/provision.sh
index b84079f..3a0ce66 100755
--- a/provision.sh
+++ b/provision.sh
@@ -31,18 +31,13 @@
 # NOTE: shellcheck SC1090 is disabled since openrc file is put in place during runtime
 # source openrc file
 # shellcheck disable=SC1090
+if [[ -z "${OPENRC+x}" || ! -f "${OPENRC}" ]]; then
+  echo "ERROR : Unable to access openrc file!"
+  exit 1
+fi
+# shellcheck disable=SC1090
 source "$OPENRC"
 
-#-------------------------------------------------------------------------------
-# Bootstrap hwconfig
-#-------------------------------------------------------------------------------
-echo "Info  : Bootstrap hardware configuration"
-echo "-------------------------------------------------------------------------"
-cd "${ENGINE_PATH}"
-ansible-playbook "${ENGINE_ANSIBLE_PARAMS[@]}" \
-    -i "${ENGINE_PATH}/engine/inventory/localhost.ini" \
-    "${PROVISIONER_ROOT_DIR}/playbooks/bootstrap-hwconfig.yaml"
-
 echo "Info  : Create stack using Heat"
 echo "-------------------------------------------------------------------------"
 cd "${ENGINE_PATH}"
@@ -58,7 +53,7 @@
     "${PROVISIONER_ROOT_DIR}/playbooks/generate-inventory.yml"
 
 echo "-------------------------------------------------------------------------"
-echo "Info  : Configure target hosts provisioned using Heat"
+echo "Info  : Configure instances provisioned using Heat"
 echo "-------------------------------------------------------------------------"
 cd "${ENGINE_PATH}"
 ansible-playbook "${ENGINE_ANSIBLE_PARAMS[@]}" \
diff --git a/vars/heat.yaml b/vars/heat.yaml
index f9d2a65..67ec443 100644
--- a/vars/heat.yaml
+++ b/vars/heat.yaml
@@ -28,4 +28,12 @@
 # with each other.
 # -------------------------------------------------------------------------------
 
+# NOTE (fdegir): local_user is the user whose ssh keys are copied to the jumphost
+# in order to access to target nodes as jumphost is where the deployment and
+# testing is driven toward target hosts
+local_user: "{{ lookup('env', 'USER') }}"
+
+# NOTE (fdegir): Name of the Heat stack to create on OpenStack
+heat_stack_name: "{{ lookup('env', 'HEAT_STACK_NAME') | default('nordix-' + deploy_scenario + '-custom', true) }}"
+
 # vim: set ts=2 sw=2 expandtab: