CORD-1000 Build and publish XOS images on corddev

Change-Id: I6491b43e518abb8a56aec98b5a71e8d293fc7ef9
diff --git a/build-images-playbook.yml b/build-images-playbook.yml
new file mode 100644
index 0000000..baea468
--- /dev/null
+++ b/build-images-playbook.yml
@@ -0,0 +1,7 @@
+---
+# build-images-playbook.yml
+
+- name: Create XOS docker images
+  hosts: localhost
+  roles:
+    - build-images
diff --git a/build-xos-playbook.yml b/build-xos-playbook.yml
new file mode 100644
index 0000000..d097b74
--- /dev/null
+++ b/build-xos-playbook.yml
@@ -0,0 +1,14 @@
+---
+# build-xos-playbook.yml
+
+- name: Include vars
+  hosts: localhost
+  tasks:
+    - name: Include variables
+      include_vars: "{{ item }}"
+      with_items:
+        - "group_vars/all"
+        - "../../build/platform-install/profile_manifests/{{ cord_profile }}.yml"
+        - "../../build/platform-install/profile_manifests/local_vars.yml"
+
+- include: ../../orchestration/xos/build-images-playbook.yml
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..d198080
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,51 @@
+import org.yaml.snakeyaml.Yaml
+
+ext {
+
+    // Deployment target config file (yaml format); this can be overwritten from the command line
+    // using the -PdeployConfig=<file-path> syntax.
+    deployConfig = project.hasProperty('deployConfig') ? project.getProperty('deployConfig') : './config/default.yml'
+
+    println "Using deployment config: $deployConfig"
+    File configFile = new File(deployConfig)
+    def yaml = new Yaml()
+    config = yaml.load(configFile.newReader())
+
+    // Upstream registry to simplify filling out the comps table below
+    upstreamReg = project.hasProperty('upstreamReg') ? project.getProperty('upstreamReg') : 'docker.io'
+
+    // Target registry to be used to publish docker images needed for deployment
+    targetReg = project.hasProperty('targetReg')
+        ? project.getProperty('targetReg')
+        : config.docker && config.docker.registry
+            ? config.docker.registry
+            : config.headnode.ip
+                ? config.headnode.ip + ":5000"
+                : 'localhost:5000'
+
+    // The tag used to tag the docker images push to the target registry
+    targetTag = project.hasProperty('targetTag')
+        ? project.getProperty('targetTag')
+        : config.docker && config.docker.imageVersion
+            ? config.docker.imageVersion
+            : 'candidate'
+}
+
+task buildImages(type: Exec) {
+  executable = "ansible-playbook"
+  args = [
+    "--extra-vars", "@../../build/genconfig/config.yml",
+    "--extra-vars", "build_docker_tag="+targetTag,
+    "--extra-vars", "cord_dir=../..",
+    "build-xos-playbook.yml" ]
+}
+
+task publish(type: Exec) {
+  executable = "ansible-playbook"
+  args = [ "-i", "../../build/genconfig/cord-inv",
+    "--extra-vars", "@../../build/genconfig/config.yml",
+    "--extra-vars", "build_docker_tag="+targetTag,
+    "--extra-vars", "deploy_docker_tag="+targetTag,
+    "--extra-vars", "deploy_docker_registry="+targetReg,
+    "publish-xos-playbook.yml" ]
+}
diff --git a/containers/xos/Dockerfile.client b/containers/xos/Dockerfile.client
index 96e8ca6..3bba5c5 100644
--- a/containers/xos/Dockerfile.client
+++ b/containers/xos/Dockerfile.client
@@ -1,4 +1,4 @@
-FROM xosproject/xos-base
+FROM xosproject/xos-base:candidate
 
 ARG XOS_GIT_COMMIT_HASH=unknown
 ARG XOS_GIT_COMMIT_DATE=unknown
@@ -6,10 +6,6 @@
 LABEL XOS_GIT_COMMIT_HASH=$XOS_GIT_COMMIT_HASH
 LABEL XOS_GIT_COMMIT_DATE=$XOS_GIT_COMMIT_DATE
 
-# Include certificates from Openstack
-ADD containers/xos/local_certs.crt /usr/local/share/ca-certificates/local_certs.crt
-RUN update-ca-certificates
-
 # Install XOS client
 ADD xos/xos_client /tmp/xos_client
 
diff --git a/containers/xos/Dockerfile.devel b/containers/xos/Dockerfile.devel
index c666792..1062756 100644
--- a/containers/xos/Dockerfile.devel
+++ b/containers/xos/Dockerfile.devel
@@ -6,10 +6,6 @@
 LABEL XOS_GIT_COMMIT_HASH=$XOS_GIT_COMMIT_HASH
 LABEL XOS_GIT_COMMIT_DATE=$XOS_GIT_COMMIT_DATE
 
-# Include certificates from Openstack
-ADD containers/xos/local_certs.crt /usr/local/share/ca-certificates/local_certs.crt
-RUN update-ca-certificates
-
 # Install XOS
 ADD xos /opt/xos
 
@@ -23,4 +19,3 @@
 
 # Define working directory
 WORKDIR /opt/xos
-
diff --git a/containers/xos/Dockerfile.synchronizer-base b/containers/xos/Dockerfile.synchronizer-base
index 38c1fa4..c550c77 100644
--- a/containers/xos/Dockerfile.synchronizer-base
+++ b/containers/xos/Dockerfile.synchronizer-base
@@ -1,4 +1,4 @@
-FROM xosproject/xos-client
+FROM xosproject/xos-client:candidate
 
 ADD xos/synchronizers/new_base /opt/xos/synchronizers/new_base
 ADD xos/xos/config.py /opt/xos/xos/config.py
diff --git a/containers/xos/Dockerfile.test b/containers/xos/Dockerfile.test
index 3d74883..2df13a6 100644
--- a/containers/xos/Dockerfile.test
+++ b/containers/xos/Dockerfile.test
@@ -1,4 +1,4 @@
-FROM xosproject/xos
+FROM xosproject/xos:candidate
 
 # install nodejs
 COPY containers/xos/nodesource.gpg.key /tmp/nodesource.gpg.key
@@ -17,4 +17,3 @@
 RUN pip install selenium
 
 RUN npm install -g phantomjs
-
diff --git a/containers/xos/Dockerfile.xos b/containers/xos/Dockerfile.xos
new file mode 100644
index 0000000..4e311bc
--- /dev/null
+++ b/containers/xos/Dockerfile.xos
@@ -0,0 +1,21 @@
+FROM xosproject/xos-base:candidate
+
+ARG XOS_GIT_COMMIT_HASH=unknown
+ARG XOS_GIT_COMMIT_DATE=unknown
+
+LABEL XOS_GIT_COMMIT_HASH=$XOS_GIT_COMMIT_HASH
+LABEL XOS_GIT_COMMIT_DATE=$XOS_GIT_COMMIT_DATE
+
+# Install XOS
+ADD xos /opt/xos
+
+RUN chmod +x /opt/xos/tools/xos-manage \
+ && mkdir -p /opt/cord_profile /opt/xos_services /opt/xos_libraries \
+ && sync \
+ && /opt/xos/tools/xos-manage genkeys
+
+# Set environment variables
+ENV HOME /root
+
+# Define working directory
+WORKDIR /opt/xos
diff --git a/group_vars/all b/group_vars/all
new file mode 100644
index 0000000..876bee0
--- /dev/null
+++ b/group_vars/all
@@ -0,0 +1,70 @@
+---
+# group_vars/all
+
+# Defaults for XOS container build and publish roles.
+# Can be overridden by variables in the profile manifest.
+
+cord_dir: "{{ ansible_user_dir + '/cord' }}"
+
+chameleon_dirs:
+  - "{{ cord_dir }}/orchestration/xos/containers/chameleon/tmp.chameleon"
+  - "{{ cord_dir }}/orchestration/xos/containers/xos/tmp.chameleon"
+
+docker_images:
+  - name: "xosproject/xos-base"
+    path: "{{ cord_dir }}/orchestration/xos/containers/xos"
+    dockerfile: "Dockerfile.base"
+    pull: True
+    publish: False
+  - name: "xosproject/xos"
+    path: "{{ cord_dir }}/orchestration/xos"
+    dockerfile: "containers/xos/Dockerfile.xos"
+    pull: False
+    publish: True
+  - name: "xosproject/chameleon"
+    path: "{{ cord_dir }}/orchestration/xos/containers/chameleon"
+    dockerfile: "Dockerfile.chameleon"
+    pull: False
+    publish: True
+  - name: "xosproject/xos-client"
+    path: "{{ cord_dir }}/orchestration/xos"
+    dockerfile: "containers/xos/Dockerfile.client"
+    pull: False
+    publish: True
+  - name: "xosproject/xos-synchronizer-base"
+    path: "{{ cord_dir }}/orchestration/xos"
+    dockerfile: "containers/xos/Dockerfile.synchronizer-base"
+    pull: False
+    publish: True
+  - name: "xosproject/xos-rest-gw"
+    path: "{{ cord_dir }}/orchestration/xos-rest-gw"
+    dockerfile: "Dockerfile"
+    pull: False
+    publish: True
+  - name: "xosproject/xos-gui"
+    path: "{{ cord_dir }}/orchestration/xos-gui"
+    dockerfile: "Dockerfile"
+    pull: False
+    publish: True
+  - name: "xosproject/xos-gui-extension-builder"
+    path: "{{ cord_dir }}/orchestration/xos-gui/"
+    dockerfile: "Dockerfile.xos-gui-extension-builder"
+    pull: False
+    publish: False
+
+build_optional_images: False
+
+docker_optional_images:
+  - name: "xosprojext/xos-test"
+    dockerfile: "Dockerfile.test"
+    pull: False
+    publish: False
+
+build_docker_tag: "candidate"
+
+misc_docker_images:
+  - "node:argon"
+
+enabled_gui_extensions:
+  - name: sample
+    path: orchestration/xos-sample-gui-extension
diff --git a/publish-images-playbook.yml b/publish-images-playbook.yml
new file mode 100644
index 0000000..98bf874
--- /dev/null
+++ b/publish-images-playbook.yml
@@ -0,0 +1,7 @@
+---
+# publish-xos-playbook.yml
+
+- name: Publish XOS docker images
+  hosts: localhost
+  roles:
+    - publish-images
diff --git a/publish-xos-playbook.yml b/publish-xos-playbook.yml
new file mode 100644
index 0000000..434e3ed
--- /dev/null
+++ b/publish-xos-playbook.yml
@@ -0,0 +1,14 @@
+---
+# publish-xos-playbook.yml
+
+- name: Include vars
+  hosts: localhost
+  tasks:
+    - name: Include variables
+      include_vars: "{{ item }}"
+      with_items:
+        - "group_vars/all"
+        - "../../build/platform-install/profile_manifests/{{ cord_profile }}.yml"
+        - "../../build/platform-install/profile_manifests/local_vars.yml"
+
+- include: ../../orchestration/xos/publish-images-playbook.yml
diff --git a/pull-images-playbook.yml b/pull-images-playbook.yml
new file mode 100644
index 0000000..845fe5a
--- /dev/null
+++ b/pull-images-playbook.yml
@@ -0,0 +1,7 @@
+---
+# pull-images-playbook.yml
+
+- name: Create XOS docker images
+  hosts: localhost
+  roles:
+    - pull-images
diff --git a/pull-xos-playbook.yml b/pull-xos-playbook.yml
new file mode 100644
index 0000000..f09ed2d
--- /dev/null
+++ b/pull-xos-playbook.yml
@@ -0,0 +1,14 @@
+---
+# pull-xos-playbook.yml
+
+- name: Include vars
+  hosts: localhost
+  tasks:
+    - name: Include variables
+      include_vars: "{{ item }}"
+      with_items:
+        - "group_vars/all"
+        - "../../build/platform-install/profile_manifests/{{ cord_profile }}.yml"
+        - "../../build/platform-install/profile_manifests/local_vars.yml"
+
+- include: ../../orchestration/xos/pull-images-playbook.yml
diff --git a/roles/build-images/tasks/main.yml b/roles/build-images/tasks/main.yml
new file mode 100644
index 0000000..6563ab2
--- /dev/null
+++ b/roles/build-images/tasks/main.yml
@@ -0,0 +1,43 @@
+---
+# build-images/tasks/main.yml
+
+- name: Clean up chameleon temp directory
+  file:
+    path: "{{ cord_dir }}/orchestration/xos/containers/chameleon/tmp.chameleon"
+    state: absent
+  with_items: "{{ chameleon_dirs }}"
+
+- name: Populate chameleon temp directory
+  shell: cp -a "{{ cord_dir }}/component/chameleon" "{{ item }}"
+  with_items: "{{ chameleon_dirs }}"
+  tags:
+    - skip_ansible_lint # docker can't access files outside of build context, so we must copy
+
+# If an image was previously pulled it won't get built
+- name: Build images
+  docker_image:
+    name: "{{ item.name }}"
+    path: "{{ item.path }}"
+    tag: "{{ build_docker_tag }}"
+    dockerfile: "{{ item.dockerfile }}"
+    pull: False
+  with_items: "{{ docker_images }}"
+
+- name: Build optional images
+  docker_image:
+    name: "{{ item.name }}"
+    path: "{{ item.path }}"
+    tag: "{{ build_docker_tag }}"
+    dockerfile: "{{ item.dockerfile }}"
+    pull: False
+  with_items: "{{ docker_optional_images }}"
+  when: build_optional_images
+
+# Build extensions images
+- name: Build xos-gui-extensions docker images
+  docker_image:
+    name: "xosproject/gui-extension-{{ item.name }}"
+    path: "{{ cord_dir }}/{{ item.path }}"
+    tag: "{{ build_docker_tag }}"
+    pull: False
+  with_items: "{{ enabled_gui_extensions }}"
diff --git a/roles/publish-images/tasks/main.yml b/roles/publish-images/tasks/main.yml
new file mode 100644
index 0000000..ca22035
--- /dev/null
+++ b/roles/publish-images/tasks/main.yml
@@ -0,0 +1,45 @@
+---
+# publish-xos-docker-images/tasks/main.yml
+
+# Remove the old local images to force them to be re-pushed
+- name: Remove old local XOS images
+  docker_image:
+    name: "{{ deploy_docker_registry }}/{{ item.name }}:{{ deploy_docker_tag }}"
+    state: absent
+  with_items: "{{ docker_images | selectattr('publish') | list }}"
+
+- name: Tag and push locally built images to docker registry
+  docker_image:
+    name: "{{ item.name }}:{{ deploy_docker_tag }}"
+    repository: "{{ deploy_docker_registry }}/{{ item.name }}:{{ deploy_docker_tag }}"
+    push: True
+  with_items: "{{ docker_images | selectattr('publish') | list }}"
+
+# Remove the old local images to force them to be re-pushed
+- name: Remove old local XOS GUI extension images
+  docker_image:
+    name: "{{ deploy_docker_registry }}/xosproject/gui-extension-{{ item.name }}:{{ deploy_docker_tag }}"
+    state: absent
+  with_items: "{{ enabled_gui_extensions }}"
+
+- name: Tag and push locally built images to docker registry
+  docker_image:
+    name: "xosproject/gui-extension-{{ item.name }}:{{ deploy_docker_tag }}"
+    repository: "{{ deploy_docker_registry }}/xosproject/gui-extension-{{ item.name }}:{{ deploy_docker_tag }}"
+    push: True
+  with_items: "{{ enabled_gui_extensions }}"
+
+# Remove the old local images to force them to be re-pushed
+- name: Remove old local miscellaneous images
+  docker_image:
+    name: "{{ deploy_docker_registry }}/{{ item }}"
+    state: absent
+  with_items: "{{ misc_docker_images }}"
+
+# Just needed for onboarding, will go away
+- name: Tag and push miscellaneous images
+  docker_image:
+    name: "{{ item }}"
+    repository: "{{ deploy_docker_registry }}/{{ item }}"
+    push: True
+  with_items: "{{ misc_docker_images }}"
diff --git a/roles/pull-images/tasks/main.yml b/roles/pull-images/tasks/main.yml
new file mode 100644
index 0000000..84d1c1f
--- /dev/null
+++ b/roles/pull-images/tasks/main.yml
@@ -0,0 +1,8 @@
+---
+# pull-images/tasks/main.yml
+
+- name: Pull latest versions of images if not present
+  docker_image:
+    name: "{{ item.name }}"
+    repository: "{{ item.name }}:{{ build_docker_tag }}"
+  with_items: "{{ docker_images | selectattr('pull') | list }}"