VOL-415 Changes to improve dependencies and solve intermittent installer
failures.

Change-Id: I6f23f42398e0509a231008f4a83e60cb12759d52
diff --git a/install/ansible/roles/cluster-host/tasks/main.yml b/install/ansible/roles/cluster-host/tasks/main.yml
index 7872fa6..7358e6e 100644
--- a/install/ansible/roles/cluster-host/tasks/main.yml
+++ b/install/ansible/roles/cluster-host/tasks/main.yml
@@ -63,6 +63,31 @@
     - deb_files
   tags: [cluster-host]
 
+- name: Required configuration scripts are copied
+  synchronize:
+    src: "/home/vinstall/{{ item }}"
+    dest: "{{ target_voltha_home }}"
+    archive: no
+    owner: no
+    perms: no
+    recursive: no
+    links: yes
+  with_items:
+    - sort_packages.sh
+    - sort_packages.py
+    - install_packages.sh
+  tags: [cluster-host]
+
+- name: The installer scripts are made executable
+  file:
+    path: "{{target_voltha_home }}/{{ item }}"
+    mode: 0744
+  with_items:
+    - sort_packages.sh
+    - sort_packages.py
+    - install_packages.sh
+  tags: [installer]
+
 - name: apt lists are up-to-date
   synchronize:
     src: "/var/lib/apt/lists"
@@ -102,8 +127,8 @@
   tags: [cluster_host]
 
 - name: Dependent software is installed (this can take about 10 Min, DONT'T PANIC, go for coffee instead)
-  command: dpkg -R -i "{{ target_voltha_home }}/deb_files"
-#  ignore_errors: true
+  command: "{{ target_voltha_home }}/install_packages.sh"
+#  command: dpkg -R -i "{{ target_voltha_home }}/deb_files"
   when: target == "cluster"
   tags: [cluster_host]
 
@@ -120,14 +145,20 @@
   when: target == "cluster"
   tags: [cluster_host]
 
-- name: Configuration directories are deleted
+# To debug package installation, comment this out so review temporary interim
+# files.
+- name: Configuration directories and files are deleted
   file:
     path: "{{ target_voltha_home }}/{{ item }}"
     state: absent
   with_items:
     - docker-py
     - netifaces
-    - deb_files
+    - sort_packages.sh
+    - sort_packages.py
+    - install_packages.sh
+    - deb_files1
+    - deb_files2
   when: target == "cluster"
   tags: [cluster_host]
 
diff --git a/install/ansible/roles/installer/tasks/main.yml b/install/ansible/roles/installer/tasks/main.yml
index 0b1666e..52ccaf4 100644
--- a/install/ansible/roles/installer/tasks/main.yml
+++ b/install/ansible/roles/installer/tasks/main.yml
@@ -26,6 +26,9 @@
     - install/voltha-swarm-stop.sh
     - install/get-logs.sh
     - install/get-host-logs.sh
+    - install/sort_packages.sh
+    - install/sort_packages.py
+    - install/install_packages.sh
     - install/ansible
     - compose
     - consul_config/basic.json
@@ -43,10 +46,15 @@
     dest: /home/vinstall
   when: file.stat.exists
 
-- name: The installer is made executable
+- name: The installer scripts are made executable
   file:
-    path: /home/vinstall/installer.sh
+    path: "/home/vinstall/{{ item }}"
     mode: 0744
+  with_items:
+    - installer.sh
+    - sort_packages.sh
+    - sort_packages.py
+    - install_packages.sh
   tags: [installer]
 
 - name: Python docker-py {{ docker_py_version }} package source is available
diff --git a/install/install_packages.sh b/install/install_packages.sh
new file mode 100644
index 0000000..b439c2c
--- /dev/null
+++ b/install/install_packages.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+pushd /home/voltha
+
+# Find all non-dpendency packages
+./sort_packages.sh
+
+# Split the package lists into those that have dependencies and those that don't
+mv deb_files{,2}
+mkdir deb_files1
+
+# Move all no-dependency packages into the phase 1 directory
+for i in `cat sortedDebs.txt`
+do
+	mv deb_files2/$i deb_files1
+done
+
+
+# Now install the phase 1 packages
+
+sudo dpkg -R -i deb_files1 2>&1 > install.log
+sudo apt-get -f install 2>&1 >> install.log
+sudo dpkg -R -i deb_files2 2>&1 >> install.log
+sudo apt-get -f install 2>&1 >> install.log
+
+rm -f sortedDebs.txt
+
+popd
+exit 0
diff --git a/install/sort_packages.py b/install/sort_packages.py
new file mode 100755
index 0000000..47bcbd6
--- /dev/null
+++ b/install/sort_packages.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+
+# Load the deb_info.txt file into a dictionary for further processing.
+deps = dict()
+pkgList = list()
+sort_list = list()
+
+with open("deb_info.txt") as f:
+    for line in f:
+        line = line.rstrip("\n")
+	linfo=line.split(":")
+	pkgList.append(linfo[0])
+	deps[linfo[0]]={}
+	deps[linfo[0]]["deb_file"] = linfo[1]
+	deps[linfo[0]]["deps"] = linfo[2].split(",")
+
+
+# First extract all packages that don't have any dependencies
+# at all with the current set of packages
+for key in deps:
+    hasDep=False
+    #print(key, " has dependencies ", deps[key]["deps"])
+    for dep in deps[key]["deps"]:
+        if dep in pkgList:
+            hasDep=True
+    if hasDep == False:
+	#print(key, " has no dependencies")
+	sort_list.append(key)
+	pkgList.remove(key)
+
+for pkg in sort_list:
+    print(deps[pkg]["deb_file"])
+
+exit(0)
+
+# The rest is for future layering of updates and
+# isn't currently used.
+
+# Now scan iterate over the remaining items and
+# add them to the sort_list if they have their
+# dependencies satisfied in the sort list.
+# Continue until the pkgList is empty
+lastLen = 0
+while len(pkgList)  > 0:
+    p = pkgList
+    curLen = len(pkgList)
+    if lastLen == curLen:
+        for pkg in p:
+	    sort_list.append(pkg)
+	    pkgList.remove(pkg)
+    else:
+        lastLen = curLen
+    for pkg in p:
+        missingDep=False
+        for dep in deps[pkg]["deps"]:
+            if dep not in sort_list and dep in pkgList:
+                missingDep=True
+        if missingDep == False:
+	    sort_list.append(pkg)
+	    pkgList.remove(pkg)
+    
+# Now write the packages out in the sorted order
+# this should ensure that dependent packages are
+# installed first.
+for pkg in sort_list:
+    print(deps[pkg]["deb_file"])
diff --git a/install/sort_packages.sh b/install/sort_packages.sh
new file mode 100755
index 0000000..b2d8dd8
--- /dev/null
+++ b/install/sort_packages.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+debDir="deb_files"
+
+rm -f deb_info.txt
+rm -f debFiles.txt
+rm -f sortedDebs.txt
+
+# Create the paackage information file for further processing by Python
+ls $debDir/*.deb | sed -e 's~deb_files/~~' > debFiles.txt
+
+
+for i in `cat debFiles.txt`
+do
+	pkgName=""
+	deps=""
+	pkgName=`dpkg -I $debDir/$i | egrep "^[ ]*Package:" | sed -e 's/Package://' | sed -e 's/\([ ]\+\)\|\([ ]\+$\)//'`
+	deps=`dpkg -I $debDir/$i | grep Depends: | sed -e 's/Depends://' | sed -e 's/\([ ]\+\)\|\([ ]\+$\)//'`
+	deps=`echo $deps | sed -e 's/|/,/g' | sed -e 's/([^)]\+)//g' | sed -e 's/:any//g' | sed -e 's/,//g'`
+	deps=`echo $deps | sed -e 's/[ ]\+/ /g' |  sed -e 's/\(^[ ]\+\)\|\([ ]\+$\)//' | sed -e 's/ /,/g'`
+	#deps=`echo $deps | sed -e 's/^\(.\)/"\1/' | sed -e 's/\(.\)$/\1"/' | sed -s 's/,/","/g'`
+	echo "${pkgName}:${i}:${deps}" >> deb_info.txt
+done
+rm -f debFiles.txt
+
+# Now launch the python scrip that sorts the files based on the dependencies.
+./sort_packages.py > sortedDebs.txt
+
+rm -f deb_info.txt