Improve application role testability

Remove different phases for application role as
those are supposed to run after each other anyway
from playbook and pre/post steps can be disabled
by other means.

Enable Helm override file generation customization by
delegating it to separate role.

Separate Helm file transfer to own module.

NOTE: install.yml with all Helm commands (shell/command)
is not idempotent and should be fixed with separate
commit.

Issue-ID: OOM-1655

Change-Id: Ib29773c4d64a0529c71c3f93c2af7265ae94059f
Signed-off-by: Samuli Silvius <s.silvius@partner.samsung.com>
diff --git a/ansible/roles/application/tasks/custom_role.yml b/ansible/roles/application/tasks/custom_role.yml
new file mode 100644
index 0000000..f0b9a84
--- /dev/null
+++ b/ansible/roles/application/tasks/custom_role.yml
@@ -0,0 +1,8 @@
+---
+# Caller fills application_custom_role variable with actual role name.
+- name: "Execute custom role {{ application_custom_role }} for Helm install."
+  include_role:
+    name: "{{ application_custom_role }}"
+  when:
+    - application_custom_role is defined
+    - application_custom_role is not none
diff --git a/ansible/roles/application/tasks/install.yml b/ansible/roles/application/tasks/install.yml
new file mode 100644
index 0000000..103ecc8
--- /dev/null
+++ b/ansible/roles/application/tasks/install.yml
@@ -0,0 +1,77 @@
+---
+- name: Helm init and upgrade
+  command: |
+     {{ helm_bin_dir }}/helm init
+     --upgrade
+     --skip-refresh
+  changed_when: true # init is always changed type of action
+
+# A correct way to implement this would be using --wait option in helm init invocation.
+# However, it does not work due to https://github.com/helm/helm/issues/4031 (fixed in newer helm release)
+- name: "Wait for helm upgrade to finish"
+  command: "{{ helm_bin_dir }}/helm version --tiller-connection-timeout 10"
+  register: result
+  until: result.rc == 0
+  delay: 10
+  retries: 12
+  changed_when: false # for idempotency
+
+- name: Get all helm repos
+  command: "{{ helm_bin_dir }}/helm repo list"
+  register: repos
+  changed_when: false # for idempotency
+
+- name: Remove stable repo
+  command: "{{ helm_bin_dir }}/helm repo remove stable"
+  changed_when: true # when executed its a changed type of action
+  when: "'stable' in repos.stdout"
+
+- name: Helm Serve
+  shell: "{{ helm_bin_dir }}/helm serve &"
+  async: 45
+  poll: 3 # wait 3sec to get a chance for some stderr
+  register: helm_serve
+  changed_when: "'address already in use' not in helm_serve.stderr"
+
+- name: List helm repos
+  command: "{{ helm_bin_dir }}/helm repo list"
+  register: helm_repo_list
+  changed_when: false # for idempotency
+  failed_when:
+    - helm_repo_list.rc > 0
+    - "'Error: no repositories to show' not in helm_repo_list.stderr"
+
+- name: Helm Add Repo
+  command: "{{ helm_bin_dir }}/helm repo add {{ helm_repository_name | mandatory }} {{ helm_repository_url | mandatory }}"
+  when: "'local' not in helm_repo_list.stdout"
+  changed_when: true # when executed its a changed type of action
+
+- name: Build local helm repository
+  make:
+    chdir: "{{ app_helm_charts_infra_directory }}"
+    target: "{{ item }}"
+  loop: "{{ app_helm_build_targets }}"
+  environment:
+    PATH: "{{ helm_bin_dir }}:{{ ansible_env.PATH }}"
+
+- name: Generate Helm application override file with custom role
+  include_role:
+    name: "{{ app_helm_override_role }}"
+  when: not app_skip_helm_override
+
+- name: Check for deploy plugin presence
+  stat:
+    path: '{{ helm_home_dir.stdout }}/plugins/deploy/deploy.sh'
+  register: deploy_plugin_presence
+
+- name: "Helm Install application {{ app_name }}"
+  command: >
+          {{ helm_bin_dir }}/helm
+          {{ 'deploy' if deploy_plugin_presence.stat.exists else 'install --name' }}
+          {{ app_helm_release_name }}
+          {{ helm_repository_name }}/{{ app_helm_chart_name }}
+          --namespace {{ app_kubernetes_namespace }}
+          {{ '' if app_skip_helm_override else '-f ' + app_helm_override_file }}
+  changed_when: true # when executed its a changed type of action
+  register: helm_install
+  failed_when: helm_install.stderr
diff --git a/ansible/roles/application/tasks/main.yml b/ansible/roles/application/tasks/main.yml
new file mode 100644
index 0000000..3018e95
--- /dev/null
+++ b/ansible/roles/application/tasks/main.yml
@@ -0,0 +1,24 @@
+---
+- name: Check if application Helm charts exist and install is even needed
+  block:
+    - name: "Does {{ app_helm_charts_install_directory }} directory exist and contain Helm Charts"
+      find:
+        paths: "{{ app_helm_charts_install_directory }}"
+        recurse: true
+      delegate_to: localhost
+      register: charts_files
+    - name: Set install active fact
+      set_fact:
+        install_needed: "{{ true if charts_files.matched | int > 0 else false }}"
+
+- name: Install app with Helm charts
+  block:
+    - include_tasks: transfer-helm-charts.yml
+    - include_tasks: pre-install.yml
+    - include_tasks: install.yml
+    - include_tasks: post-install.yml
+  when: install_needed
+
+- debug:
+    msg: "NOTE, nothing done as application Helm charts does not exist!"
+  when: not install_needed
diff --git a/ansible/roles/application/tasks/post-install.yml b/ansible/roles/application/tasks/post-install.yml
new file mode 100644
index 0000000..5464cb4
--- /dev/null
+++ b/ansible/roles/application/tasks/post-install.yml
@@ -0,0 +1,5 @@
+---
+- name: "Execute custome role {{ application_post_install_role }} if defined."
+  include_tasks: custom_role.yml
+  vars:
+    application_custom_role: "{{ application_post_install_role | default('') }}"
diff --git a/ansible/roles/application/tasks/pre-install.yml b/ansible/roles/application/tasks/pre-install.yml
new file mode 100644
index 0000000..74f1548
--- /dev/null
+++ b/ansible/roles/application/tasks/pre-install.yml
@@ -0,0 +1,5 @@
+---
+- name: "Execute custom role {{ application_pre_install_role }} if defined."
+  include_tasks: custom_role.yml
+  vars:
+    application_custom_role: "{{ application_pre_install_role | default('') }}"
diff --git a/ansible/roles/application/tasks/transfer-helm-charts.yml b/ansible/roles/application/tasks/transfer-helm-charts.yml
new file mode 100644
index 0000000..0cd7c02
--- /dev/null
+++ b/ansible/roles/application/tasks/transfer-helm-charts.yml
@@ -0,0 +1,44 @@
+---
+# before custom specific code is executed we need to move helm charts to infra
+- name: Distribute helm charts to infra node
+  block:
+    - name: Archive helm charts
+      archive:
+        path: "{{ app_helm_charts_install_directory }}/*"
+        dest: "{{ app_helm_charts_install_directory }}.tgz"
+      delegate_to: localhost
+    - name: Create helm charts dir on infra
+      file:
+        path: "{{ app_helm_charts_infra_directory }}"
+        state: directory
+        mode: 0755
+    - name: Unarchive helm charts on infra node
+      unarchive:
+        src: "{{ app_helm_charts_install_directory }}.tgz"
+        dest: "{{ app_helm_charts_infra_directory }}"
+
+
+- name: Install helm plugins if needed
+  block:
+    - name: Get helm dir
+      command: "{{ helm_bin_dir }}/helm home"
+      register: helm_home_dir
+    - name: Ensure that dir for helm plugins exists
+      file:
+        path: "{{ helm_home_dir.stdout }}/plugins"
+        state: directory
+        mode: 0755
+    - name: Register all plugins to be inserted by dir names
+      find:
+        paths: "{{ app_helm_plugins_directory }}"
+        file_type: "directory"
+      register: list_of_plugins
+      delegate_to: localhost
+    - name: Install all helm plugins from {{ app_helm_plugins_directory }} dir
+      copy:
+        src: "{{ item.path }}"
+        dest: "{{ helm_home_dir.stdout }}/plugins"
+        directory_mode: true
+        mode: 0755
+      with_items: "{{ list_of_plugins.files }}"
+  when: app_helm_plugins_directory is defined and app_helm_plugins_directory is not none