CORD-1151
Make cord_dir and cord_profile_dir local to config node
use head_* and config_* prefixes to avoid hardcoding paths
config-side ssh key generation+
fix frontend & mock builds
[build] group in inventory
fix inventory strangeness
raise privs when creating ssh_pki_dir
move admin-openrc.sh.j2 to cord-profile
add copy-cord-playbook.yml, clarify where it runs
fix paths for head_cord_profile_dir with mock/frontend
use /opt/cord_profile/admin-openrc.sh rather than ~/admin-openrc.sh
install pki
make comment in do-enlist-compute-node accurate, set correct interface
remove hardcoded credential path
logging and ssh key fixes

Change-Id: Ie7560c911dce1558e09806c9997884dfbd475e9c
diff --git a/roles/api-tests/defaults/main.yml b/roles/api-tests/defaults/main.yml
index f78a3b2..065a432 100644
--- a/roles/api-tests/defaults/main.yml
+++ b/roles/api-tests/defaults/main.yml
@@ -1,4 +1,5 @@
 ---
 # api-tests/defaults/main.yml
 
-cord_dir: "{{ hostvars['localhost']['ansible_user_dir'] + '/cord' }}"
+config_cord_dir: "{{ ansible_user_dir + '/cord' }}"
+
diff --git a/roles/api-tests/tasks/main.yml b/roles/api-tests/tasks/main.yml
index 843a384..8ea52e6 100644
--- a/roles/api-tests/tasks/main.yml
+++ b/roles/api-tests/tasks/main.yml
@@ -3,7 +3,7 @@
 
 - name: Copy apiary.apib to target location
   copy:
-    src: "{{ cord_dir }}/orchestration/xos/apiary.apib"
+    src: "{{ config_cord_dir }}/orchestration/xos/apiary.apib"
     dest: "/opt/xos/tests/api/apiary.apib"
 
 - name: Run API tests
diff --git a/roles/automation-integration/defaults/main.yml b/roles/automation-integration/defaults/main.yml
index c7af0e3..c41e867 100644
--- a/roles/automation-integration/defaults/main.yml
+++ b/roles/automation-integration/defaults/main.yml
@@ -1,4 +1,7 @@
 ---
 # automation-integration/defaults/main.yml
 
+# paths
+head_cord_dir: "/opt/cord"
+
 cord_in_a_box: False
diff --git a/roles/automation-integration/templates/do-enlist-compute-node.j2 b/roles/automation-integration/templates/do-enlist-compute-node.j2
index 3490c8c..155dcc2 100644
--- a/roles/automation-integration/templates/do-enlist-compute-node.j2
+++ b/roles/automation-integration/templates/do-enlist-compute-node.j2
@@ -18,10 +18,10 @@
 cat $INV >> $LOG
 echo "END INVENTORY_FILE" >> $LOG
 
-echo "cd /opt/cord/build/platform-install; ansible-playbook --private-key=/etc/maas/ansible/id_rsa -u $COMPUTE_USER --extra-vars '@{{ cord_dir }}/build/genconfig/config.yml' -i $INV cord-compute-playbook.yml" >> $LOG
+echo "cd /opt/cord/build/platform-install; ansible-playbook --private-key=/etc/maas/ansible/id_rsa -u $COMPUTE_USER --extra-vars '@{{ head_cord_dir }}/build/genconfig/config.yml' -i $INV cord-compute-maas-playbook.yml" >> $LOG
 
 cd /opt/cord/build/platform-install
-ansible-playbook --private-key=/etc/maas/ansible/id_rsa -u $COMPUTE_USER --extra-vars '@{{ cord_dir }}/build/genconfig/config.yml' -i $INV cord-compute-maas-playbook.yml >> $LOG
+ansible-playbook --private-key=/etc/maas/ansible/id_rsa -u $COMPUTE_USER --extra-vars '@{{ head_cord_dir }}/build/genconfig/config.yml' -i $INV cord-compute-maas-playbook.yml >> $LOG
 
 RESULT=$?
 rm $INV
diff --git a/roles/compute-node-config/defaults/main.yml b/roles/compute-node-config/defaults/main.yml
index 70507cc..dffca62 100644
--- a/roles/compute-node-config/defaults/main.yml
+++ b/roles/compute-node-config/defaults/main.yml
@@ -1,10 +1,14 @@
 ---
 # compute-node-config/defaults/main.yml
 
-cord_profile_dir: "{{ ansible_user_dir + '/cord_profile' }}"
+# location of cord_profile on head node
+head_cord_profile_dir: /opt/cord_profile
+
+# name of the external interface on compute nodes. Should have the ansible_ prefix.
+# `fabric` is default in R-CORD
+compute_external_interface: ansible_fabric
 
 # service configs referenced here are likely located in cord-profile/templates
-
 # used in openstack-compute-vtn.yaml.j2, referencing network in management-net.yaml.j2
 use_management_hosts: False
 vtn_management_host_net_interface: veth3
@@ -12,3 +16,4 @@
 # used in openstack-compute-vtn.yaml.j2, referencing service in fabric.yaml.j2
 use_fabric: False
 
+
diff --git a/roles/compute-node-config/tasks/main.yml b/roles/compute-node-config/tasks/main.yml
index 6500dbb..c592bf7 100644
--- a/roles/compute-node-config/tasks/main.yml
+++ b/roles/compute-node-config/tasks/main.yml
@@ -6,7 +6,7 @@
 - name: Create OpenStack compute node TOSCA
   template:
     src: "{{ item }}.j2"
-    dest: "{{ cord_profile_dir }}/{{ item }}"
+    dest: "{{ head_cord_profile_dir }}/{{ item }}"
     owner: "{{ ansible_user_id }}"
     mode: 0644
   with_items:
diff --git a/roles/compute-node-enable-maas/defaults/main.yml b/roles/compute-node-enable-maas/defaults/main.yml
index de6b9a3..f2b3a99 100644
--- a/roles/compute-node-enable-maas/defaults/main.yml
+++ b/roles/compute-node-enable-maas/defaults/main.yml
@@ -2,7 +2,7 @@
 # compute-node-enable-maas/defaults/main.yml
 
 credentials_dir: "{{ playbook_dir }}/credentials"
-cord_profile_dir: "{{ ansible_user_dir ~ '/cord_profile' }}"
+head_cord_profile_dir: "/opt/cord_profile"
 
 xos_admin_user: "xosadmin@opencord.org"
 xos_admin_pass: "{{ lookup('password', credentials_dir ~ '/xosadmin@opencord.org chars=ascii_letters,digits') }}"
diff --git a/roles/compute-node-enable-maas/tasks/main.yml b/roles/compute-node-enable-maas/tasks/main.yml
index 9892aa1..0c1fd39 100644
--- a/roles/compute-node-enable-maas/tasks/main.yml
+++ b/roles/compute-node-enable-maas/tasks/main.yml
@@ -1,9 +1,9 @@
 ---
 # compute-node-enable-maas/tasks/main.yml
 
-- name: Fetch generated nodes.yaml file
+- name: Fetch generated compute node onboarding TOSCA files
   fetch:
-    src: "{{ cord_profile_dir + '/' + item }}"
+    src: "{{ head_cord_profile_dir + '/' + item }}"
     dest: "/tmp/{{ item }}"
     flat: yes
     fail_on_missing: yes
diff --git a/roles/compute-node-enable/defaults/main.yml b/roles/compute-node-enable/defaults/main.yml
index a3a1e7c..6f52840 100644
--- a/roles/compute-node-enable/defaults/main.yml
+++ b/roles/compute-node-enable/defaults/main.yml
@@ -1,5 +1,5 @@
 ---
 # compute-node-enable/defaults/main.yml
 
-cord_profile_dir: "{{ ansible_user_dir + '/cord_profile' }}"
+head_cord_profile_dir: "/opt/cord_profile"
 
diff --git a/roles/compute-node-enable/tasks/main.yml b/roles/compute-node-enable/tasks/main.yml
index f746241..60c6651 100644
--- a/roles/compute-node-enable/tasks/main.yml
+++ b/roles/compute-node-enable/tasks/main.yml
@@ -2,7 +2,7 @@
 # compute-node-enable/tasks/main.yml
 
 - name: Load TOSCA to add OpenStack compute nodes
-  command: "python /opt/xos/tosca/run.py {{ xos_admin_user }} {{ cord_profile_dir }}/{{ item }}"
+  command: "python /opt/xos/tosca/run.py {{ xos_admin_user }} {{ head_cord_profile_dir }}/{{ item }}"
   with_items:
     - openstack.yaml
     - openstack-compute.yaml
@@ -14,7 +14,7 @@
     seconds: 20
 
 - name: Load TOSCA to enable VTN on OpenStack compute nodes
-  command: "python /opt/xos/tosca/run.py {{ xos_admin_user }} {{ cord_profile_dir }}/{{ item }}"
+  command: "python /opt/xos/tosca/run.py {{ xos_admin_user }} {{ head_cord_profile_dir }}/{{ item }}"
   with_items:
     - vtn-service.yaml
     - openstack-compute-vtn.yaml
diff --git a/roles/copy-cord/defaults/main.yml b/roles/copy-cord/defaults/main.yml
new file mode 100644
index 0000000..962c8db
--- /dev/null
+++ b/roles/copy-cord/defaults/main.yml
@@ -0,0 +1,5 @@
+---
+# copy-cord/defaults/main.yml
+
+config_cord_dir: "{{ ansible_user_dir + '/cord' }}"
+head_cord_dir: "/opt/cord"
diff --git a/roles/copy-cord/tasks/main.yml b/roles/copy-cord/tasks/main.yml
new file mode 100644
index 0000000..1cf241a
--- /dev/null
+++ b/roles/copy-cord/tasks/main.yml
@@ -0,0 +1,18 @@
+---
+# copy-cord/tasks/main.yml
+
+- name: Copy (sync) the cord directory to head node
+  become: yes
+  synchronize:
+    src: "{{ config_cord_dir }}/"
+    dest: "{{ head_cord_dir }}/"
+
+- name: Set ownership on CORD dir on head node
+  become: yes
+  file:
+    dest: "{{ head_cord_dir }}"
+    state: directory
+    recurse: yes
+    owner: "{{ ansible_user_id }}"
+    group: "{{ ansible_user_gid }}"
+
diff --git a/roles/copy-credentials/defaults/main.yml b/roles/copy-credentials/defaults/main.yml
new file mode 100644
index 0000000..cf19dfd
--- /dev/null
+++ b/roles/copy-credentials/defaults/main.yml
@@ -0,0 +1,4 @@
+---
+# copy-credentials/defaults/main.yml
+
+credentials_dir: "{{ playbook_dir }}/credentials"
diff --git a/roles/copy-credentials/tasks/main.yml b/roles/copy-credentials/tasks/main.yml
new file mode 100644
index 0000000..3d3af3e
--- /dev/null
+++ b/roles/copy-credentials/tasks/main.yml
@@ -0,0 +1,18 @@
+---
+# copy-credentials/tasks/main.yml
+
+- name: Copy (sync) the credentials directory to head node, for MaaS provisioner
+  become: yes
+  synchronize:
+    src: "{{ credentials_dir }}/"
+    dest: "/opt/credentials/"
+
+- name: Set ownership on credentials dir on head node, for MaaS provisioner
+  become: yes
+  file:
+    dest: "/opt/credentials"
+    state: directory
+    recurse: yes
+    owner: "{{ ansible_user_id }}"
+    group: "{{ ansible_user_gid }}"
+
diff --git a/roles/copy-profile/defaults/main.yml b/roles/copy-profile/defaults/main.yml
new file mode 100644
index 0000000..c4f7979
--- /dev/null
+++ b/roles/copy-profile/defaults/main.yml
@@ -0,0 +1,5 @@
+---
+# copy-profile/defaults/main.yml
+
+config_cord_profile_dir: "{{ ansible_user_dir + '/cord_profile' }}"
+head_cord_profile_dir: "/opt/cord_profile"
diff --git a/roles/copy-profile/tasks/main.yml b/roles/copy-profile/tasks/main.yml
new file mode 100644
index 0000000..c206a3f
--- /dev/null
+++ b/roles/copy-profile/tasks/main.yml
@@ -0,0 +1,17 @@
+---
+# copy-profile/tasks/main.yml
+
+- name: Copy (sync) the cord_profile directory structure to head node
+  synchronize:
+    src: "{{ config_cord_profile_dir }}/"
+    dest: "{{ head_cord_profile_dir }}/"
+    delete: yes
+
+- name: Set ownership on cord_profile dir on head node
+  file:
+    dest: "{{ head_cord_profile_dir }}"
+    state: directory
+    recurse: yes
+    owner: "{{ ansible_user_id }}"
+    group: "{{ ansible_user_gid }}"
+
diff --git a/roles/cord-profile/defaults/main.yml b/roles/cord-profile/defaults/main.yml
index 7c25a49..542ac64 100644
--- a/roles/cord-profile/defaults/main.yml
+++ b/roles/cord-profile/defaults/main.yml
@@ -1,16 +1,22 @@
 ---
 # cord-profile/defaults/main.yml
 
-cord_dir: "{{ ansible_user_dir + '/cord' }}"
-cord_profile_dir: "{{ ansible_user_dir + '/cord_profile' }}"
+# where the cord_profile directory is on the config node
+config_cord_profile_dir: "{{ ansible_user_dir + '/cord_profile' }}"
+
 pki_dir: "{{ playbook_dir }}/pki"
+ssh_pki_dir: "{{ playbook_dir }}/ssh_pki"
 credentials_dir: "{{ playbook_dir }}/credentials"
 
-deploy_docker_registry: ""
+# where cord files are copied to on head node
+head_cord_profile_dir: "/opt/cord_profile"
+head_cord_dir: "/opt/cord"
+
+deploy_docker_registry: "" # was: "localhost:5000/"
 deploy_docker_tag: "candidate"
 
 # name of docker image to use in onboarding synchronizer
-xos_docker_image: "xosproject/xos:candidate"
+xos_docker_image: "{{ deploy_docker_registry }}xosproject/xos{{ deploy_docker_tag }}"
 
 # For storing OpenStack images
 image_dir: /opt/images
@@ -42,10 +48,10 @@
 xos_libraries:
   - "ng-xos-lib"
 
-xos_services: []
-xos_service_sshkeys: []
+# name of master ssh key for this pod
+pod_sshkey_name: "headnode"
 
-xos_images: []
+xos_services: []
 
 xos_tosca_config_templates: []
 
@@ -62,6 +68,9 @@
 xos_dir: /opt/xos
 
 # GUI Config [new GUI], used in app.config.js.j2 and style.config.js.j2
+
+enabled_gui_extensions: []
+
 gw_port: 3000
 gui_api_endpoint: "/xosapi/v1"
 gui_websocket: "/"
@@ -94,6 +103,7 @@
 
 site_name: sitename
 site_humanname: "Site HumanName"
+site_suffix: sitename.test
 
 deployment_type: deploymenttype
 
diff --git a/roles/cord-profile/tasks/main.yml b/roles/cord-profile/tasks/main.yml
index 7a5fffb..2edba24 100644
--- a/roles/cord-profile/tasks/main.yml
+++ b/roles/cord-profile/tasks/main.yml
@@ -2,61 +2,57 @@
 # 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:
-    path: "{{ cord_profile_dir }}"
+    path: "{{ config_cord_profile_dir }}"
     state: directory
     mode: 0755
     owner: "{{ ansible_user_id }}"
     group: "{{ ansible_user_gid }}"
 
-- name: Create cord_profile/profile_name, containing profile name
+- name: Create cord_profile/profile_name file containing profile name
   copy:
-    dest: "{{ cord_profile_dir }}/profile_name"
+    dest: "{{ config_cord_profile_dir }}/profile_name"
     content: "{{ cord_profile }}"
     mode: 0644
 
 - name: Create subdirectories inside cord_profile directory
   file:
-    path: "{{ cord_profile_dir }}/{{ item }}"
+    path: "{{ config_cord_profile_dir }}/{{ item }}"
     state: directory
     mode: 0755
   with_items:
     - key_import
-    - onboarding-docker-compose
     - images
 
-# *** This should be revisited. ***
-# Currently the key pair is generated on the head node by the
-# "prep" role in the "maas" repo, invoked during the "deployBase" Gradle task.
-# The keys should probably be generated earlier, in the corddev VM, and copied over.
-# The /opt/credentials directory might be a good place to keep the generated keys.
-#
-# Ensure a keypair exists in case we're not running on MaaS.
-- name: Ensure keypair
-  user:
-    name: "{{ ansible_user_id }}"
-    generate_ssh_key: yes
-
-- name: Copy ssh keys to key_import directory
+- name: Copy ssh private key to node_key file
   copy:
-    # 'expanduser' won't work below, it expands on control machine
-    src: "{{ item.source_path | replace('~', ansible_user_dir, 1) }}"
-    dest: "{{ cord_profile_dir }}/key_import/{{ item.name }}"
+    src: "{{ ssh_pki_dir }}/client_certs/{{ pod_sshkey_name }}_sshkey"
+    dest: "{{ config_cord_profile_dir }}/node_key"
     mode: 0600
     remote_src: True
-  with_items: "{{ xos_service_sshkeys }}"
+
+- name: Copy ssh private key to key_import directory for services that require it
+  copy:
+    src: "{{ ssh_pki_dir }}/client_certs/{{ pod_sshkey_name }}_sshkey"
+    dest: "{{ config_cord_profile_dir }}/key_import/{{ item.keypair }}"
+    mode: 0600
+    remote_src: True
+  with_items: "{{ xos_services | selectattr('keypair', 'defined') | list }}"
+
+- name: Copy ssh public key to key_import directory for services that require it
+  copy:
+    src: "{{ ssh_pki_dir }}/client_certs/{{ pod_sshkey_name }}_sshkey.pub"
+    dest: "{{ config_cord_profile_dir }}/key_import/{{ item.keypair }}.pub"
+    mode: 0644
+    remote_src: True
+  with_items: "{{ xos_services | selectattr('keypair', 'defined') | list }}"
 
 - name: Copy cert chain and core api key and cert
   copy:
     src: "{{ pki_dir }}/{{ item.src }}"
-    dest: "{{ cord_profile_dir }}/{{ item.dest }}"
+    dest: "{{ config_cord_profile_dir }}/{{ item.dest }}"
     mode: 0600
   with_items:
     - src: "{{ site_name }}_im_ca/private/xos-core.{{ site_suffix }}_key.pem"
@@ -66,45 +62,10 @@
     - src: "{{ site_name }}_im_ca/certs/im_cert_chain.pem"
       dest: "im_cert_chain.pem"
 
-- name: Get localhost facts (to get local uid and gid)
-  setup:
-  delegate_to: localhost
-  delegate_facts: True
-
-- name: Make local images directory
-  delegate_to: localhost
-  become: yes
-  file:
-    path: "{{ image_dir }}"
-    state: directory
-    mode: 0755
-    owner: "{{ hostvars['localhost']['ansible_user_id'] }}"
-    group: "{{ hostvars['localhost']['ansible_user_gid'] }}"
-
-- name: Download Glance VM images
-  when: use_openstack
-  delegate_to: localhost
-  get_url:
-    url: "{{ item.url }}"
-    checksum: "{{ item.checksum }}"
-    dest: "{{ image_dir }}/{{ item.name }}.qcow2"
-  with_items: "{{ xos_images }}"
-  register: glance_vm_result
-  until: glance_vm_result|success
-  retries: 5
-  delay: 10
-
-- name: Copy Glance VM images to profile directory
-  when: use_openstack
-  copy:
-    src: "{{ image_dir }}/{{ item.name }}.qcow2"
-    dest: "{{ cord_profile_dir }}/images/{{ item.name }}.qcow2"
-  with_items: "{{ xos_images }}"
-
 - name: Copy over commonly used and utility TOSCA files
   copy:
     src: "{{ item }}"
-    dest: "{{ cord_profile_dir }}/{{ item }}"
+    dest: "{{ config_cord_profile_dir }}/{{ item }}"
   with_items:
     - fixtures.yaml
     - enable-onboarding.yaml
@@ -113,7 +74,7 @@
 - name: Create templated XOS configuration files
   template:
     src: "{{ item }}.j2"
-    dest: "{{ cord_profile_dir }}/{{ item }}"
+    dest: "{{ config_cord_profile_dir }}/{{ item }}"
     mode: 0644
   with_items:
     - xos_common_config
@@ -130,36 +91,21 @@
 - name: Create profile specific templated TOSCA config files
   template:
     src: "{{ item }}.j2"
-    dest: "{{ cord_profile_dir }}/{{ item }}"
+    dest: "{{ config_cord_profile_dir }}/{{ item }}"
   with_items: "{{ xos_tosca_config_templates }}"
 
 - name: Create profile specific templated non-TOSCA files
   template:
     src: "{{ item }}.j2"
-    dest: "{{ cord_profile_dir }}/{{ item }}"
+    dest: "{{ config_cord_profile_dir }}/{{ item }}"
   with_items: "{{ xos_other_templates }}"
 
-- name: Copy node key
-  when: not on_maas and use_openstack
-  copy:
-    src: "{{ ansible_user_dir }}/.ssh/id_rsa"
-    dest: "{{ item }}/node_key"
-    owner: "{{ ansible_user }}"
-    mode: 0600
-    remote_src: True
+- name: Create OpenStack config and TOSCA onboarding
+  when: use_openstack
+  template:
+    src: "{{ item }}.j2"
+    dest: "{{ config_cord_profile_dir }}/{{ item }}"
   with_items:
-    - "{{ ansible_user_dir }}"
-    - "{{ cord_profile_dir }}"
+    - openstack.yaml
+    - admin-openrc.sh
 
-- 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/juju-setup/templates/admin-openrc.sh.j2 b/roles/cord-profile/templates/admin-openrc.sh.j2
similarity index 100%
rename from roles/juju-setup/templates/admin-openrc.sh.j2
rename to roles/cord-profile/templates/admin-openrc.sh.j2
diff --git a/roles/cord-profile/templates/docker-compose.yml.j2 b/roles/cord-profile/templates/docker-compose.yml.j2
index 29fa893..b64e837 100644
--- a/roles/cord-profile/templates/docker-compose.yml.j2
+++ b/roles/cord-profile/templates/docker-compose.yml.j2
@@ -1,7 +1,7 @@
 version: '2'
 
 # XOS docker compose
-# generated by platform-install/roles/cord-profile
+# generated by cord-profile/templates/docker-compose.yml.j2
 
 networks:
 {% for network in xos_docker_networks %}
@@ -94,8 +94,8 @@
       - xos_ws
       - xos_chameleon
     volumes:
-      - {{ cord_profile_dir }}/style.config.js:/var/www/dist/style.config.js
-      - {{ cord_profile_dir }}/app.config.js:/var/www/dist/app.config.js
+      - {{ head_cord_profile_dir }}/style.config.js:/var/www/dist/style.config.js
+      - {{ head_cord_profile_dir }}/app.config.js:/var/www/dist/app.config.js
     volumes_from:
       - gui_extensions_store
     logging:
@@ -171,7 +171,7 @@
       - xos_redis
 {% endif %}
     volumes:
-      - {{ cord_profile_dir }}/gateway-config.yml:/var/www/src/config/gateway-config.yml
+      - {{ head_cord_profile_dir }}/gateway-config.yml:/var/www/src/config/gateway-config.yml
     logging:
       driver: "json-file"
       options:
@@ -204,11 +204,11 @@
       - xos_redis
 {% endif %}
     volumes:
-      - {{ cord_profile_dir }}/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
-      - {{ cord_profile_dir }}/xos_config.yaml:/opt/xos/xos_config.yaml:ro
-      - {{ cord_profile_dir }}:/opt/cord_profile:ro
-      - {{ cord_dir }}/orchestration/xos_libraries/ng-xos-lib:/opt/xos_libraries/ng-xos-lib:ro
-      - {{ cord_profile_dir }}/im_cert_chain.pem:/usr/local/share/ca-certificates/local_certs.crt:ro
+      - {{ head_cord_profile_dir }}/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
+      - {{ head_cord_profile_dir }}/xos_config.yaml:/opt/xos/xos_config.yaml:ro
+      - {{ head_cord_profile_dir }}:/opt/cord_profile:ro
+      - {{ head_cord_dir }}/orchestration/xos_libraries/ng-xos-lib:/opt/xos_libraries/ng-xos-lib:ro
+      - {{ head_cord_profile_dir }}/im_cert_chain.pem:/usr/local/share/ca-certificates/local_certs.crt:ro
     logging:
       driver: "json-file"
       options:
@@ -243,11 +243,11 @@
       - xos_redis
 {% endif %}
     volumes:
-      - {{ cord_profile_dir }}/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
-      - {{ cord_profile_dir }}/xos_config.yaml:/opt/xos/xos_config.yaml:ro
-      - {{ cord_profile_dir }}:/opt/cord_profile:ro
-      - {{ cord_dir }}/orchestration/xos_libraries/ng-xos-lib:/opt/xos_libraries/ng-xos-lib:ro
-      - {{ cord_profile_dir }}/im_cert_chain.pem:/usr/local/share/ca-certificates/local_certs.crt:ro
+      - {{ head_cord_profile_dir }}/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
+      - {{ head_cord_profile_dir }}/xos_config.yaml:/opt/xos/xos_config.yaml:ro
+      - {{ head_cord_profile_dir }}:/opt/cord_profile:ro
+      - {{ head_cord_dir }}/orchestration/xos_libraries/ng-xos-lib:/opt/xos_libraries/ng-xos-lib:ro
+      - {{ head_cord_profile_dir }}/im_cert_chain.pem:/usr/local/share/ca-certificates/local_certs.crt:ro
       - /var/run/docker.sock:/var/run/docker.sock
     logging:
       driver: "json-file"
@@ -280,7 +280,7 @@
 
 {% if not frontend_only %}
 {% for svc in xos_services %}
-{% if svc.synchronizer is defined and svc.synchronizer %}
+{% if svc.synchronizer is not defined or svc.synchronizer %}
   {{ svc.name }}-synchronizer:
     image: {{ deploy_docker_registry }}xosproject/{{ svc.name }}-synchronizer:{{ deploy_docker_tag }}
     networks:
@@ -298,14 +298,14 @@
       - xos_redis:redis
 {% endif %}
     volumes:
-      - {{ cord_profile_dir }}/node_key:/opt/cord_profile/node_key:ro
-      - {{ cord_dir }}/build/platform-install/credentials/xosadmin@opencord.org:/opt/xos/services/{{ svc.name }}/credentials/xosadmin@opencord.org:ro
-      - {{ cord_profile_dir }}/im_cert_chain.pem:/usr/local/share/ca-certificates/local_certs.crt:ro
+      - {{ head_cord_profile_dir }}/node_key:/opt/cord_profile/node_key:ro
+      - /opt/credentials:/opt/xos/services/{{ svc.name }}/credentials:ro
+      - {{ head_cord_profile_dir }}/im_cert_chain.pem:/usr/local/share/ca-certificates/local_certs.crt:ro
 {% if svc.keypair is defined %}
-      - {{ cord_profile_dir }}/key_import/{{ svc.keypair }}:/opt/xos/services/{{ svc.name }}/keys/{{ svc.keypair }}:ro
+      - {{ head_cord_profile_dir }}/key_import/{{ svc.keypair }}:/opt/xos/services/{{ svc.name }}/keys/{{ svc.keypair }}:ro
 {% endif %}
 {% if svc.name == "openstack" %}
-      - {{ cord_profile_dir }}/images:/opt/xos/images:ro
+      - {{ head_cord_profile_dir }}/images:/opt/xos/images:ro
 {% endif %}
     logging:
       driver: "json-file"
diff --git a/roles/cord-profile/templates/xos-bootstrap-docker-compose.yaml.j2 b/roles/cord-profile/templates/xos-bootstrap-docker-compose.yaml.j2
deleted file mode 100644
index 06c20d2..0000000
--- a/roles/cord-profile/templates/xos-bootstrap-docker-compose.yaml.j2
+++ /dev/null
@@ -1,104 +0,0 @@
-version: '2'
-
-# XOS bootstrap docker compose
-# generated by platform-install/roles/cord-profile
-
-networks:
-{% for network in xos_docker_networks %}
-  {{ network }}:
-    external: true
-{% endfor %}
-
-services:
-  xos_db:
-    image: {{ deploy_docker_registry }}xosproject/xos-postgres:{{ deploy_docker_tag }}
-    networks:
-{% for network in xos_docker_networks %}
-      - {{ network }}
-{% endfor %}
-    expose:
-      - "5432"
-
-{% if use_redis %}
-  xos_redis:
-    image: {{ deploy_docker_registry }}redis:{{ deploy_docker_tag }}
-    networks:
-{% for network in xos_docker_networks %}
-     - {{ network }}
-{% endfor %}
-    logging:
-      driver: "json-file"
-      options:
-        max-size: "1000k"
-        max-file: "5"
-{% endif %}
-
-  xos_bootstrap_ui:
-    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 %}
-     - {{ network }}
-{% endfor %}
-    labels:
-      org.xosproject.kind: userinterface
-      org.xosproject.target: bootstrap
-    links:
-      - xos_db
-{% if use_redis %}
-      - xos_redis:redis
-{% endif %}
-    volumes:
-      - .:/opt/cord_profile:ro
-      - ./xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
-{% for service in xos_services %}
-      - {{ cord_dir }}/{{ service.path }}:/opt/xos_services/{{ service.path | basename }}:ro
-{% endfor %}
-{% for library in xos_libraries %}
-      - {{ cord_dir }}/orchestration/xos_libraries/{{ library }}:/opt/xos_libraries/{{ library }}:ro
-{% endfor %}
-{% for volume in xos_docker_volumes %}
-      - {{ volume.host }}:{{ volume.container }}{{ ":rw" if (volume.read_only is defined and not volume.read_only ) else ":ro" }}
-{% endfor %}
-    ports:
-      - "{{ xos_bootstrap_ui_port }}:{{ xos_bootstrap_ui_port }}"
-    logging:
-      driver: "json-file"
-      options:
-        max-size: "1000k"
-        max-file: "5"
-    depends_on:
-      - xos_db
-{% if use_redis %}
-      - xos_redis
-{% endif %}
-
-  xos_synchronizer_onboarding:
-    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 %}
-     - {{ network }}
-{% endfor %}
-    labels:
-      org.xosproject.kind: synchronizer
-      org.xosproject.target: onboarding
-    links:
-      - xos_db
-    volumes:
-      - /var/run/docker.sock:/var/run/docker.sock
-      - ./key_import:/opt/xos/key_import:ro
-      - ./onboarding-docker-compose:/opt/xos/synchronizers/onboarding/docker-compose
-{% for service in xos_services %}
-      - {{ cord_dir }}/{{ service.path }}:/opt/xos_services/{{ service.path | basename }}:ro
-{% endfor %}
-{% for library in xos_libraries %}
-      - {{ cord_dir }}/orchestration/xos_libraries/{{ library }}:/opt/xos_libraries/{{ library }}:ro
-{% endfor %}
-    logging:
-      driver: "json-file"
-      options:
-        max-size: "1000k"
-        max-file: "5"
-    depends_on:
-      - xos_db
diff --git a/roles/cord-profile/templates/xos.yaml.j2 b/roles/cord-profile/templates/xos.yaml.j2
index 4bd792f..553f9b1 100644
--- a/roles/cord-profile/templates/xos.yaml.j2
+++ b/roles/cord-profile/templates/xos.yaml.j2
@@ -11,4 +11,3 @@
     xos:
       type: tosca.nodes.XOS
 
-
diff --git a/roles/cord-profile/templates/xos_common_config.j2 b/roles/cord-profile/templates/xos_common_config.j2
index 175be92..ba67acd 100644
--- a/roles/cord-profile/templates/xos_common_config.j2
+++ b/roles/cord-profile/templates/xos_common_config.j2
@@ -41,7 +41,7 @@
 dependency_graph=/opt/xos/model-deps
 logfile=/var/log/xos_backend.log
 save_ansible_output=True
-node_key={{ cord_profile_dir }}/node_key
+node_key={{ head_cord_profile_dir }}/node_key
 
 [gui]
 disable_minidashboard={{ disable_minidashboard }}
diff --git a/roles/exampleservice-config/defaults/main.yml b/roles/exampleservice-config/defaults/main.yml
index 82098e0..0ce1f31 100644
--- a/roles/exampleservice-config/defaults/main.yml
+++ b/roles/exampleservice-config/defaults/main.yml
@@ -1,6 +1,6 @@
 ---
 # exampleservice-config/defaults/main.yml
 
-cord_dir: "{{ ansible_user_dir + '/cord' }}"
-cord_profile_dir: "{{ ansible_user_dir + '/cord_profile' }}"
-
+# As a test, this is assumed to entirely run on the head node
+head_cord_dir: "/opt/cord"
+head_cord_profile_dir: "/opt/cord_profile"
diff --git a/roles/exampleservice-config/tasks/main.yml b/roles/exampleservice-config/tasks/main.yml
index dc21c17..c07838c 100644
--- a/roles/exampleservice-config/tasks/main.yml
+++ b/roles/exampleservice-config/tasks/main.yml
@@ -6,7 +6,7 @@
     remote_src: True # file is local to the remote machine
     force: False # only copy if destination file doesn't exist
     src: "/dev/null"
-    dest: "{{ cord_profile_dir }}/key_import/{{ item }}"
+    dest: "{{ head_cord_profile_dir }}/key_import/{{ item }}"
     mode: 0600
   with_items:
     - exampleservice_rsa
@@ -14,16 +14,16 @@
 
 - name: Copy exampleservice onboarding TOSCA files to cord_profile
   copy:
-    src: "{{ cord_dir }}/orchestration/xos_services/exampleservice/xos/exampleservice-onboard.yaml"
-    dest: "{{ cord_profile_dir }}/exampleservice-onboard.yaml"
+    src: "{{ head_cord_dir }}/orchestration/xos_services/exampleservice/xos/exampleservice-onboard.yaml"
+    dest: "{{ head_cord_profile_dir }}/exampleservice-onboard.yaml"
 
 - name: TOSCA to mount exampleservice volume in XOS container
   template:
     src: "xos-exampleservice.yaml.j2"
-    dest: "{{ cord_profile_dir }}/xos-exampleservice.yaml"
+    dest: "{{ head_cord_profile_dir }}/xos-exampleservice.yaml"
 
 - name: TOSCA to create exampleservice test config
   template:
     src: "test-exampleservice.yaml.j2"
-    dest: "{{ cord_profile_dir }}/test-exampleservice.yaml"
+    dest: "{{ head_cord_profile_dir }}/test-exampleservice.yaml"
 
diff --git a/roles/exampleservice-config/templates/xos-exampleservice.yaml.j2 b/roles/exampleservice-config/templates/xos-exampleservice.yaml.j2
index 441e075..1baba82 100644
--- a/roles/exampleservice-config/templates/xos-exampleservice.yaml.j2
+++ b/roles/exampleservice-config/templates/xos-exampleservice.yaml.j2
@@ -15,7 +15,7 @@
     /opt/xos_services/exampleservice:
       type: tosca.nodes.XOSVolume
       properties:
-          host_path: "{{ cord_dir }}/orchestration/xos_services/exampleservice"
+          host_path: "{{ head_cord_dir }}/orchestration/xos_services/exampleservice"
           read_only: True
       requirements:
           - xos:
diff --git a/roles/glance-images/defaults/main.yml b/roles/glance-images/defaults/main.yml
new file mode 100644
index 0000000..8b07f0b
--- /dev/null
+++ b/roles/glance-images/defaults/main.yml
@@ -0,0 +1,9 @@
+---
+# glance-images/defaults/main.yml
+
+use_openstack: True
+
+image_dir: /opt/images
+
+xos_images: []
+
diff --git a/roles/glance-images/tasks/main.yml b/roles/glance-images/tasks/main.yml
new file mode 100644
index 0000000..90cbaec
--- /dev/null
+++ b/roles/glance-images/tasks/main.yml
@@ -0,0 +1,33 @@
+---
+# glance-images/tasks/main.yml
+
+- name: Make images directory
+  when: use_openstack
+  become: yes
+  file:
+    path: "{{ image_dir }}"
+    state: directory
+    mode: 0755
+    owner: "{{ ansible_user_id }}"
+    group: "{{ ansible_user_gid }}"
+
+- name: Download Glance VM images
+  when: use_openstack
+  get_url:
+    url: "{{ item.url }}"
+    checksum: "{{ item.checksum }}"
+    dest: "{{ image_dir }}/{{ item.name }}.qcow2"
+  with_items: "{{ xos_images }}"
+  register: glance_vm_result
+  until: glance_vm_result|success
+  retries: 5
+  delay: 10
+
+- name: Copy Glance VM images to profile directory
+  when: use_openstack
+  copy:
+    remote_src: yes
+    src: "{{ image_dir }}/{{ item.name }}.qcow2"
+    dest: "/opt/cord_profile/images/{{ item.name }}.qcow2"
+  with_items: "{{ xos_images }}"
+
diff --git a/roles/head-diag/tasks/main.yml b/roles/head-diag/tasks/main.yml
index e73417b..d2e53fb 100644
--- a/roles/head-diag/tasks/main.yml
+++ b/roles/head-diag/tasks/main.yml
@@ -41,7 +41,7 @@
    - "juju status --format=json"
 
 - name: OpenStack diag collection
-  shell: "source ~/admin-openrc.sh && {{ item }} > ~/{{ diag_dir }}/openstack/{{ item | regex_replace('[^\\w-]', '_')}}"
+  shell: "source /opt/cord_profile/admin-openrc.sh && {{ item }} > ~/{{ diag_dir }}/openstack/{{ item | regex_replace('[^\\w-]', '_')}}"
   ignore_errors: yes
   args:
     executable: "/bin/bash"
diff --git a/roles/juju-compute-setup/tasks/main.yml b/roles/juju-compute-setup/tasks/main.yml
index f4e3918..d6a92c8 100644
--- a/roles/juju-compute-setup/tasks/main.yml
+++ b/roles/juju-compute-setup/tasks/main.yml
@@ -59,7 +59,7 @@
   with_items: "{{ groups['compute'] }}"
 
 - name: verify that the nodes appear in nova
-  action: shell bash -c "source ~/admin-openrc.sh; nova hypervisor-list | grep '{{ item }}'"
+  action: shell bash -c "source /opt/cord_profile/admin-openrc.sh; nova hypervisor-list | grep '{{ item }}'"
   register: result
   until: result | success
   retries: 20
diff --git a/roles/juju-setup/tasks/main.yml b/roles/juju-setup/tasks/main.yml
index d1607b8..115857d 100644
--- a/roles/juju-setup/tasks/main.yml
+++ b/roles/juju-setup/tasks/main.yml
@@ -86,11 +86,3 @@
   tags:
    - skip_ansible_lint # benign to do this more than once, hard to check for
 
-- name: Create admin-openrc.sh OpenStack credentials file
-  template:
-    src: admin-openrc.sh.j2
-    dest: "{{ item }}/admin-openrc.sh"
-  with_items:
-    - "{{ ansible_user_dir }}"
-    - "{{ cord_profile_dir }}"
-
diff --git a/roles/monitoringservice-config/defaults/main.yml b/roles/monitoringservice-config/defaults/main.yml
index 5016f47..2514331 100644
--- a/roles/monitoringservice-config/defaults/main.yml
+++ b/roles/monitoringservice-config/defaults/main.yml
@@ -1,6 +1,9 @@
 ---
 # monitoringservice-config/defaults/main.yml
 
-cord_dir: "{{ ansible_user_dir + '/cord' }}"
-cord_profile_dir: "{{ ansible_user_dir + '/cord_profile' }}"
+#paths
+config_cord_dir: "{{ ansible_user_dir + '/cord' }}"
+head_cord_dir: "/opt/cord"
+
+head_cord_profile_dir: "/opt/cord_profile"
 
diff --git a/roles/monitoringservice-config/tasks/main.yml b/roles/monitoringservice-config/tasks/main.yml
index c511f09..4b925a9 100644
--- a/roles/monitoringservice-config/tasks/main.yml
+++ b/roles/monitoringservice-config/tasks/main.yml
@@ -3,18 +3,18 @@
 
 - name: Copy monitoringservice onboarding TOSCA files to cord_profile
   copy:
-    src: "{{ cord_dir }}/orchestration/xos_services/monitoring/xos/monitoring-onboard.yaml"
-    dest: "{{ cord_profile_dir }}/monitoring-onboard.yaml"
+    src: "{{ config_cord_dir }}/orchestration/xos_services/monitoring/xos/monitoring-onboard.yaml"
+    dest: "{{ head_cord_profile_dir }}/monitoring-onboard.yaml"
 
 - name: TOSCA to mount monitoringservice volume in XOS container
   template:
     src: "xos-monitoringservice.yaml.j2"
-    dest: "{{ cord_profile_dir }}/xos-monitoringservice.yaml"
+    dest: "{{ head_cord_profile_dir }}/xos-monitoringservice.yaml"
 
 - name: TOSCA files to instantiate monitoringservice
   template:
     src: "{{ item }}.j2"
-    dest: "{{ cord_profile_dir }}/{{ item }}"
+    dest: "{{ head_cord_profile_dir }}/{{ item }}"
   with_items:
     - "monitoringservice.yaml"
     - "monitoringtenant.yaml"
diff --git a/roles/monitoringservice-config/templates/xos-monitoringservice.yaml.j2 b/roles/monitoringservice-config/templates/xos-monitoringservice.yaml.j2
index b97ffc7..f54874b 100644
--- a/roles/monitoringservice-config/templates/xos-monitoringservice.yaml.j2
+++ b/roles/monitoringservice-config/templates/xos-monitoringservice.yaml.j2
@@ -15,7 +15,7 @@
     /opt/xos_services/monitoring:
       type: tosca.nodes.XOSVolume
       properties:
-          host_path: "{{ cord_dir }}/orchestration/xos_services/monitoring"
+          host_path: "{{ head_cord_dir }}/orchestration/xos_services/monitoring"
           read_only: True
       requirements:
           - xos:
diff --git a/roles/monitoringservice-onboard/defaults/main.yml b/roles/monitoringservice-onboard/defaults/main.yml
index ff338b7..42c8d6e 100644
--- a/roles/monitoringservice-onboard/defaults/main.yml
+++ b/roles/monitoringservice-onboard/defaults/main.yml
@@ -1,8 +1,8 @@
 ---
 # monitoringservice-onboard/defaults/main.yml
 
-cord_dir: "{{ ansible_user_dir + '/cord' }}"
-cord_profile_dir: "{{ ansible_user_dir + '/cord_profile' }}"
+# paths
+head_cord_profile_dir: "/opt/cord_profile"
 
 xos_bootstrap_ui_port: 9001
 
diff --git a/roles/monitoringservice-onboard/tasks/main.yml b/roles/monitoringservice-onboard/tasks/main.yml
index 9538d7f..c1156f8 100644
--- a/roles/monitoringservice-onboard/tasks/main.yml
+++ b/roles/monitoringservice-onboard/tasks/main.yml
@@ -2,22 +2,22 @@
 # monitoringservice-onboard/tasks/main.yml
 
 - name: Disable onboarding
-  command: "python /opt/xos/tosca/run.py {{ xos_admin_user }} /opt/cord_profile/disable-onboarding.yaml"
+  command: "python /opt/xos/tosca/run.py {{ xos_admin_user }} {{ head_cord_profile_dir }}/disable-onboarding.yaml"
   tags:
     - skip_ansible_lint # TOSCA loading should be idempotent
 
 - name: Have XOS container mount monitoringservice volume
-  command: "python /opt/xos/tosca/run.py {{ xos_admin_user }} /opt/cord_profile/xos-monitoringservice.yaml"
+  command: "python /opt/xos/tosca/run.py {{ xos_admin_user }} {{ head_cord_profile_dir }}/xos-monitoringservice.yaml"
   tags:
     - skip_ansible_lint # TOSCA loading should be idempotent
 
 - name: Onboard monitoringservice
-  command: "python /opt/xos/tosca/run.py {{ xos_admin_user }} /opt/cord_profile/monitoring-onboard.yaml"
+  command: "python /opt/xos/tosca/run.py {{ xos_admin_user }} {{ head_cord_profile_dir }}/monitoring-onboard.yaml"
   tags:
     - skip_ansible_lint # TOSCA loading should be idempotent
 
 - name: Enable onboarding
-  command: "python /opt/xos/tosca/run.py {{ xos_admin_user }} /opt/cord_profile/enable-onboarding.yaml"
+  command: "python /opt/xos/tosca/run.py {{ xos_admin_user }} {{ head_cord_profile_dir }}/enable-onboarding.yaml"
   tags:
     - skip_ansible_lint # TOSCA loading should be idempotent
 
diff --git a/roles/onos-cord-install/defaults/main.yml b/roles/onos-cord-install/defaults/main.yml
index 9b43adc..bdf6d18 100644
--- a/roles/onos-cord-install/defaults/main.yml
+++ b/roles/onos-cord-install/defaults/main.yml
@@ -1,15 +1,23 @@
 ---
-# onos-vm-install/defaults/main.yml
+# onos-cord-install/defaults/main.yml
 
+# paths
+pki_dir: "{{ playbook_dir }}/pki"
+ssh_pki_dir: "{{ playbook_dir }}/ssh_pki"
+head_onos_cord_dir: "/opt/onos_cord"
+
+# Should probably be set to a specific version
+onos_docker_image: "opencord/onos:latest"
+
+# log level for ONOS
+onos_log_level: "INFO"
+
+# name of master ssh key for this pod
+pod_sshkey_name: "headnode"
+
+# used for Java KeyStore within ONOS image
 trust_store_pw: 222222
 
-# ONOS 1.7 not tagged yet, but latest is 1.7
-onos_docker_image: "onosproject/onos:latest"
-
-onos_cord_dest: "{{ ansible_user_dir }}/onos-cord/"
-
-node_private_key: "{{ ansible_user_dir }}/node_key"
-
 # logging_host should be set to DNS or IP addr of logstash host
 logging_host: "cordloghost"
 log4j_port: 4560
diff --git a/roles/onos-cord-install/tasks/main.yml b/roles/onos-cord-install/tasks/main.yml
index 441dc07..86ec128 100644
--- a/roles/onos-cord-install/tasks/main.yml
+++ b/roles/onos-cord-install/tasks/main.yml
@@ -1,29 +1,31 @@
 ---
-# Common ONOS setup
+# onos-cord-install/tasks/main.yml
 
-# onos_cord_dest: {{ ansible_user_dir }}/onos-cord/
-
-- name: Pull docker image for ONOS
-  become: yes
-  command: "docker pull {{ onos_docker_image }}"
-  tags:
-    - skip_ansible_lint # Should replace with http://docs.ansible.com/ansible/docker_module.html, when replacements are stable
+- name: Pull base docker image for ONOS
+  docker_image:
+    name: "{{ onos_docker_image }}"
 
 - name: Create dest directory
-  file: path="{{ onos_cord_dest }}" state=directory
+  become: yes
+  file:
+    path: "{{ head_onos_cord_dir }}"
+    state: directory
+    owner: "{{ ansible_user_id }}"
+    group: "{{ ansible_user_gid }}"
+    mode: 0755
 
 - name: Copy over SSH key
   copy:
-    remote_src: True
-    src: "{{ node_private_key }}"
-    dest: "{{ onos_cord_dest }}/node_key"
+    src: "{{ ssh_pki_dir }}/client_certs/{{ pod_sshkey_name }}_sshkey"
+    dest: "{{ head_onos_cord_dir }}/node_key"
     owner: "{{ ansible_user_id }}"
+    group: "{{ ansible_user_gid }}"
     mode: 0600
 
 - name: Create templated ONOS files
   template:
     src: "{{ item }}.j2"
-    dest: "{{ onos_cord_dest }}/{{ item }}"
+    dest: "{{ head_onos_cord_dir }}/{{ item }}"
   with_items:
     - Dockerfile
     - onos-service
@@ -32,27 +34,26 @@
 - name: Copy over ONOS playbook and other files
   copy:
     src: "onos-cord-docker-compose.yml"
-    dest: "{{ onos_cord_dest }}/docker-compose.yml"
+    dest: "{{ head_onos_cord_dir }}/docker-compose.yml"
 
-# TODO: Find the proper place for this on the dev machine rather than
-#       copying it within the head node machine.
-
-- name: Copy SSL Certs to ONOS so docker-compose can find it
+- name: Copy SSL Certs to ONOS so docker-compose can find them
   copy:
-    src: "/usr/local/share/ca-certificates/{{ item }}"
-    dest: "{{ onos_cord_dest }}/{{ item }}"
+    src: "{{ pki_dir }}/{{ item.src }}"
+    dest: "{{ head_onos_cord_dir }}/{{ item.dest }}"
     owner: "{{ ansible_user_id }}"
-    remote_src: True
   with_items:
-    - "cord_root_ca.crt"
-    - "cord_intermediate_ca.crt"
+    - src: "root_ca/certs/ca_cert.pem"
+      dest: "cord_root_ca.crt"
+    - src: "{{ site_name }}_im_ca/certs/im_cert.pem"
+      dest: "cord_{{ site_name }}_im_ca.crt"
 
-- name: Build onos image
-  command: docker-compose build chdir={{ onos_cord_dest }}
-  tags:
-    - skip_ansible_lint
+- name: Build xos/onos docker image
+  docker_image:
+    name: "xos/onos"
+    path: "{{ head_onos_cord_dir }}"
+    dockerfile: "Dockerfile"
 
-- name: Start ONOS
-  command: chdir="{{ onos_cord_dest }}" docker-compose up -d
-  tags:
-    - skip_ansible_lint
+- name: Start ONOS for CORD
+  docker_service:
+    project_src: "{{ head_onos_cord_dir }}"
+
diff --git a/roles/onos-cord-install/templates/Dockerfile.j2 b/roles/onos-cord-install/templates/Dockerfile.j2
index 263767f..3886943 100644
--- a/roles/onos-cord-install/templates/Dockerfile.j2
+++ b/roles/onos-cord-install/templates/Dockerfile.j2
@@ -5,19 +5,19 @@
 
 # Add SSL certs
 COPY cord_root_ca.crt /usr/local/share/ca-certificates/cord_root_ca.crt
-COPY cord_intermediate_ca.crt /usr/local/share/ca-certificates/cord_intermediate_ca.crt
+COPY cord_{{ site_name }}_im_ca.crt /usr/local/share/ca-certificates/cord_{{ site_name }}_im_ca.crt
 RUN update-ca-certificates
 
 # Create Java KeyStore from certs
 RUN openssl x509 -in /usr/local/share/ca-certificates/cord_root_ca.crt \
       -outform der -out /usr/local/share/ca-certificates/cord_root_ca.der && \
-    openssl x509 -in /usr/local/share/ca-certificates/cord_intermediate_ca.crt \
-      -outform der -out /usr/local/share/ca-certificates/cord_intermediate_ca.der && \
+    openssl x509 -in /usr/local/share/ca-certificates/cord_{{ site_name }}_im_ca.crt \
+      -outform der -out /usr/local/share/ca-certificates/cord_{{ site_name }}_im_ca.der && \
     keytool -import -noprompt -storepass {{ trust_store_pw }} -alias cord_root_ca \
       -file /usr/local/share/ca-certificates/cord_root_ca.der \
       -keystore /usr/local/share/ca-certificates/cord_ca_certs.jks && \
-    keytool -import -noprompt -storepass {{ trust_store_pw }} -alias cord_intermediate_ca \
-      -file /usr/local/share/ca-certificates/cord_intermediate_ca.der \
+    keytool -import -noprompt -storepass {{ trust_store_pw }} -alias cord_{{ site_name }}_im_ca \
+      -file /usr/local/share/ca-certificates/cord_{{ site_name }}_im_ca.der \
       -keystore /usr/local/share/ca-certificates/cord_ca_certs.jks
 
 # Updated onos-service to use the jks
diff --git a/roles/onos-cord-install/templates/org.ops4j.pax.logging.cfg.j2 b/roles/onos-cord-install/templates/org.ops4j.pax.logging.cfg.j2
index 2761c7e..d1c712a 100644
--- a/roles/onos-cord-install/templates/org.ops4j.pax.logging.cfg.j2
+++ b/roles/onos-cord-install/templates/org.ops4j.pax.logging.cfg.j2
@@ -18,7 +18,7 @@
 ################################################################################
 
 # Root logger
-log4j.rootLogger=INFO, out, logstash, osgi:*
+log4j.rootLogger={{ onos_log_level }}, out, logstash, osgi:*
 log4j.throwableRenderer=org.apache.log4j.OsgiThrowableRenderer
 
 # CONSOLE appender not used by default
@@ -28,7 +28,6 @@
 
 # logstash log4j appender
 log4j.appender.logstash=org.apache.log4j.net.SocketAppender
-log4j.appender.logstash.threshold=DEBUG
 log4j.appender.logstash.Port={{ log4j_port }}
 log4j.appender.logstash.RemoteHost={{ logging_host }}
 log4j.appender.logstash.ReconnectionDelay=5000
diff --git a/roles/onos-fabric-install/defaults/main.yml b/roles/onos-fabric-install/defaults/main.yml
index 8a1e199..2c70fc8 100644
--- a/roles/onos-fabric-install/defaults/main.yml
+++ b/roles/onos-fabric-install/defaults/main.yml
@@ -1,11 +1,10 @@
 ---
-# onos-vm-install/defaults/main.yml
+# onos-fabric-install/defaults/main.yml
 
-trust_store_pw: 222222
+# paths
+head_onos_fabric_dir: "/opt/onos_fabric"
 
-# ONOS 1.7 not tagged yet, but latest is 1.7
-onos_docker_image: "onosproject/onos:latest"
+# Should probably be set to a specific version
+onos_docker_image: "opencord/onos:latest"
 
-onos_fabric_dest: "{{ ansible_user_dir }}/onos-fabric/"
 
-node_private_key: "{{ ansible_user_dir }}/node_key"
diff --git a/roles/onos-fabric-install/tasks/main.yml b/roles/onos-fabric-install/tasks/main.yml
index 4f16e64..49c2538 100644
--- a/roles/onos-fabric-install/tasks/main.yml
+++ b/roles/onos-fabric-install/tasks/main.yml
@@ -1,28 +1,29 @@
 ---
-# Common ONOS setup
+# onos-fabric-install/tasks/main.yml
 
-- name: Pull docker image for ONOS
+- name: Pull base docker image for ONOS
+  docker_image:
+    name: "{{ onos_docker_image }}"
+
+- name: Create onos-fabric dest directory
   become: yes
-  command: "docker pull {{ onos_docker_image }}"
-  tags:
-    - skip_ansible_lint # Should replace with http://docs.ansible.com/ansible/docker_module.html, when replacements are stable
-
-- name: Create dest directory
   file:
-    path: "{{ onos_fabric_dest }}"
+    path: "{{ head_onos_fabric_dir }}"
     state: directory
+    owner: "{{ ansible_user_id }}"
+    group: "{{ ansible_user_gid }}"
+    mode: 0755
 
 - name: Create templated ONOS files
   template:
     src: "{{ item }}.j2"
-    dest: "{{ onos_fabric_dest }}/{{ item }}"
+    dest: "{{ head_onos_fabric_dir }}/{{ item }}"
   with_items:
     - docker-compose.yml
 
 # Note: we do not rebuild onos container for the fabric
 
-- name: Start ONOS
-  command: chdir="{{ onos_fabric_dest }}" docker-compose up -d
-  tags:
-    - skip_ansible_lint
+- name: Start ONOS for fabric
+  docker_service:
+    project_src: "{{ head_onos_fabric_dir }}"
 
diff --git a/roles/pki-root-ca/tasks/main.yml b/roles/pki-root-ca/tasks/main.yml
index 8c2f34d..fd526e4 100644
--- a/roles/pki-root-ca/tasks/main.yml
+++ b/roles/pki-root-ca/tasks/main.yml
@@ -1,21 +1,16 @@
 ---
 # pki-root-ca/tasks/main.yml
 
-- name: Create credentials directory
+- name: Create PKI and credentials directories
   become: yes
   file:
-    dest: "{{ credentials_dir }}"
+    dest: "{{ item }}"
     state: directory
     owner: "{{ ansible_user_id }}"
     mode: 0700
-
-- name: Create PKI directory
-  become: yes
-  file:
-    dest: "{{ pki_dir }}"
-    state: directory
-    owner: "{{ ansible_user_id }}"
-    mode: 0755
+  with_items:
+    - "{{ credentials_dir }}"
+    - "{{ pki_dir }}"
 
 - name: Create root CA directory
   become: yes
diff --git a/roles/platform-check/defaults/main.yml b/roles/platform-check/defaults/main.yml
index 16a8ef7..4e19128 100644
--- a/roles/platform-check/defaults/main.yml
+++ b/roles/platform-check/defaults/main.yml
@@ -1,8 +1,8 @@
 ---
 # platform-check/defaults/main.yml
 
-onos_cord_dest: "{{ ansible_user_dir }}/onos-cord/"
-cord_profile_dir: "{{ ansible_user_dir + '/cord_profile' }}"
+config_cord_profile_dir: "{{ ansible_user_dir + '/cord_profile' }}"
+head_onos_cord_dir: "/opt/onos-cord/"
 
 xos_ui_port: 9000
 
diff --git a/roles/platform-check/tasks/main.yml b/roles/platform-check/tasks/main.yml
index a67e837..bd9347e 100644
--- a/roles/platform-check/tasks/main.yml
+++ b/roles/platform-check/tasks/main.yml
@@ -16,7 +16,7 @@
   when: result | failed
   shell: docker-compose stop; docker-compose rm -f; docker-compose up -d
   args:
-    chdir: "{{ onos_cord_dest }}"
+    chdir: "{{ head_onos_cord_dir }}"
   tags:
     - skip_ansible_lint
 
@@ -26,7 +26,7 @@
     url: "http://xos.{{ site_suffix }}:{{ xos_ui_port }}/api/utility/tosca/run/"
     user: "{{ xos_admin_user }}"
     password:  "{{ xos_admin_pass }}"
-    recipe: "{{ lookup('file', cord_profile_dir + '/' + item ) }}"
+    recipe: "{{ lookup('file', head_cord_profile_dir + '/' + item ) }}"
   with_items:
     - openstack.yaml
     - openstack-compute.yaml
@@ -42,7 +42,7 @@
     url: "http://xos.{{ site_suffix }}:{{ xos_ui_port }}/api/utility/tosca/run/"
     user: "{{ xos_admin_user }}"
     password:  "{{ xos_admin_pass }}"
-    recipe: "{{ lookup('file', cord_profile_dir + '/' + item ) }}"
+    recipe: "{{ lookup('file', head_cord_profile_dir + '/' + item ) }}"
   with_items:
     - openstack-compute-vtn.yaml
 
diff --git a/roles/repo/defaults/main.yml b/roles/repo/defaults/main.yml
index b2af59f..6ef6c5a 100644
--- a/roles/repo/defaults/main.yml
+++ b/roles/repo/defaults/main.yml
@@ -1,7 +1,7 @@
 ---
 # repo/defaults/main.yml
 
-cord_dir: "{{ ansible_user_dir + '/cord' }}"
+config_cord_dir: "{{ ansible_user_dir + '/cord' }}"
 repo_dl_url: "https://storage.googleapis.com/git-repo-downloads/repo"
 
 # This is for repo v1.23, and will change, as repo_dl_url unfortunately lacks a version...
diff --git a/roles/repo/tasks/main.yml b/roles/repo/tasks/main.yml
index 779e406..58cafa3 100644
--- a/roles/repo/tasks/main.yml
+++ b/roles/repo/tasks/main.yml
@@ -13,25 +13,25 @@
 
 - name: Create CORD directory
   file:
-    dest: "{{ cord_dir }}"
+    dest: "{{ config_cord_dir }}"
     state: directory
 
 - name: Init CORD repos (master branch) using repo
   command: "/usr/local/bin/repo init -u {{ repo_manifest_url }} -b master -g build,onos,orchestration"
   args:
-    chdir: "{{ cord_dir }}"
-    creates: "{{ cord_dir }}/.repo"
+    chdir: "{{ config_cord_dir }}"
+    creates: "{{ config_cord_dir }}/.repo"
 
 - name: Synchronize CORD repos using repo
   command: "repo sync"
   args:
-    chdir: "{{ cord_dir }}"
-    creates: "{{ cord_dir }}/build"
+    chdir: "{{ config_cord_dir }}"
+    creates: "{{ config_cord_dir }}/build"
 
 - name: Download specific gerrit changesets using repo
   command: "/usr/local/bin/repo download {{ item.path }} {{ item.revision }}"
   args:
-    chdir: "{{ cord_dir }}"
+    chdir: "{{ config_cord_dir }}"
   with_items: "{{ gerrit_changesets }}"
   tags:
     - skip_ansible_lint # usually won't be run, except during dev
diff --git a/roles/ssh-install-maas/defaults/main.yml b/roles/ssh-install-maas/defaults/main.yml
new file mode 100644
index 0000000..15abf98
--- /dev/null
+++ b/roles/ssh-install-maas/defaults/main.yml
@@ -0,0 +1,11 @@
+---
+# ssh-install-maas/defaults/main.yml
+
+ssh_pki_dir: "{{ playbook_dir }}/ssh_pki"
+
+ssh_keytype: rsa
+
+# name of master ssh key for this pod
+pod_sshkey_name: "headnode"
+
+on_maas: False
diff --git a/roles/ssh-install-maas/tasks/main.yml b/roles/ssh-install-maas/tasks/main.yml
new file mode 100644
index 0000000..96d952d
--- /dev/null
+++ b/roles/ssh-install-maas/tasks/main.yml
@@ -0,0 +1,35 @@
+---
+# ssh-install-maas/tasks/main.yml
+
+# the following replicates the functionality of the maas repo `prep` role
+# users/perms may seem off, but is identical to that role
+
+- name: Create ssh key directory for MaaS
+  when: on_maas
+  file:
+    dest: "/etc/maas/.ssh/"
+    mode: 0755
+    owner: "root"
+    group: "root"
+    state: directory
+
+- name: Copy ssh private key for MaaS
+  when: on_maas
+  copy:
+    src: "{{ ssh_pki_dir }}/client_certs/{{ pod_sshkey_name }}_sshkey"
+    dest: "/etc/maas/.ssh/cord_rsa"
+    mode: 0644
+    owner: "root"
+    group: "root"
+    backup: true
+
+- name: Copy ssh public key for MaaS
+  when: on_maas
+  copy:
+    src: "{{ ssh_pki_dir }}/client_certs/{{ pod_sshkey_name }}_sshkey.pub"
+    dest: "/etc/maas/.ssh/cord_rsa.pub"
+    mode: 0644
+    owner: "root"
+    group: "root"
+    backup: true
+
diff --git a/roles/ssh-install/defaults/main.yml b/roles/ssh-install/defaults/main.yml
new file mode 100644
index 0000000..1fbddfa
--- /dev/null
+++ b/roles/ssh-install/defaults/main.yml
@@ -0,0 +1,11 @@
+---
+# ssh-install/defaults/main.yml
+
+ssh_pki_dir: "{{ playbook_dir }}/ssh_pki"
+
+ssh_keytype: rsa
+
+# name of master ssh key for this pod
+pod_sshkey_name: "headnode"
+
+on_maas: False
diff --git a/roles/ssh-install/tasks/main.yml b/roles/ssh-install/tasks/main.yml
new file mode 100644
index 0000000..d59db84
--- /dev/null
+++ b/roles/ssh-install/tasks/main.yml
@@ -0,0 +1,29 @@
+---
+# ssh-install/tasks/main.yml
+
+- name: Create ~/.ssh directory
+  file:
+    dest: "{{ ansible_user_dir }}/.ssh/"
+    mode: 0700
+    owner: "{{ ansible_user_id }}"
+    group: "{{ ansible_user_gid }}"
+    state: directory
+
+- name: Install ssh private key
+  copy:
+    src: "{{ ssh_pki_dir }}/client_certs/{{ pod_sshkey_name }}_sshkey"
+    dest: "{{ ansible_user_dir }}/.ssh/id_{{ ssh_keytype }}"
+    mode: 0600
+    owner: "{{ ansible_user_id }}"
+    group: "{{ ansible_user_gid }}"
+    backup: true
+
+- name: Install ssh public key
+  copy:
+    src: "{{ ssh_pki_dir }}/client_certs/{{ pod_sshkey_name }}_sshkey.pub"
+    dest: "{{ ansible_user_dir }}/.ssh/id_{{ ssh_keytype }}.pub"
+    mode: 0600
+    owner: "{{ ansible_user_id }}"
+    group: "{{ ansible_user_gid }}"
+    backup: true
+
diff --git a/roles/ssh-pki/defaults/main.yml b/roles/ssh-pki/defaults/main.yml
index c7e6125..0909635 100644
--- a/roles/ssh-pki/defaults/main.yml
+++ b/roles/ssh-pki/defaults/main.yml
@@ -11,9 +11,12 @@
 ssh_keytype: rsa
 ssh_keysize: 4096
 
+# name of master ssh key for this pod
+pod_sshkey_name: "headnode"
+
 # lists of keys to generate
 ssh_client_genkeys:
-  - name: headnode
+  - name: "{{ pod_sshkey_name }}"
 
 ssh_host_genkeys: []
 
diff --git a/roles/ssh-pki/tasks/main.yml b/roles/ssh-pki/tasks/main.yml
index 44dbe64..2cc7c64 100644
--- a/roles/ssh-pki/tasks/main.yml
+++ b/roles/ssh-pki/tasks/main.yml
@@ -2,6 +2,7 @@
 # ssh-pki/tasks/main.yml
 
 - name: Create SSH CA Directory
+  become: yes
   file:
     dest: "{{ item }}"
     state: directory
diff --git a/roles/teardown-profile/defaults/main.yml b/roles/teardown-profile/defaults/main.yml
index b050484..83c07e2 100644
--- a/roles/teardown-profile/defaults/main.yml
+++ b/roles/teardown-profile/defaults/main.yml
@@ -1,11 +1,9 @@
 ---
 # teardown-profile/defaults/main.yml
 
-cord_dir: "{{ ansible_user_dir + '/cord' }}"
-
-cord_profile_dir: "{{ ansible_user_dir + '/cord_profile' }}"
+head_cord_profile_dir: "/opt/cord_profile"
 
 xos_docker_networks:
   - "xos"
 
-delete_cord_profile_dir: False
\ No newline at end of file
+delete_cord_profile_dir: False
diff --git a/roles/teardown-profile/tasks/main.yml b/roles/teardown-profile/tasks/main.yml
index 4cfd552..365c087 100644
--- a/roles/teardown-profile/tasks/main.yml
+++ b/roles/teardown-profile/tasks/main.yml
@@ -6,7 +6,7 @@
 - name: Stop and remove XOS containers
   docker_service:
     project_name: "{{ cord_profile | regex_replace('\\W','') }}"
-    project_src: "{{ cord_profile_dir }}"
+    project_src: "{{ head_cord_profile_dir }}"
     state: absent
     remove_images: local
   ignore_errors: yes
@@ -22,7 +22,7 @@
 
 - name: Remove the cord_profile directory
   file:
-    path: "{{ cord_profile_dir }}"
+    path: "{{ head_cord_profile_dir }}"
     state: absent
   ignore_errors: yes
   when: delete_cord_profile_dir
diff --git a/roles/test-ecord-subscriber-config/defaults/main.yml b/roles/test-ecord-subscriber-config/defaults/main.yml
index 3fbf456..9d7abab 100644
--- a/roles/test-ecord-subscriber-config/defaults/main.yml
+++ b/roles/test-ecord-subscriber-config/defaults/main.yml
@@ -1,5 +1,4 @@
 ---
-# test-subscriber-config/defaults/main.yml
+# test-ecord-subscriber-config/defaults/main.yml
 
-cord_profile_dir: "{{ ansible_user_dir + '/cord_profile' }}"
-
+head_cord_profile_dir: "/opt/cord_profile"
diff --git a/roles/test-ecord-subscriber-config/tasks/main.yml b/roles/test-ecord-subscriber-config/tasks/main.yml
index 16a343d..51fe639 100644
--- a/roles/test-ecord-subscriber-config/tasks/main.yml
+++ b/roles/test-ecord-subscriber-config/tasks/main.yml
@@ -1,10 +1,10 @@
 ---
-# test-subscriber/tasks/main.yml
+# test-ecord-subscriber-config/tasks/main.yml
 
 - name: Create test-ecord-subscriber.yaml TOSCA config
   template:
     src: test-ecord-subscriber.yaml.j2
-    dest: "{{ cord_profile_dir }}/test-ecord-subscriber.yaml"
+    dest: "{{ head_cord_profile_dir }}/test-ecord-subscriber.yaml"
     owner: "{{ ansible_user_id }}"
     mode: 0644
 
diff --git a/roles/test-exampleservice/defaults/main.yml b/roles/test-exampleservice/defaults/main.yml
index 04b252e..82900ab 100644
--- a/roles/test-exampleservice/defaults/main.yml
+++ b/roles/test-exampleservice/defaults/main.yml
@@ -1,6 +1,6 @@
 ---
 # test-exampleservice/defaults/main.yml
 
-cord_profile_dir: "{{ ansible_user_dir + '/cord_profile' }}"
+head_cord_profile_dir: "/opt/cord_profile"
 xos_ui_port: 9000
 
diff --git a/roles/test-exampleservice/tasks/main.yml b/roles/test-exampleservice/tasks/main.yml
index 08fad6b..fd69893 100644
--- a/roles/test-exampleservice/tasks/main.yml
+++ b/roles/test-exampleservice/tasks/main.yml
@@ -7,10 +7,10 @@
     url: "http://xos.{{ site_suffix }}:{{ xos_ui_port }}/api/utility/tosca/run/"
     user: "{{ xos_admin_user }}"
     password:  "{{ xos_admin_pass }}"
-    recipe: "{{ lookup('file', cord_profile_dir + '/test-exampleservice.yaml' ) }}"
+    recipe: "{{ lookup('file', head_cord_profile_dir + '/test-exampleservice.yaml' ) }}"
 
 - name: Wait for ExampleService VM to come up
-  shell: bash -c "source ~/admin-openrc.sh; nova list --all-tenants|grep 'exampleservice.*ACTIVE' > /dev/null"
+  shell: bash -c "source /opt/cord_profile/admin-openrc.sh; nova list --all-tenants|grep 'exampleservice.*ACTIVE' > /dev/null"
   register: result
   until: result | success
   retries: 10
@@ -19,25 +19,25 @@
     - skip_ansible_lint # running a sub job
 
 - name: Get ID of VM
-  shell: bash -c "source ~/admin-openrc.sh; nova list --all-tenants|grep mysite_exampleservice|cut -d '|' -f 2"
+  shell: bash -c "source /opt/cord_profile/admin-openrc.sh; nova list --all-tenants|grep mysite_exampleservice|cut -d '|' -f 2"
   register: nova_id
   tags:
     - skip_ansible_lint # running a sub job
 
 - name: Get mgmt IP of VM
-  shell: bash -c "source ~/admin-openrc.sh; nova interface-list {{ nova_id.stdout }}|grep -o -m 1 '172\.27\.[[:digit:]]*\.[[:digit:]]*'"
+  shell: bash -c "source /opt/cord_profile/admin-openrc.sh; nova interface-list {{ nova_id.stdout }}|grep -o -m 1 '172\.27\.[[:digit:]]*\.[[:digit:]]*'"
   register: mgmt_ip
   tags:
     - skip_ansible_lint # running a sub job
 
 - name: Get public IP of VM
-  shell: bash -c "source ~/admin-openrc.sh; nova interface-list {{ nova_id.stdout }}|grep -o -m 1 '10\.6\.[[:digit:]]*\.[[:digit:]]*'"
+  shell: bash -c "source /opt/cord_profile/admin-openrc.sh; nova interface-list {{ nova_id.stdout }}|grep -o -m 1 '10\.6\.[[:digit:]]*\.[[:digit:]]*'"
   register: public_ip
   tags:
     - skip_ansible_lint # running a sub job
 
 - name: Get name of compute node
-  shell: bash -c "source ~/admin-openrc.sh; nova service-list|grep nova-compute|cut -d '|' -f 3"
+  shell: bash -c "source /opt/cord_profile/admin-openrc.sh; nova service-list|grep nova-compute|cut -d '|' -f 3"
   register: node_name
   tags:
     - skip_ansible_lint # running a sub job
diff --git a/roles/test-subscriber-config/defaults/main.yml b/roles/test-subscriber-config/defaults/main.yml
index 3fbf456..9da9f64 100644
--- a/roles/test-subscriber-config/defaults/main.yml
+++ b/roles/test-subscriber-config/defaults/main.yml
@@ -1,5 +1,4 @@
 ---
 # test-subscriber-config/defaults/main.yml
 
-cord_profile_dir: "{{ ansible_user_dir + '/cord_profile' }}"
-
+head_cord_profile_dir: "/opt/cord_profile"
diff --git a/roles/test-subscriber-config/tasks/main.yml b/roles/test-subscriber-config/tasks/main.yml
index 46c1642..fd8a7a1 100644
--- a/roles/test-subscriber-config/tasks/main.yml
+++ b/roles/test-subscriber-config/tasks/main.yml
@@ -1,10 +1,10 @@
 ---
-# test-subscriber/tasks/main.yml
+# test-subscriber-config/tasks/main.yml
 
 - name: Create test-subscriber.yaml TOSCA config
   template:
     src: test-subscriber.yaml.j2
-    dest: "{{ cord_profile_dir }}/test-subscriber.yaml"
+    dest: "{{ head_cord_profile_dir }}/test-subscriber.yaml"
     owner: "{{ ansible_user_id }}"
     mode: 0644
 
diff --git a/roles/test-vsg/tasks/main.yml b/roles/test-vsg/tasks/main.yml
index 6beb908..972dc7b 100644
--- a/roles/test-vsg/tasks/main.yml
+++ b/roles/test-vsg/tasks/main.yml
@@ -4,13 +4,13 @@
 # Run tests to check that the CORD-in-a-Box deployment has worked.
 
 - name: Get name of compute node
-  shell: bash -c "source ~/admin-openrc.sh; nova service-list|grep nova-compute|cut -d '|' -f 3"
+  shell: bash -c "source /opt/cord_profile/admin-openrc.sh; nova service-list|grep nova-compute|cut -d '|' -f 3"
   register: node_name
   tags:
     - skip_ansible_lint # running a sub job
 
 - name: Wait for vSG VM to come up
-  shell: bash -c "source ~/admin-openrc.sh; nova list --all-tenants|grep 'vsg.*ACTIVE' > /dev/null"
+  shell: bash -c "source /opt/cord_profile/admin-openrc.sh; nova list --all-tenants|grep 'vsg.*ACTIVE' > /dev/null"
   register: result
   until: result | success
   retries: 10
@@ -19,13 +19,13 @@
     - skip_ansible_lint # running a sub job
 
 - name: Get ID of VM
-  shell: bash -c "source ~/admin-openrc.sh; nova list --all-tenants|grep mysite_vsg|cut -d '|' -f 2"
+  shell: bash -c "source /opt/cord_profile/admin-openrc.sh; nova list --all-tenants|grep mysite_vsg|cut -d '|' -f 2"
   register: nova_id
   tags:
     - skip_ansible_lint # running a sub job
 
 - name: Get mgmt IP of VM
-  shell: bash -c "source ~/admin-openrc.sh; nova interface-list {{ nova_id.stdout }}|grep -o -m 1 '172\.27\.[[:digit:]]*\.[[:digit:]]*'"
+  shell: bash -c "source /opt/cord_profile/admin-openrc.sh; nova interface-list {{ nova_id.stdout }}|grep -o -m 1 '172\.27\.[[:digit:]]*\.[[:digit:]]*'"
   register: mgmt_ip
   tags:
     - skip_ansible_lint # running a sub job
diff --git a/roles/xos-bootstrap-hosts/defaults/main.yml b/roles/xos-bootstrap-hosts/defaults/main.yml
index 6b20046..86f373f 100644
--- a/roles/xos-bootstrap-hosts/defaults/main.yml
+++ b/roles/xos-bootstrap-hosts/defaults/main.yml
@@ -1,7 +1,5 @@
 ---
 # xos-bootstrap-hosts/defaults/main.yml
 
-cord_dir: "{{ ansible_user_dir + '/cord' }}"
-
-cord_profile_dir: "{{ ansible_user_dir + '/cord_profile' }}"
+head_cord_profile_dir: "/opt/cord_profile"
 
diff --git a/roles/xos-bootstrap-hosts/tasks/main.yml b/roles/xos-bootstrap-hosts/tasks/main.yml
index 32a589c..9437dde 100644
--- a/roles/xos-bootstrap-hosts/tasks/main.yml
+++ b/roles/xos-bootstrap-hosts/tasks/main.yml
@@ -4,7 +4,7 @@
 - name: Get the Docker container names for bootstrap containers
   docker_service:
     project_name: "{{ cord_profile | regex_replace('\\W','') }}bs"
-    project_src: "{{ cord_profile_dir }}"
+    project_src: "{{ head_cord_profile_dir }}"
     files: "xos-bootstrap-docker-compose.yaml"
     recreate: never
   register: xos_bootstrap_out
diff --git a/roles/xos-core-build/defaults/main.yml b/roles/xos-core-build/defaults/main.yml
index e6d6c26..2772a14 100644
--- a/roles/xos-core-build/defaults/main.yml
+++ b/roles/xos-core-build/defaults/main.yml
@@ -1,7 +1,8 @@
 ---
+# xos-core-build/defaults/main.yml
 
-cord_dir: "{{ playbook_dir + '/../..' }}"
-build_docker_tag: candidate
+build_cord_dir: "{{ playbook_dir ~ '/../..' }}"
+build_docker_tag: "candidate"
 
 deploy_docker_registry: "localhost:5000"
 deploy_docker_tag: "candidate"
@@ -12,3 +13,4 @@
 profile_library: ""
 
 xos_services: []
+
diff --git a/roles/xos-core-build/tasks/main.yml b/roles/xos-core-build/tasks/main.yml
index 88e6af6..06faff1 100644
--- a/roles/xos-core-build/tasks/main.yml
+++ b/roles/xos-core-build/tasks/main.yml
@@ -30,7 +30,7 @@
 
 - name: Create the BUILD directory
   file:
-    path: "{{ cord_dir | realpath }}/orchestration/xos/containers/xos/BUILD"
+    path: "{{ build_cord_dir | realpath }}/orchestration/xos/containers/xos/BUILD"
     state: directory
     mode: 0755
 
@@ -41,9 +41,9 @@
   shell: >
     docker run
     --rm
-    -v {{ cord_dir | realpath }}:/opt/cord
-    -v {{ cord_dir | realpath }}/orchestration/xos/containers/xos/BUILD:/opt/xos_corebuilder/BUILD
-    xosproject/xos-corebuilder:candidate
+    -v {{ build_cord_dir | realpath }}:/opt/cord
+    -v {{ build_cord_dir ~ "/orchestration/xos/containers/xos/BUILD" | realpath }}:/opt/xos_corebuilder/BUILD
+    xosproject/xos-corebuilder:{{ build_docker_tag }}
     {{ recipes_string }}
   tags:
    - skip_ansible_lint # running a build task
@@ -51,7 +51,7 @@
 - name: Build UI image
   docker_image:
     name: "xosproject/xos-ui"
-    path: "{{ cord_dir | realpath }}/orchestration/xos"
+    path: "{{ build_cord_dir | realpath }}/orchestration/xos"
     tag: "{{ build_docker_tag }}"
     dockerfile: "containers/xos/Dockerfile.UI"
     pull: False
diff --git a/roles/xos-gui-extension-build/defaults/main.yml b/roles/xos-gui-extension-build/defaults/main.yml
index 260f667..0dd8561 100644
--- a/roles/xos-gui-extension-build/defaults/main.yml
+++ b/roles/xos-gui-extension-build/defaults/main.yml
@@ -1,7 +1,7 @@
 ---
 # xos-gui-extension-build/defaults/main.yml
 
-cord_dir: "{{ ansible_user_dir + '/cord' }}"
-cord_profile_dir: "{{ ansible_user_dir + '/cord_profile' }}"
+head_cord_dir: "/opt/cord"
+head_cord_profile_dir: "/opt/cord_profile"
 
-enabled_gui_extensions: []
\ No newline at end of file
+enabled_gui_extensions: []
diff --git a/roles/xos-gui-extension-build/tasks/main.yml b/roles/xos-gui-extension-build/tasks/main.yml
index 51be926..b337d4f 100644
--- a/roles/xos-gui-extension-build/tasks/main.yml
+++ b/roles/xos-gui-extension-build/tasks/main.yml
@@ -5,7 +5,7 @@
 - name: Build xos-gui-extension-builder image
   docker_image:
     name: "xosproject/xos-gui-extension-builder"
-    path: "{{ cord_dir }}/orchestration/xos-gui/"
+    path: "{{ head_cord_dir }}/orchestration/xos-gui/"
     dockerfile: "Dockerfile.xos-gui-extension-builder"
   register: "xos-gui-extension-builder"
 
@@ -13,24 +13,17 @@
 - name: Build xos-gui-extensions docker images
   docker_image:
     name: "xosproject/gui-extension-{{ item.name }}"
-    path: "{{ cord_dir }}/{{ item.path }}"
+    path: "{{ head_cord_dir }}/{{ item.path }}"
     pull: false
   with_items: "{{ enabled_gui_extensions }}"
 
-# Compile the TOSCA to onboard extensions
+# Compile the TOSCA to onboard and persist extensions
 - name: Create templated TOSCA to onboard extensions
   template:
     src: "{{ item }}.j2"
-    dest: "{{ cord_profile_dir }}/{{ item }}"
+    dest: "{{ head_cord_profile_dir }}/{{ item }}"
     mode: 0644
   with_items:
     - xos-gui-extensions-onboard.yml
-
-# Compile the TOSCA to persist extensions
-- name: Create templated TOSCA to persist extensions
-  template:
-    src: "{{ item }}.j2"
-    dest: "{{ cord_profile_dir }}/{{ item }}"
-    mode: 0644
-  with_items:
     - xos-gui-extensions.yml
+
diff --git a/roles/xos-onboard-hosts/defaults/main.yml b/roles/xos-onboard-hosts/defaults/main.yml
index ee4dbb9..089a98a 100644
--- a/roles/xos-onboard-hosts/defaults/main.yml
+++ b/roles/xos-onboard-hosts/defaults/main.yml
@@ -1,7 +1,5 @@
 ---
 # xos-onboard-hosts/defaults/main.yml
 
-cord_dir: "{{ ansible_user_dir + '/cord' }}"
-
-cord_profile_dir: "{{ ansible_user_dir + '/cord_profile' }}"
+head_cord_profile_dir: /opt/cord_profile
 
diff --git a/roles/xos-onboard-hosts/tasks/main.yml b/roles/xos-onboard-hosts/tasks/main.yml
index 2b60f5a..bc378cd 100644
--- a/roles/xos-onboard-hosts/tasks/main.yml
+++ b/roles/xos-onboard-hosts/tasks/main.yml
@@ -4,7 +4,7 @@
 - name: Get the Docker container names for onboarded containers
   docker_service:
     project_name: "{{ cord_profile | regex_replace('\\W','') }}"
-    project_src: "{{ cord_profile_dir }}"
+    project_src: "{{ head_cord_profile_dir }}"
     recreate: never
   register: xos_onboard_out
 
diff --git a/roles/xos-onboard-test-hosts/defaults/main.yml b/roles/xos-onboard-test-hosts/defaults/main.yml
index 659d9c4..8fe0c9d 100644
--- a/roles/xos-onboard-test-hosts/defaults/main.yml
+++ b/roles/xos-onboard-test-hosts/defaults/main.yml
@@ -1,5 +1,4 @@
 ---
+# xos-onboard-hosts/defaults/main.yml
 
-cord_dir: "{{ ansible_user_dir + '/cord' }}"
-
-cord_profile_dir: "{{ ansible_user_dir + '/cord_profile' }}"
+head_cord_profile_dir: "/opt/cord_profile"
diff --git a/roles/xos-onboard-test-hosts/tasks/main.yml b/roles/xos-onboard-test-hosts/tasks/main.yml
index 0496464..53c5b42 100644
--- a/roles/xos-onboard-test-hosts/tasks/main.yml
+++ b/roles/xos-onboard-test-hosts/tasks/main.yml
@@ -4,7 +4,7 @@
 - name: Get the Docker container names for onboarded containers
   docker_service:
     project_name: "{{ cord_profile | regex_replace('\\W','') }}"
-    project_src: "{{ cord_profile_dir }}/onboarding-docker-compose/"
+    project_src: "{{ head_cord_profile_dir }}/onboarding-docker-compose/"
     recreate: never
   register: xos_onboard_out
 
diff --git a/roles/xos-up/defaults/main.yml b/roles/xos-up/defaults/main.yml
index 7804fa3..189b3a8 100644
--- a/roles/xos-up/defaults/main.yml
+++ b/roles/xos-up/defaults/main.yml
@@ -1,8 +1,7 @@
 ---
-# xos-service-onboard/defaults/main.yml
+# xos-up/defaults/main.yml
 
-cord_dir: "{{ ansible_user_dir + '/cord' }}"
-cord_profile_dir: "{{ ansible_user_dir + '/cord_profile' }}"
+head_cord_profile_dir: "/opt/cord_profile"
 
 xos_docker_networks:
   - "xos"
diff --git a/roles/xos-up/tasks/main.yml b/roles/xos-up/tasks/main.yml
index 8e442b9..e97c9e5 100644
--- a/roles/xos-up/tasks/main.yml
+++ b/roles/xos-up/tasks/main.yml
@@ -9,4 +9,4 @@
 - name: Bring up XOS services
   docker_service:
     project_name: "{{ cord_profile | regex_replace('\\W','') }}"
-    project_src: "{{ cord_profile_dir }}"
+    project_src: "{{ head_cord_profile_dir }}"