CORD-1000 Build and publish XOS images on corddev

Change-Id: I10f9a41220ac42e412b0fb90d574d17556c2c4e8
diff --git a/cord-profile-playbook.yml b/cord-profile-playbook.yml
new file mode 100644
index 0000000..7e7d9df
--- /dev/null
+++ b/cord-profile-playbook.yml
@@ -0,0 +1,16 @@
+---
+# cord-profile-playbook.yml
+
+- name: Include vars
+  hosts: all
+  tasks:
+    - name: Include variables
+      include_vars: "{{ item }}"
+      with_items:
+        - "profile_manifests/{{ cord_profile }}.yml"
+        - profile_manifests/local_vars.yml
+
+- name: Create CORD profile and copy Glance images
+  hosts: head
+  roles:
+    - cord-profile
diff --git a/deploy-xos-playbook.retry b/deploy-xos-playbook.retry
deleted file mode 100644
index c7fd6be..0000000
--- a/deploy-xos-playbook.retry
+++ /dev/null
@@ -1 +0,0 @@
-mockecordbs_xos_bootstrap_ui_1
diff --git a/deploy-xos-playbook.yml b/deploy-xos-playbook.yml
index 47559f9..f9cb4cf 100644
--- a/deploy-xos-playbook.yml
+++ b/deploy-xos-playbook.yml
@@ -1,6 +1,9 @@
 ---
 # deploy-xos-playbook.yml
 
+# This playbook is used for development.  It walks through CORD's
+# fetch -> build -> deploy container pipeline for XOS.
+
 - name: Include vars
   hosts: all
   tasks:
@@ -13,43 +16,17 @@
 # for docker, docker-compose
 - include: devel-tools-playbook.yml
 
-# setup PKI when needed for development
-- name: Create Root CA, Intermediate CA, Server certs
-  hosts: localhost
-  connection: local
-  roles:
-    - { role: pki-root-ca,         when: needs_pki_install is defined and needs_pki_install }
-    - { role: pki-intermediate-ca, when: needs_pki_install is defined and needs_pki_install }
-    - { role: pki-cert,            when: needs_pki_install is defined and needs_pki_install }
+# pull / build base XOS images
+- include: ../../orchestration/xos/pull-xos-playbook.yml
+- include: ../../orchestration/xos/build-xos-playbook.yml
 
-# install PKI when needed for development
-- name: Install CA certificates
+- include: pki-install-playbook.yml
+
+- include: cord-profile-playbook.yml
+
+- name: Pull other docker images if not present
   hosts: head
   roles:
-    - { role: pki-install,         when: needs_pki_install is defined and needs_pki_install }
+    - pull-xos-docker-images
 
-- name: Create CORD profile, create docker images, bootstrap XOS in docker
-  hosts: head
-  roles:
-    - cord-profile
-    - xos-docker-images
-    - xos-bootstrap
-
-- include: add-bootstrap-containers-playbook.yml
-
-- name: Onboard XOS services
-  hosts: xos_bootstrap_ui
-  connection: docker
-  roles:
-    - xos-onboarding
-
-- include: add-onboard-containers-playbook.yml
-
-- name: Check to see if XOS UI is ready, apply profile config
-  hosts: xos_ui
-  connection: docker
-  roles:
-    - xos-ready
-    - xos-config
-
-- include: deploy-xos-gui-extensions-playbook.yml
+- include: launch-xos-playbook.yml
diff --git a/launch-xos-playbook.yml b/launch-xos-playbook.yml
new file mode 100644
index 0000000..0af98bb
--- /dev/null
+++ b/launch-xos-playbook.yml
@@ -0,0 +1,37 @@
+---
+# launch-xos-playbook.yml
+
+- name: Include vars
+  hosts: all
+  tasks:
+    - name: Include variables
+      include_vars: "{{ item }}"
+      with_items:
+        - "profile_manifests/{{ cord_profile }}.yml"
+        - profile_manifests/local_vars.yml
+
+# for docker, docker-compose
+- include: devel-tools-playbook.yml
+
+- name: Bootstrap XOS in docker
+  hosts: head
+  roles:
+    - xos-bootstrap
+
+- include: add-bootstrap-containers-playbook.yml
+
+- name: Onboard XOS services
+  hosts: xos_bootstrap_ui
+  connection: docker
+  roles:
+    - xos-onboarding
+    - xos-gui-extension-onboard
+
+- include: add-onboard-containers-playbook.yml
+
+- name: Check to see if XOS UI is ready, apply profile config
+  hosts: xos_ui
+  connection: docker
+  roles:
+    - xos-ready
+    - xos-config
diff --git a/roles/cord-profile/defaults/main.yml b/roles/cord-profile/defaults/main.yml
index 029d9e8..166cd56 100644
--- a/roles/cord-profile/defaults/main.yml
+++ b/roles/cord-profile/defaults/main.yml
@@ -5,12 +5,21 @@
 cord_profile_dir: "{{ ansible_user_dir + '/cord_profile' }}"
 pki_dir: "/opt/pki"
 
+deploy_docker_registry: ""
+deploy_docker_tag: "candidate"
+
+# For storing OpenStack images
+image_dir: /opt/images
+
 # used in xos.yaml.j2, if True, other synchronizer container will not be started
 frontend_only: False
 
 # Set to True if you want to copy the admin-openrc.sh openstack config file
 use_openstack: True
 
+# Will be overridden if doing a full pod build
+on_maas: False
+
 # set to True to create the xos_redis container in the bootstrap context
 use_redis: True
 
diff --git a/roles/cord-profile/tasks/main.yml b/roles/cord-profile/tasks/main.yml
index 2e6083f..cbf8b42 100644
--- a/roles/cord-profile/tasks/main.yml
+++ b/roles/cord-profile/tasks/main.yml
@@ -2,6 +2,11 @@
 # cord-profile/tasks/main.yml
 # Constructs a CORD service profile directory and configuration files
 
+- name: Create and copy XOS admin password
+  copy:
+    content: "{{ xos_admin_pass }}"
+    dest: "{{ cord_dir }}/build/platform-install/credentials/{{ xos_admin_user }}"
+
 - name: Create cord_profile directory
   become: yes
   file:
@@ -29,41 +34,45 @@
 
 - name: Copy ssh keys to key_import directory
   copy:
-    remote_src: True # file is local to the remote machine
     src: "{{ item.source_path | expanduser }}"
     dest: "{{ cord_profile_dir }}/key_import/{{ item.name }}"
     mode: 0600
   with_items: "{{ xos_service_sshkeys }}"
 
-- name: Copy over core api key and cert
+- name: Copy cert chain and core api key and cert
   copy:
     src: "{{ pki_dir }}/{{ item }}"
     dest: "{{ cord_profile_dir }}/{{ item }}"
     mode: 0600
+    remote_src: True
   with_items:
     - core_api_key.pem
     - core_api_cert.pem
+    - im_cert_chain.pem
 
-- name: Make Image directory ( outside of profile directory to avoid repeat downloads on sequential runs)
+- name: Make local images directory
+  delegate_to: localhost
   become: yes
   file:
-    path: "{{ cord_dir }}/images"
+    path: "{{ image_dir }}"
     state: directory
     mode: 0755
     owner: "{{ ansible_user_id }}"
     group: "{{ ansible_user_gid }}"
 
 - name: Download Glance VM images
+  when: use_openstack
+  delegate_to: localhost
   get_url:
     url: "{{ item.url }}"
     checksum: "{{ item.checksum }}"
-    dest: "{{ cord_dir }}/images/{{ item.name }}.qcow2"
+    dest: "{{ image_dir }}/{{ item.name }}.qcow2"
   with_items: "{{ xos_images }}"
 
 - name: Copy Glance VM images to profile directory
+  when: use_openstack
   copy:
-    remote_src: True
-    src: "{{ cord_dir }}/images/{{ item.name }}.qcow2"
+    src: "{{ image_dir }}/{{ item.name }}.qcow2"
     dest: "{{ cord_profile_dir }}/images/{{ item.name }}.qcow2"
   with_items: "{{ xos_images }}"
 
@@ -93,6 +102,9 @@
     - gateway-config.yml
     - style.config.js
     - app.config.js
+    - Dockerfile.xos
+    - xos-gui-extensions-onboard.yml
+    - xos-gui-extensions.yml
 
 - name: Create profile specific templated TOSCA config files
   template:
@@ -106,17 +118,26 @@
     dest: "{{ cord_profile_dir }}/{{ item }}"
   with_items: "{{ xos_other_templates }}"
 
-- name: Copy admin_openrc.sh
-  when: use_openstack
+- name: Copy node key
+  when: not on_maas and use_openstack
   copy:
-    remote_src: True
-    src: "{{ ansible_user_dir }}/admin-openrc.sh"
-    dest: "{{ cord_profile_dir }}/admin-openrc.sh"
-
-- name: Copy node_key to cord_profile directory
-  when: use_openstack
-  copy:
-    remote_src: True # file is local to the remote machine
-    src: "{{ ansible_user_dir }}/node_key"
-    dest: "{{ cord_profile_dir }}/node_key"
+    src: "{{ ansible_user_dir }}/.ssh/id_rsa"
+    dest: "{{ item }}/node_key"
+    owner: "{{ ansible_user }}"
     mode: 0600
+  with_items:
+    - "{{ ansible_user_dir }}"
+    - "{{ cord_profile_dir }}"
+
+- name: Copy node key (MaaS)
+  when: on_maas and use_openstack
+  become: yes
+  copy:
+    src: "{{ maas_node_key }}"
+    dest: "{{ item }}/node_key"
+    owner: "{{ ansible_user }}"
+    mode: 0600
+    remote_src: True
+  with_items:
+    - "{{ ansible_user_dir }}"
+    - "{{ cord_profile_dir }}"
diff --git a/roles/cord-profile/templates/Dockerfile.xos.j2 b/roles/cord-profile/templates/Dockerfile.xos.j2
new file mode 100644
index 0000000..a8bfc2a
--- /dev/null
+++ b/roles/cord-profile/templates/Dockerfile.xos.j2
@@ -0,0 +1,11 @@
+FROM {{ deploy_docker_registry }}xosproject/xos:{{ deploy_docker_tag }}
+
+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
+
+# Include local certificates for onboarding
+ADD im_cert_chain.pem /usr/local/share/ca-certificates/local_certs.crt
+RUN update-ca-certificates
diff --git a/roles/cord-profile/templates/onboard-chameleon.yaml.j2 b/roles/cord-profile/templates/onboard-chameleon.yaml.j2
index e8f88d8..caefaea 100644
--- a/roles/cord-profile/templates/onboard-chameleon.yaml.j2
+++ b/roles/cord-profile/templates/onboard-chameleon.yaml.j2
@@ -11,7 +11,7 @@
       type: tosca.nodes.Component
       properties:
         command: python chameleon/chameleon/main.py -R 9101 -G xos-core:50055
-        image: xosproject/chameleon
+        image: {{ deploy_docker_registry }}xosproject/chameleon:{{ deploy_docker_tag }}
         ports: 9101:9101
 
     chameleon-to-core:
diff --git a/roles/cord-profile/templates/onboard-gui-extensions-store.yaml.j2 b/roles/cord-profile/templates/onboard-gui-extensions-store.yaml.j2
index 0e83718..02cc72c 100644
--- a/roles/cord-profile/templates/onboard-gui-extensions-store.yaml.j2
+++ b/roles/cord-profile/templates/onboard-gui-extensions-store.yaml.j2
@@ -12,7 +12,7 @@
     gui-extensions-store:
       type: tosca.nodes.Component
       properties:
-        image: node:argon
+        image: {{ deploy_docker_registry }}node:argon
         command: /bin/true
 
     /var/www/dist/extensions:
@@ -23,4 +23,4 @@
       requirements:
           - xos:
              node: gui-extensions-store
-             relationship: tosca.relationships.VolumeOfComponent
\ No newline at end of file
+             relationship: tosca.relationships.VolumeOfComponent
diff --git a/roles/cord-profile/templates/onboard-xos-gui.yaml.j2 b/roles/cord-profile/templates/onboard-xos-gui.yaml.j2
index bcaf3c3..877f444 100644
--- a/roles/cord-profile/templates/onboard-xos-gui.yaml.j2
+++ b/roles/cord-profile/templates/onboard-xos-gui.yaml.j2
@@ -12,7 +12,7 @@
     xos-spa-gui:
       type: tosca.nodes.Component
       properties:
-        image: xosproject/xos-gui
+        image: {{ deploy_docker_registry }}xosproject/xos-gui:{{ deploy_docker_tag }}
         ports: 4000:4000
 
     # UI App Config
@@ -57,7 +57,7 @@
           - xos:
              node: xos-spa-gui
              relationship: tosca.relationships.LinkOfComponent
-    
+
     gui-to-gw:
       type: tosca.nodes.ComponentLink
       properties:
@@ -67,4 +67,4 @@
       requirements:
           - xos:
              node: xos-spa-gui
-             relationship: tosca.relationships.LinkOfComponent
\ No newline at end of file
+             relationship: tosca.relationships.LinkOfComponent
diff --git a/roles/cord-profile/templates/onboard-xos-rest-gw.yaml.j2 b/roles/cord-profile/templates/onboard-xos-rest-gw.yaml.j2
index 22d9fc6..503d6b5 100644
--- a/roles/cord-profile/templates/onboard-xos-rest-gw.yaml.j2
+++ b/roles/cord-profile/templates/onboard-xos-rest-gw.yaml.j2
@@ -12,7 +12,7 @@
     xos-rest-gateway:
       type: tosca.nodes.Component
       properties:
-        image: xosproject/xos-rest-gw
+        image: {{ deploy_docker_registry }}xosproject/xos-rest-gw:{{ deploy_docker_tag }}
         command: npm start -- --config gateway-config.yml
         ports: 3000:3000
 
@@ -47,4 +47,4 @@
       requirements:
           - xos:
              node: xos-rest-gateway
-             relationship: tosca.relationships.LinkOfComponent
\ No newline at end of file
+             relationship: tosca.relationships.LinkOfComponent
diff --git a/roles/cord-profile/templates/xos-bootstrap-docker-compose.yaml.j2 b/roles/cord-profile/templates/xos-bootstrap-docker-compose.yaml.j2
index bf79d65..ed24bd5 100644
--- a/roles/cord-profile/templates/xos-bootstrap-docker-compose.yaml.j2
+++ b/roles/cord-profile/templates/xos-bootstrap-docker-compose.yaml.j2
@@ -11,7 +11,7 @@
 
 services:
   xos_db:
-    image: xosproject/xos-postgres
+    image: {{ deploy_docker_registry }}xosproject/xos-postgres:{{ deploy_docker_tag }}
     networks:
 {% for network in xos_docker_networks %}
       - {{ network }}
@@ -21,7 +21,7 @@
 
 {% if use_redis %}
   xos_redis:
-    image: redis
+    image: {{ deploy_docker_registry }}redis:{{ deploy_docker_tag }}
     networks:
 {% for network in xos_docker_networks %}
      - {{ network }}
@@ -34,7 +34,7 @@
 {% endif %}
 
   xos_bootstrap_ui:
-    image: xosproject/xos
+    image: {{ deploy_docker_registry }}xosproject/xos:{{ deploy_docker_tag }}
     command: python /opt/xos/manage.py runserver 0.0.0.0:{{ xos_bootstrap_ui_port }} --insecure --makemigrations
     networks:
 {% for network in xos_docker_networks %}
@@ -69,7 +69,7 @@
         max-file: "5"
 
   xos_synchronizer_onboarding:
-    image: xosproject/xos
+    image: {{ deploy_docker_registry }}xosproject/xos:{{ deploy_docker_tag }}
     command: bash -c "cd /opt/xos/synchronizers/onboarding; ./run.sh"
     networks:
 {% for network in xos_docker_networks %}
@@ -95,4 +95,3 @@
       options:
         max-size: "1000k"
         max-file: "5"
-
diff --git a/roles/cord-profile/templates/xos-gui-extensions-onboard.yml.j2 b/roles/cord-profile/templates/xos-gui-extensions-onboard.yml.j2
new file mode 100644
index 0000000..a46c188
--- /dev/null
+++ b/roles/cord-profile/templates/xos-gui-extensions-onboard.yml.j2
@@ -0,0 +1,28 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Onboard xos-sample-gui-extension
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+
+    # UI Extensions
+{% for ext in enabled_gui_extensions %}
+    gui-extensions-{{ext.name}}:
+      type: tosca.nodes.Component
+      properties:
+        image: {{ deploy_docker_registry }}xosproject/gui-extension-{{ ext.name }}:{{ deploy_docker_tag }}
+        command: npm run build
+
+    gui-extensions-store-{{ ext.name }}:
+      type: tosca.nodes.ComponentVolumeContainer
+      properties:
+          container: gui-extensions-store
+      requirements:
+          - xos:
+             node: gui-extensions-{{ext.name}}
+             relationship: tosca.relationships.VolumeContainerOfComponent
+{% endfor %}
+
diff --git a/roles/cord-profile/templates/xos-gui-extensions.yml.j2 b/roles/cord-profile/templates/xos-gui-extensions.yml.j2
new file mode 100644
index 0000000..6b5be5e
--- /dev/null
+++ b/roles/cord-profile/templates/xos-gui-extensions.yml.j2
@@ -0,0 +1,17 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Persist xos-sample-gui-extension
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+
+    # UI Extension
+{% for ext in enabled_gui_extensions %}
+    {{ext.name}}:
+      type: tosca.nodes.XOSGuiExtension
+      properties:
+        files: /spa/extensions/{{ext.name}}/vendor.js, /spa/extensions/{{ext.name}}/app.js
+{% endfor %}
diff --git a/roles/head-prep/tasks/main.yml b/roles/head-prep/tasks/main.yml
index af2eaf8..c779d8b 100644
--- a/roles/head-prep/tasks/main.yml
+++ b/roles/head-prep/tasks/main.yml
@@ -86,22 +86,3 @@
     src=ansible.cfg
     dest={{ ansible_user_dir }}/.ansible.cfg
     owner={{ ansible_user_id }} mode=0644
-
-- name: Copy node key
-  when: not on_maas
-  copy:
-    src={{ ansible_user_dir }}/.ssh/id_rsa
-    dest={{ ansible_user_dir }}/node_key
-    owner={{ ansible_user }}
-    mode=0600
-    remote_src=True
-
-- name: Copy node key (MaaS)
-  when: on_maas
-  copy:
-    src={{ maas_node_key }}
-    dest={{ ansible_user_dir }}/node_key
-    owner={{ ansible_user }}
-    mode=0600
-    remote_src=True
-
diff --git a/roles/juju-finish/tasks/main.yml b/roles/juju-finish/tasks/main.yml
index 32dfd85..e173e0c 100644
--- a/roles/juju-finish/tasks/main.yml
+++ b/roles/juju-finish/tasks/main.yml
@@ -32,5 +32,7 @@
 - name: Create admin-openrc.sh credentials file
   template:
    src=admin-openrc.sh.j2
-   dest={{ ansible_user_dir }}/admin-openrc.sh
-
+   dest="{{ item }}/admin-openrc.sh"
+  with_items:
+    - "{{ ansible_user_dir }}"
+    - "{{ cord_profile_dir }}"
diff --git a/roles/pull-xos-docker-images/defaults/main.yml b/roles/pull-xos-docker-images/defaults/main.yml
new file mode 100644
index 0000000..bf12830
--- /dev/null
+++ b/roles/pull-xos-docker-images/defaults/main.yml
@@ -0,0 +1 @@
+deploy_docker_tag: candidate
\ No newline at end of file
diff --git a/roles/pull-xos-docker-images/tasks/main.yml b/roles/pull-xos-docker-images/tasks/main.yml
new file mode 100644
index 0000000..d145454
--- /dev/null
+++ b/roles/pull-xos-docker-images/tasks/main.yml
@@ -0,0 +1,12 @@
+---
+# pull-xos-docker-images/tasks/main.yml
+
+- name: Pull latest versions of images if not present
+  docker_image:
+    name: "{{ item }}:latest"
+    repository: "{{ item }}:candidate"
+  with_items:
+    - xosproject/xos-postgres
+    - xosproject/vsg
+    - redis
+
diff --git a/roles/xos-bootstrap/tasks/main.yml b/roles/xos-bootstrap/tasks/main.yml
index d962165..9c503fa 100644
--- a/roles/xos-bootstrap/tasks/main.yml
+++ b/roles/xos-bootstrap/tasks/main.yml
@@ -6,6 +6,16 @@
     name: "{{ item }}"
   with_items: "{{ xos_docker_networks }}"
 
+# Customized version of xosproject/xos with local cert baked in
+# Used by the onboarding synchronizer, soon this will go away
+- name: Build xosproject/xos bootstrap image (temporary, for onboarding)
+  docker_image:
+    name: "xosproject/xos"
+    path: "{{ cord_profile_dir }}"
+    dockerfile: "Dockerfile.xos"
+    pull: False
+    force: True
+
 - name: Start XOS bootstrap containers
   docker_service:
     project_name: "{{ cord_profile | regex_replace('\\W','') }}bs"