Initial commit of the voltha installer. There are several things that
need to be cleaned up but the installer is fully functional in test
mode and creates 3 non-clustered VMs with identical voltha installs
until such time as HA is ready. Once HA is ready, the scripts will be
modified to deploy the full HA cluster.
This update partially addresses Epic VOL-6.

Made changes requested by the reviewers.

Change-Id: I083239e1f349136d2ec1e51e09391da341177076
diff --git a/install/ansible/roles/apt-repository/tasks/debian.yml b/install/ansible/roles/apt-repository/tasks/debian.yml
new file mode 100644
index 0000000..b77a9f6
--- /dev/null
+++ b/install/ansible/roles/apt-repository/tasks/debian.yml
@@ -0,0 +1,45 @@
+- name: The apt-repository is copied

+  copy:

+    src: "{{ cord_home }}/incubator/voltha/install/apt-mirror"

+    dest: /home/vinstall

+    owner: vinstall

+    group: vinstall

+  tags: [apt]

+- name: Nginx is installed

+  apt:

+    name: nginx

+    state: latest

+  tags: [apt]

+

+- name: Nginx config is copied

+  copy:

+    src: "{{ cord_home }}/incubator/voltha/install/nginx-default"

+    dest: /etc/nginx/sites-enabled/default

+  register: copy_result

+  tags: [apt]

+

+- name: nginx is restarted

+  command: service nginx restart

+  when: copy_result|changed

+  tags: [apt]

+

+#- name: NFS is installed TESTING ONLY REMOVE FOR PRODUCTION

+#  apt:

+#    name: nfs-common

+#    state: latest

+#  tags: [apt]

+#

+#- name: Apt repo is mounted TESTING ONLY REMOVE FOR PRODUCTION

+#  mount:

+#    name: /home/vinstall/apt-mirror

+#    src: "{{ mount_host }}:{{ cord_home }}/incubator/voltha/install/apt-mirror"

+#    fstype: nfs

+#    state: mounted

+#  tags: [apt]

+

+- name: Links to the repos are created

+  file:

+    src: /home/vinstall/apt-mirror/mirror/archive.ubuntu.com/ubuntu

+    dest: /var/www/ubuntu

+    state: link

+  tags: [apt]

diff --git a/install/ansible/roles/apt-repository/tasks/main.yml b/install/ansible/roles/apt-repository/tasks/main.yml
new file mode 100644
index 0000000..1495847
--- /dev/null
+++ b/install/ansible/roles/apt-repository/tasks/main.yml
@@ -0,0 +1,5 @@
+- include: debian.yml
+  when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu'
+
+- include: centos.yml
+  when: ansible_distribution == 'CentOS' or ansible_distribution == 'Red Hat Enterprise Linux'
diff --git a/install/ansible/roles/common/defaults/main.yml b/install/ansible/roles/common/defaults/main.yml
new file mode 100644
index 0000000..7be66d2
--- /dev/null
+++ b/install/ansible/roles/common/defaults/main.yml
@@ -0,0 +1,24 @@
+hosts: [
+  { host_ip: "10.100.198.220", host_name: "voltha"},
+]
+
+use_latest_for:
+  - debian-keyring
+  - debian-archive-keyring
+  - python-dev
+  - kafkacat
+  - libssl-dev
+  - libffi-dev
+  - libpcap-dev
+  - libxml2-dev
+  - libxslt1-dev
+  - python-virtualenv
+  - jq
+  - python-nose
+  - python-flake8
+  - python-scapy
+#  - python-libpcap
+
+obsolete_services:
+  - puppet
+  - chef-client
diff --git a/install/ansible/roles/common/files/ssh_config b/install/ansible/roles/common/files/ssh_config
new file mode 100644
index 0000000..990a43d
--- /dev/null
+++ b/install/ansible/roles/common/files/ssh_config
@@ -0,0 +1,3 @@
+Host *
+   StrictHostKeyChecking no
+   UserKnownHostsFile=/dev/null
diff --git a/install/ansible/roles/common/tasks/main.yml b/install/ansible/roles/common/tasks/main.yml
new file mode 100644
index 0000000..8b1c054
--- /dev/null
+++ b/install/ansible/roles/common/tasks/main.yml
@@ -0,0 +1,48 @@
+- name: JQ is present
+  apt:
+    name: jq
+    force: yes
+  tags: [common]
+
+- name: Host is present
+  lineinfile:
+    dest: /etc/hosts
+    regexp: "^{{ item.host_ip }}"
+    line: "{{ item.host_ip }} {{ item.host_name }}"
+  with_items: "{{ hosts }}"
+  tags: [common]
+
+- name: Latest apt packages
+  apt:
+    name: "{{ item }}"
+  with_items: "{{ use_latest_for }}"
+  when: target != "cluster"
+  tags: [common]
+
+- name: Services are not running
+  service:
+    name: "{{ item }}"
+    state: stopped
+  ignore_errors: yes
+  with_items: "{{ obsolete_services }}"
+  tags: [common]
+
+- name: Ensure there is a .ssh directory for /root
+  file:
+    path: "{{ ansible_env['HOME'] }}/.ssh"
+    state: directory
+    owner: root
+    group: root
+
+- name: Ensure known_hosts file is absent
+  file:
+    path: "{{ ansible_env['HOME'] }}/.ssh/known_hosts"
+    state: absent
+
+- name: Disable Known Host Checking
+  copy:
+    src: files/ssh_config
+    dest: "{{ ansible_env['HOME'] }}/.ssh/config"
+    owner: root
+    group: root
+    mode: 0600
diff --git a/install/ansible/roles/docker-compose/tasks/main.yml b/install/ansible/roles/docker-compose/tasks/main.yml
new file mode 100644
index 0000000..4bf56e9
--- /dev/null
+++ b/install/ansible/roles/docker-compose/tasks/main.yml
@@ -0,0 +1,12 @@
+- name: Executable is downloaded
+  get_url:
+    url: https://github.com/docker/compose/releases/download/1.9.0/docker-compose-Linux-x86_64
+    dest: /home/vinstall
+    mode: 0644
+  when: target == "installer"
+- name: Executable is present
+  copy:
+    src: /home/vinstall/docker-compose-Linux-x86_64
+    dest: /usr/local/bin/docker-compose
+    mode: 0755
+  when: target == "cluster"
diff --git a/install/ansible/roles/docker-registry/tasks/debian.yml b/install/ansible/roles/docker-registry/tasks/debian.yml
new file mode 100644
index 0000000..72903ab
--- /dev/null
+++ b/install/ansible/roles/docker-registry/tasks/debian.yml
@@ -0,0 +1,5 @@
+- name: The insecure docker registry is started

+  command: docker run -d -p 5000:5000 --name registry registry:2

+  register: result

+  ignore_errors: true

+  tags: [docker]

diff --git a/install/ansible/roles/docker-registry/tasks/main.yml b/install/ansible/roles/docker-registry/tasks/main.yml
new file mode 100644
index 0000000..1495847
--- /dev/null
+++ b/install/ansible/roles/docker-registry/tasks/main.yml
@@ -0,0 +1,5 @@
+- include: debian.yml
+  when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu'
+
+- include: centos.yml
+  when: ansible_distribution == 'CentOS' or ansible_distribution == 'Red Hat Enterprise Linux'
diff --git a/install/ansible/roles/docker/defaults/main.yml b/install/ansible/roles/docker/defaults/main.yml
new file mode 100644
index 0000000..338d16e
--- /dev/null
+++ b/install/ansible/roles/docker/defaults/main.yml
@@ -0,0 +1,6 @@
+docker_extra: ""
+
+centos_files: [
+  { src: "docker.centos.repo", dest: "/etc/yum.repos.d/docker.repo" },
+  { src: "docker.centos.service", dest: "/lib/systemd/system/docker.service" },
+]
\ No newline at end of file
diff --git a/install/ansible/roles/docker/files/docker.centos.repo b/install/ansible/roles/docker/files/docker.centos.repo
new file mode 100644
index 0000000..b472187
--- /dev/null
+++ b/install/ansible/roles/docker/files/docker.centos.repo
@@ -0,0 +1,6 @@
+[dockerrepo]
+name=Docker Repository
+baseurl=https://yum.dockerproject.org/repo/main/centos/7
+enabled=1
+gpgcheck=1
+gpgkey=https://yum.dockerproject.org/gpg
\ No newline at end of file
diff --git a/install/ansible/roles/docker/files/docker.centos.service b/install/ansible/roles/docker/files/docker.centos.service
new file mode 100644
index 0000000..3bbef84
--- /dev/null
+++ b/install/ansible/roles/docker/files/docker.centos.service
@@ -0,0 +1,17 @@
+[Unit]
+Description=Docker Application Container Engine
+Documentation=https://docs.docker.com
+After=network.target docker.socket
+Requires=docker.socket
+
+[Service]
+EnvironmentFile=-/etc/sysconfig/docker
+Type=notify
+ExecStart=/usr/bin/docker daemon --insecure-registry 10.100.198.200:5000 -H fd://
+MountFlags=slave
+LimitNOFILE=1048576
+LimitNPROC=1048576
+LimitCORE=infinity
+
+[Install]
+WantedBy=multi-user.target
diff --git a/install/ansible/roles/docker/tasks/centos.yml b/install/ansible/roles/docker/tasks/centos.yml
new file mode 100644
index 0000000..a8910d4
--- /dev/null
+++ b/install/ansible/roles/docker/tasks/centos.yml
@@ -0,0 +1,23 @@
+- name: CentOS files are copied
+  copy:
+    src: "{{ item.src }}"
+    dest: "{{ item.dest }}"
+  with_items: centos_files
+  tags: [docker]
+
+- name: CentOS package is installed
+  yum:
+    name: docker-engine
+    state: present
+  tags: [docker]
+
+- name: CentOS Daemon is reloaded
+  command: systemctl daemon-reload
+  tags: [docker]
+
+- name: CentOS service is running
+  service:
+    name: docker
+    state: running
+  tags: [docker]
+
diff --git a/install/ansible/roles/docker/tasks/debian.yml b/install/ansible/roles/docker/tasks/debian.yml
new file mode 100644
index 0000000..081fda9
--- /dev/null
+++ b/install/ansible/roles/docker/tasks/debian.yml
@@ -0,0 +1,91 @@
+- name: Debian add Docker repository and update apt cache

+  apt_repository:

+    repo: deb https://apt.dockerproject.org/repo ubuntu-{{ debian_version }} main

+    update_cache: yes

+    state: present

+  when: target == "installer"

+  tags: [docker]

+

+- name: Debian Docker is present

+  apt:

+    name: docker-engine

+    state: latest

+    force: yes

+  when: target == "installer"

+  tags: [docker]

+

+#- name: Docker deb install file is present

+#  get_url:

+#    url: https://apt.dockerproject.org/repo/pool/main/d/docker-engine/docker-engine_17.05.0~ce-0~ubuntu-xenial_amd64.deb

+#    dest: /home/vinstall

+#    owner: vinstall

+#    group: vinstall

+#  when: target == "installer"

+#  tags: [docker]

+

+#- name: Docker dependencies satisfied

+#  apt:

+#    name: libltdl7

+#    state: latest

+#    force: yes

+#  when: target == "cluster"

+#  tags: [docker]

+

+#- name: Docker install deb file is copied

+#  copy:

+#    src: /home/vinstall/docker-engine_17.05.0~ce-0~ubuntu-xenial_amd64.deb

+#    dest: /home/voltha

+#  when: target == "cluster"

+#  tags: [docker]

+

+#- name: Docker engine is installed

+#  apt:

+#    deb: /home/vinstall/docker-engine_17.05.0~ce-0~ubuntu-xenial_amd64.deb

+#  when: target == "cluster"

+#  tags: [docker]

+

+- name: Debian python-pip is present

+  apt: name=python-pip state=present

+  tags: [docker]

+

+- name: Debian docker-py is present

+  pip:

+    name: docker-py

+    version: 1.6.0

+    state: present

+  when: target == "installer"

+  tags: [docker]

+

+- name: netifaces pip package is present

+  pip:

+    name: netifaces

+    version: 0.10.4

+    state: present

+  when: target == "installer"

+  tags: [docker]

+

+- name: Debian files are present

+  template:

+    src: "{{ docker_cfg }}"

+    dest: "{{ docker_cfg_dest }}"

+  register: copy_result

+  tags: [docker]

+

+- name: Debian Daemon is reloaded

+  command: systemctl daemon-reload

+  when: copy_result|changed and is_systemd is defined

+  tags: [docker]

+

+- name: vagrant user is added to the docker group

+  user:

+    name: "{{ ansible_env['SUDO_USER'] }}"

+    group: docker

+  register: user_result

+  tags: [docker]

+

+- name: Debian Docker service is restarted

+  service:

+    name: docker

+    state: restarted

+  when: copy_result|changed or user_result|changed

+  tags: [docker]

diff --git a/install/ansible/roles/docker/tasks/main.yml b/install/ansible/roles/docker/tasks/main.yml
new file mode 100644
index 0000000..1495847
--- /dev/null
+++ b/install/ansible/roles/docker/tasks/main.yml
@@ -0,0 +1,5 @@
+- include: debian.yml
+  when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu'
+
+- include: centos.yml
+  when: ansible_distribution == 'CentOS' or ansible_distribution == 'Red Hat Enterprise Linux'
diff --git a/install/ansible/roles/docker/templates/docker-swarm-master.service b/install/ansible/roles/docker/templates/docker-swarm-master.service
new file mode 100644
index 0000000..b284d4b
--- /dev/null
+++ b/install/ansible/roles/docker/templates/docker-swarm-master.service
@@ -0,0 +1,21 @@
+[Unit]
+Description=Docker Application Container Engine
+Documentation=https://docs.docker.com
+After=network.target docker.socket
+Requires=docker.socket
+
+[Service]
+Type=notify
+ExecStart=/usr/bin/docker daemon -H fd:// \
+          --insecure-registry 10.100.198.220:5000 \
+          --registry-mirror=http://10.100.198.220:5001 \
+          --cluster-store=consul://{{ ip }}:8500/swarm \
+          --cluster-advertise={{ ip }}:2375 {{ docker_extra }}
+MountFlags=master
+LimitNOFILE=1048576
+LimitNPROC=1048576
+LimitCORE=infinity
+
+[Install]
+WantedBy=multi-user.target
+
diff --git a/install/ansible/roles/docker/templates/docker-swarm-node.service b/install/ansible/roles/docker/templates/docker-swarm-node.service
new file mode 100644
index 0000000..55bcc50
--- /dev/null
+++ b/install/ansible/roles/docker/templates/docker-swarm-node.service
@@ -0,0 +1,23 @@
+[Unit]
+Description=Docker Application Container Engine
+Documentation=https://docs.docker.com
+After=network.target docker.socket
+Requires=docker.socket
+
+[Service]
+Type=notify
+ExecStart=/usr/bin/docker daemon -H fd:// \
+          -H tcp://0.0.0.0:2375 \
+          -H unix:///var/run/docker.sock \
+          --insecure-registry 10.100.198.220:5000 \
+          --registry-mirror=http://10.100.198.220:5001 \
+          --cluster-store=consul://{{ ip }}:8500/swarm \
+          --cluster-advertise={{ ip }}:2375 {{ docker_extra }}
+MountFlags=slave
+LimitNOFILE=1048576
+LimitNPROC=1048576
+LimitCORE=infinity
+
+[Install]
+WantedBy=multi-user.target
+
diff --git a/install/ansible/roles/docker/templates/docker.cfg b/install/ansible/roles/docker/templates/docker.cfg
new file mode 100644
index 0000000..d59db12
--- /dev/null
+++ b/install/ansible/roles/docker/templates/docker.cfg
@@ -0,0 +1 @@
+DOCKER_OPTS="$DOCKER_OPTS --insecure-registry 192.168.121.91:5000 -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --registry-mirror=http://192.168.121.91:5001"
diff --git a/install/ansible/roles/installer/tasks/installer.yml b/install/ansible/roles/installer/tasks/installer.yml
new file mode 100644
index 0000000..5d29235
--- /dev/null
+++ b/install/ansible/roles/installer/tasks/installer.yml
@@ -0,0 +1,49 @@
+- name: Ansible repository is available

+  apt_repository:

+    repo: 'ppa:ansible/ansible'

+  tags: [installer]

+- name: Debian ansible is present

+  apt:

+    name: ansible

+    state: latest

+    force: yes

+  tags: [installer]

+- name: Installer files and directories are copied

+  copy:

+    src: "{{ cord_home }}/incubator/voltha/{{ item }}"

+    dest: /home/vinstall

+    owner: vinstall

+    group: vinstall

+  with_items:

+    - install/installer.sh

+    - install/install.cfg

+    - install/ansible

+    - compose

+    - nginx_config

+  tags: [installer]

+- name: Determine if test mode is active

+  local_action: stat path="{{ cord_home }}/incubator/voltha/install/.test"

+  register: file

+  ignore_errors: True

+- name: Test mode file is copied

+  copy:

+    src: "{{ cord_home }}/incubator/voltha/install/.test"

+    dest: /home/vinstall

+  when: file.stat.exists

+- name: The installer is made executable

+  file:

+    path: /home/vinstall/installer.sh

+    mode: 0744

+  tags: [installer]

+- name: Python docker-py 1.6.0 package source is available

+  command: pip download -d /home/vinstall/docker-py "docker-py==1.6.0"

+  tags: [installer]

+- name: Python netifaces 0.10.4 package source is available

+  command: pip download -d /home/vinstall/netifaces "netifaces==0.10.4"

+  tags: [installer]

+- name: Deb files are saved.

+  command: cp -r /var/cache/apt/archives /home/vinstall

+  tags: [installer]

+- name: Deb file directory is renamed

+  command: mv /home/vinstall/archives /home/vinstall/deb_files

+  tags: [installer]

diff --git a/install/ansible/roles/installer/tasks/main.yml b/install/ansible/roles/installer/tasks/main.yml
new file mode 100644
index 0000000..005734b
--- /dev/null
+++ b/install/ansible/roles/installer/tasks/main.yml
@@ -0,0 +1,2 @@
+- include: installer.yml
+  when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu'
diff --git a/install/ansible/roles/pull-images/tasks/main.yml b/install/ansible/roles/pull-images/tasks/main.yml
new file mode 100644
index 0000000..dde3d78
--- /dev/null
+++ b/install/ansible/roles/pull-images/tasks/main.yml
@@ -0,0 +1,2 @@
+- include: pull.yml
+  when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu'
diff --git a/install/ansible/roles/pull-images/tasks/pull.yml b/install/ansible/roles/pull-images/tasks/pull.yml
new file mode 100644
index 0000000..9b2044d
--- /dev/null
+++ b/install/ansible/roles/pull-images/tasks/pull.yml
@@ -0,0 +1,12 @@
+- name: Docker containers for Voltha are pulled
+  command: docker pull {{ docker_registry }}/{{ item }}
+  with_items: "{{ voltha_containers }}"
+  tags: [pull]
+- name: Docker images are re-tagged to expected names
+  command: docker tag {{ docker_registry }}/{{ item }} {{ item }}
+  with_items: "{{ voltha_containers }}"
+  tags: [pull]
+- name: Old docker image tags are removed
+  command: docker rmi {{ docker_registry }}/{{ item }}
+  with_items: "{{ voltha_containers }}"
+  tags: [pull]
diff --git a/install/ansible/roles/push-images/tasks/main.yml b/install/ansible/roles/push-images/tasks/main.yml
new file mode 100644
index 0000000..8c8d827
--- /dev/null
+++ b/install/ansible/roles/push-images/tasks/main.yml
@@ -0,0 +1,2 @@
+- include: push.yml
+  when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu'
diff --git a/install/ansible/roles/push-images/tasks/push.yml b/install/ansible/roles/push-images/tasks/push.yml
new file mode 100644
index 0000000..88dbc52
--- /dev/null
+++ b/install/ansible/roles/push-images/tasks/push.yml
@@ -0,0 +1,12 @@
+- name: Docker images are re-tagged to registry for push
+  command: docker tag {{ item }} {{ docker_push_registry }}/{{ item }}
+  with_items: "{{ voltha_containers }}"
+  tags: [push]
+- name: Docker containers for Voltha are pushed
+  command: docker push {{ docker_push_registry }}/{{ item }}
+  with_items: "{{ voltha_containers }}"
+  tags: [push]
+- name: Temporary registry push tags are removed
+  command: docker rmi {{ docker_push_registry }}/{{ item }}
+  with_items: "{{ voltha_containers }}"
+  tags: [push]
diff --git a/install/ansible/roles/voltha/tasks/main.yml b/install/ansible/roles/voltha/tasks/main.yml
new file mode 100644
index 0000000..597ecd1
--- /dev/null
+++ b/install/ansible/roles/voltha/tasks/main.yml
@@ -0,0 +1,2 @@
+- include: voltha.yml
+  when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu'
diff --git a/install/ansible/roles/voltha/tasks/voltha.yml b/install/ansible/roles/voltha/tasks/voltha.yml
new file mode 100644
index 0000000..c8cc78d
--- /dev/null
+++ b/install/ansible/roles/voltha/tasks/voltha.yml
@@ -0,0 +1,57 @@
+- name: Required directory exists

+  file:

+    path: /cord/incubator/voltha

+    state: directory

+    owner: voltha

+    group: voltha

+  tags: [voltha]

+

+- name: Required directories are copied

+  copy:

+    src: /home/vinstall/{{ item }}

+    dest: /cord/incubator/voltha

+    owner: voltha

+    group: voltha

+  with_items:

+    - compose

+    - nginx_config

+    - docker-py

+    - netifaces

+    - deb_files

+  tags: [voltha]

+

+- name: Nginx module symlink is present

+  file:

+    dest: /cord/incubator/voltha/nginx_config/modules

+    src: ../../usr/lib/nginx/modules

+    state: link

+    follow: no

+    force: yes

+  tags: [voltha]

+

+- name: Nginx statup script is executable

+  file:

+    path: /cord/incubator/voltha/nginx_config/start_service.sh

+    mode: 0755

+  tags: [voltha]

+

+- name: Dependent software is installed

+  command: dpkg -i /cord/incubator/voltha/deb_files/{{ item }}

+  with_items: "{{ deb_files }}"

+  when: target == "cluster"

+  ignore_errors: true

+  tags: [voltha]

+

+- name: Dependent software is initialized

+  command: apt-get -f install

+  when: target == "cluster"

+  tags: [voltha]

+

+- name: Python packages are installe

+  command: pip install {{ item }} --no-index --find-links file:///cord/incubator/voltha/{{ item }}

+  with_items:

+    - docker-py

+    - netifaces

+  when: target == "cluster"

+  tags: [voltha]

+