CORD-912
OpenCloud-in-a-Box script
apply VAGRANT_CWD in proper place, fix order on elk.diff application
nvme drive support for Utah cloudlab
utah cloudlab fixes
fix logic inversion on SSH keygen
rename network interface
configuration of libvirt networks
network fixes
vagrant-libvirt fails to use networks created by others
update ip addresses for OCiaB
change IP's for head/compute VM's
fix VM destroy
manually configure mgmt network
use a bogus ip address range for management network
typo
dns failure check
don't install docker on the host node
frontload more package installation
sudo on cleanup vagrant command
s/loghost/cordloghost/ to fix logging to logstash
remove now-unneccesary steps
make suitable for CiaB use
fix paths in CiaB Vagrantfile
fixed paths in a more maintainable way
set vagrantfile path in more places
bump Vagrant version, fix for compute-node naming

Change-Id: Icbaaab4e74bd18c87b17f474bd5eea347c98cfaf
diff --git a/ansible/opencloud-in-a-box-playbook.yml b/ansible/opencloud-in-a-box-playbook.yml
new file mode 100644
index 0000000..0b469b0
--- /dev/null
+++ b/ansible/opencloud-in-a-box-playbook.yml
@@ -0,0 +1,15 @@
+---
+# opencloud-in-a-box-playbook.yml
+# configures host for running the OpenCloud-in-a-Box
+
+- name: Include vars
+  hosts: localhost
+  tasks:
+    - name: Include vars
+      include_vars: "../config/opencloud_in_a_box.yaml"
+
+- name: Configure libvirt networks
+  hosts: localhost
+  roles:
+    - virt-nets
+
diff --git a/ansible/roles/virt-nets/defaults/main.yml b/ansible/roles/virt-nets/defaults/main.yml
new file mode 100644
index 0000000..5126a98
--- /dev/null
+++ b/ansible/roles/virt-nets/defaults/main.yml
@@ -0,0 +1,5 @@
+---
+# virt-nets/defaults/main.yml
+
+virt_nets: []
+
diff --git a/ansible/roles/virt-nets/tasks/main.yml b/ansible/roles/virt-nets/tasks/main.yml
new file mode 100644
index 0000000..15e52e5
--- /dev/null
+++ b/ansible/roles/virt-nets/tasks/main.yml
@@ -0,0 +1,53 @@
+---
+# virt-nets/tasks/main.yml
+
+- name: Install libvirt/lxml python module
+  apt:
+    name: "{{ item }}"
+    update_cache: yes
+    cache_valid_time: 3600
+  with_items:
+    - python-libvirt
+    - python-lxml
+
+- name: collect libvirt network facts
+  virt_net:
+    command: facts
+
+- name: Tear down libvirt's default network
+  when: ansible_libvirt_networks["default"] is defined
+  virt_net:
+    command: "{{ item }}"
+    name: "default"
+  with_items:
+    - destroy
+    - undefine
+
+# note, this isn't idempotent, so may need manual fixing if it changes
+- name: Define libvirt networks settings (IP/DHCP/DNS)
+  when: "{{ ansible_libvirt_networks[item.name] is not defined }}"
+  virt_net:
+    name: "{{ item.name }}"
+    command: define
+    xml: "{{ lookup('template', 'virt_net.xml.j2') }}"
+  with_items: "{{ virt_nets }}"
+
+- name: Collect libvirt network facts after defining new network
+  virt_net:
+    command: facts
+
+- name: Start libvirt networks
+  when: "{{ ansible_libvirt_networks[item.name].state != 'active' }}"
+  virt_net:
+    name: "{{ item.name }}"
+    command: create
+    autostart: yes
+  with_items: "{{ virt_nets }}"
+
+- name: Have libvirt networks automatically start on reboot
+  when: "{{ ansible_libvirt_networks[item.name].autostart != 'yes' }}"
+  virt_net:
+    name: "{{ item.name }}"
+    autostart: yes
+  with_items: "{{ virt_nets }}"
+
diff --git a/ansible/roles/virt-nets/templates/virt_net.xml.j2 b/ansible/roles/virt-nets/templates/virt_net.xml.j2
new file mode 100644
index 0000000..83e95ef
--- /dev/null
+++ b/ansible/roles/virt-nets/templates/virt_net.xml.j2
@@ -0,0 +1,13 @@
+<network>
+  <name>{{ item.name }}</name>
+  <bridge name="br-{{ item.name }}"/>
+  <forward/>
+  <ip address="{{ item.ipv4_prefix }}.1" netmask="255.255.255.0">
+    <dhcp>
+      <range start="{{ item.ipv4_prefix }}.2" end="{{ item.ipv4_prefix }}.254"/>
+{% for node in item.nodes %}
+      <host name='{{ node.name }}' ip='{{ item.ipv4_prefix }}.{{ node.ipv4_last_octet }}'/>
+{% endfor %}
+    </dhcp>
+  </ip>
+</network>
diff --git a/config/opencloud_in_a_box.yaml b/config/opencloud_in_a_box.yaml
new file mode 100644
index 0000000..3f99ffc
--- /dev/null
+++ b/config/opencloud_in_a_box.yaml
@@ -0,0 +1,28 @@
+---
+# Opencloud-in-a-Box configuration
+
+public_network: cordpub
+public_network_cidr: "10.230.100.0/24"
+
+mgmt_network: cordmgmt
+
+virt_nets:
+  - name: cordpub
+    ipv4_prefix: 10.230.100
+    nodes:
+      - name: head1
+        ipv4_last_octet: 100
+      - name: compute1
+        ipv4_last_octet: 101
+      - name: compute2
+        ipv4_last_octet: 102
+  - name: cordmgmt
+    ipv4_prefix: 192.168.200
+    nodes:
+      - name: head1
+        ipv4_last_octet: 10
+      - name: compute1
+        ipv4_last_octet: 20
+      - name: compute2
+        ipv4_last_octet: 21
+
diff --git a/scripts/bootstrap_ansible.sh b/scripts/bootstrap_ansible.sh
index 6c7db5b..2f1b4b5 100755
--- a/scripts/bootstrap_ansible.sh
+++ b/scripts/bootstrap_ansible.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
 #
 # Copyright 2012 the original author or authors.
 #
@@ -17,8 +17,8 @@
 
 set -e
 
-echo "Installing Ansible..."
-apt-get install -y software-properties-common python-netaddr apt-transport-https 
+echo "Installing Ansible using APT (PPA)..."
+apt-get install -y software-properties-common python-netaddr apt-transport-https
 apt-add-repository ppa:ansible/ansible
 apt-get update
 apt-get install -y ansible
diff --git a/scripts/cord-in-a-box.sh b/scripts/cord-in-a-box.sh
index 17e3b65..09b29fd 100755
--- a/scripts/cord-in-a-box.sh
+++ b/scripts/cord-in-a-box.sh
@@ -1,15 +1,21 @@
 #!/usr/bin/env bash
+# cord-in-a-box.sh
 
 set -e -x
 
+# start time, used to name logfiles
+START_T=$(date -u "+%Y%m%d_%H%M%SZ")
+
+# Paths
 CORDDIR=~/cord
 VMDIR=/cord/build/
 CONFIG=config/cord_in_a_box.yml
 SSHCONFIG=~/.ssh/config
+VAGRANT_CWD=${CORDDIR}/build/targets/cord-in-a-box
 
-# For CORD version
+# CORD versioning
 REPO_BRANCH="master"
-VERSION_STRING="CiaB development version"
+VERSION_STRING="CiaB Devel"
 
 function finish {
     EXIT=$?
@@ -40,7 +46,9 @@
   then
     echo "Destroying all Vagrant VMs"
     cd $CORDDIR/build
-    for i in `seq 12`; do sudo su $USER -c 'vagrant destroy' && break; done
+    for i in `seq 12`; do
+      sudo VAGRANT_CWD=$VAGRANT_CWD vagrant destroy && break
+    done
   fi
 
   echo "Removing $CORDDIR"
@@ -49,39 +57,65 @@
 }
 
 function bootstrap() {
+
   echo "Generating build id"
   rm -f /tmp/cord-build-version
-
   dd bs=18 count=1 if=/dev/urandom | base64 | tr +/ _. > /tmp/cord-build
-  cd ~
-  sudo apt-get update
-  [ -e vagrant_1.8.5_x86_64.deb ] || wget https://releases.hashicorp.com/vagrant/1.8.5/vagrant_1.8.5_x86_64.deb
-  dpkg -l vagrant || sudo dpkg -i vagrant_1.8.5_x86_64.deb
-  sudo apt-get -y install qemu-kvm libvirt-bin libvirt-dev curl nfs-kernel-server git build-essential python-pip
-  sudo pip install pyparsing python-logstash mixpanel
 
+  if [ ! -x "/usr/local/bin/repo" ]
+  then
+    echo "Installing repo..."
+    REPO_SHA256SUM="e147f0392686c40cfd7d5e6f332c6ee74c4eab4d24e2694b3b0a0c037bf51dc5" # not versioned...
+    curl -o /tmp/repo https://storage.googleapis.com/git-repo-downloads/repo
+    echo "$REPO_SHA256SUM  /tmp/repo" | sha256sum -c -
+    sudo mv /tmp/repo /usr/local/bin/repo
+    sudo chmod a+x /usr/local/bin/repo
+  fi
+
+  if [ ! -x "/usr/bin/vagrant" ]
+  then
+    echo "Installing vagrant and associated tools..."
+    VAGRANT_SHA256SUM="faff6befacc7eed3978b4b71f0dbb9c135c01d8a4d13236bda2f9ed53482d2c4"  # version 1.9.3
+    curl -o /tmp/vagrant.deb https://releases.hashicorp.com/vagrant/1.9.3/vagrant_1.9.3_x86_64.deb
+    echo "$VAGRANT_SHA256SUM  /tmp/vagrant.deb" | sha256sum -c -
+    sudo apt-get update
+    sudo dpkg -i /tmp/vagrant.deb
+    sudo apt-get -y install qemu-kvm libvirt-bin libvirt-dev curl nfs-kernel-server git build-essential python-pip
+    sudo adduser $USER libvirtd
+    sudo pip install pyparsing python-logstash mixpanel
+  fi
+
+  echo "Installing vagrant plugins..."
+  vagrant plugin list | grep vagrant-libvirt || vagrant plugin install vagrant-libvirt --plugin-version 0.0.35
+  vagrant plugin list | grep vagrant-mutate || vagrant plugin install vagrant-mutate
+
+  add_box ubuntu/trusty64
+
+  echo "Creating SSH key..."
   [ -e ~/.ssh/id_rsa ] || ssh-keygen -t rsa -N "" -f ~/.ssh/id_rsa
 
-  sudo adduser $USER libvirtd
-
-  sudo curl -o /usr/local/bin/repo https://storage.googleapis.com/git-repo-downloads/repo
-  sudo chmod a+x /usr/local/bin/repo
-
   if [ ! -d "$CORDDIR" ]
   then
+    echo "Downloading CORD/XOS..."
+
+    if [ ! -e "~/.gitconfig" ]
+    then
+      echo "No ~/.gitconfig, setting testing defaults"
+      git config --global user.name 'Test User'
+      git config --global user.email 'test@null.com'
+      git config --global color.ui false
+    fi
+
+    # make sure we can find gerrit.opencord.org as DNS failures will fail the build
+    dig +short gerrit.opencord.org || (echo "ERROR: gerrit.opencord.org can't be looked up in DNS" && exit 1)
+
     mkdir $CORDDIR && cd $CORDDIR
-
-
-    git config --global user.name 'Test User'
-    git config --global user.email 'test@null.com'
-    git config --global color.ui false
-
-    repo init -u https://gerrit.opencord.org/manifest -b $REPO_BRANCH -g build,onos,orchestration,voltha
+    repo init -u https://gerrit.opencord.org/manifest -b master -g build,onos,orchestration,voltha
     repo sync
 
     # check out gerrit branches using repo
     for gerrit_branch in ${GERRIT_BRANCHES[@]}; do
-      echo "checking out opencord gerrit branch: $gerrit_branch"
+      echo "Checking out opencord gerrit branch: $gerrit_branch"
       repo download ${gerrit_branch/:/ }
     done
   fi
@@ -89,11 +123,6 @@
   exec > >(tee -i $CORDDIR/install.out)
   exec 2>&1
 
-  cd $CORDDIR/build
-  vagrant plugin list | grep vagrant-libvirt || vagrant plugin install vagrant-libvirt --plugin-version 0.0.35
-  vagrant plugin list | grep vagrant-mutate || vagrant plugin install vagrant-mutate
-  add_box ubuntu/trusty64
-
   # Start tracking failures from this point
   trap finish EXIT
 
@@ -158,13 +187,17 @@
 }
 
 function vagrant_vms_up() {
+
+  echo "Bringing up CORD-in-a-Box Vagrant VM's..."
   cd $CORDDIR/build
 
-  sudo su $USER -c 'vagrant up corddev prod --provider libvirt'
+  sudo VAGRANT_CWD=$VAGRANT_CWD vagrant up corddev prod --provider libvirt
 
   # This is a workaround for a weird issue with ARP cache timeout breaking 'vagrant ssh'
   # It allows SSH'ing to the machine via 'ssh corddev'
-  sudo su $USER -c "vagrant ssh-config corddev prod > $SSHCONFIG"
+  sudo VAGRANT_CWD=$VAGRANT_CWD vagrant ssh-config corddev prod > $SSHCONFIG
+
+  sudo chown -R ${USER} ${VAGRANT_CWD}/.vagrant
 
   scp ~/.ssh/id_rsa* corddev:.ssh
   ssh corddev "chmod go-r ~/.ssh/id_rsa"
@@ -209,10 +242,10 @@
 
   if [[ $FABRIC -ne 0 ]]
   then
-      sudo su $USER -c "FABRIC=$FABRIC vagrant up leaf-1 leaf-2 spine-1 spine-2 --provider libvirt"
+      sudo VAGRANT_CWD=$VAGRANT_CWD FABRIC=$FABRIC vagrant up leaf-1 leaf-2 spine-1 spine-2 --provider libvirt
   else
       # Linux bridging seems to be having issues with two spine switches
-      sudo su $USER -c "FABRIC=$FABRIC vagrant up leaf-1 leaf-2 spine-1 --provider libvirt"
+      sudo VAGRANT_CWD=$VAGRANT_CWD FABRIC=$FABRIC vagrant up leaf-1 leaf-2 spine-1 --provider libvirt
   fi
 
   # Turn off MAC learning on "links" -- i.e., bridges created by libvirt.
@@ -234,7 +267,7 @@
   echo add_compute_node: $1 $2
 
   cd $CORDDIR/build
-  sudo su $USER -c "vagrant up $1 --provider libvirt"
+  sudo VAGRANT_CWD=$VAGRANT_CWD vagrant up $1 --provider libvirt
 
   # Set up power cycling for the compute node and wait for it to be provisioned
   ssh prod "cd /cord/build/ansible; ansible-playbook maas-provision.yml --extra-vars \"maas_user=maas vagrant_name=$2\""
@@ -347,7 +380,7 @@
 for i in `seq 1 $NUM_COMPUTE_NODES`;
 do
    echo adding the compute node: compute-node-$i
-   add_compute_node compute-node-$i build_compute-node-$i
+   add_compute_node compute-node-$i cord-in-a-box_compute-node-$i
 done
 echo "==> Adding compute nodes: Complete"
 
diff --git a/scripts/opencloud-in-a-box.sh b/scripts/opencloud-in-a-box.sh
new file mode 100755
index 0000000..ee2bd5d
--- /dev/null
+++ b/scripts/opencloud-in-a-box.sh
@@ -0,0 +1,244 @@
+#!/usr/bin/env bash
+# opencloud-in-a-box.sh
+
+set -e -x
+
+# start time, used to name logfiles
+START_T=$(date -u "+%Y%m%d_%H%M%SZ")
+
+# Paths
+CORDDIR=~/cord
+CONFIG=${CORDDIR}/config/opencloud_in_a_box.yml
+SSHCONFIG=~/.ssh/config
+VAGRANT_CWD=${CORDDIR}/build/targets/opencloud-in-a-box
+
+# CORD versioning
+REPO_BRANCH="master"
+VERSION_STRING="OpenCloud Devel"
+
+function add_box() {
+  echo "Downloading image: $1"
+  vagrant box list | grep $1 | grep virtualbox || vagrant box add $1
+  vagrant box list | grep $1 | grep libvirt || vagrant mutate $1 libvirt --input-provider virtualbox
+}
+
+function run_stage {
+    echo "==> "$1": Starting"
+    $1
+    echo "==> "$1": Complete"
+}
+
+function cleanup_from_previous_test() {
+  echo "## Cleanup ##"
+
+  if [ -d $CORDDIR/build ]
+  then
+    echo "Destroying all Vagrant VMs"
+    cd $CORDDIR/build
+    sudo VAGRANT_CWD=$VAGRANT_CWD vagrant destroy
+  fi
+
+  echo "Removing $CORDDIR"
+  cd ~
+  rm -rf $CORDDIR
+}
+
+function bootstrap() {
+
+  if [ ! -x "/usr/bin/ansible" ]
+  then
+    echo "Installing Ansible..."
+    sudo apt-get update
+    sudo apt-get install -y software-properties-common apt-transport-https
+    sudo apt-add-repository -y ppa:ansible/ansible  # latest supported version
+    sudo apt-get update
+    sudo apt-get install -y ansible python-netaddr
+  fi
+
+  if [ ! -x "/usr/local/bin/repo" ]
+  then
+    echo "Installing repo..."
+    REPO_SHA256SUM="e147f0392686c40cfd7d5e6f332c6ee74c4eab4d24e2694b3b0a0c037bf51dc5" # not versioned...
+    curl -o /tmp/repo https://storage.googleapis.com/git-repo-downloads/repo
+    echo "$REPO_SHA256SUM  /tmp/repo" | sha256sum -c -
+    sudo mv /tmp/repo /usr/local/bin/repo
+    sudo chmod a+x /usr/local/bin/repo
+  fi
+
+  if [ ! -x "/usr/bin/vagrant" ]
+  then
+    echo "Installing vagrant and associated tools..."
+    VAGRANT_SHA256SUM="52ebd6aa798582681d0f1e008982c709136eeccd668a8e8be4d48a1f632de7b8"  # version 1.9.2
+    curl -o /tmp/vagrant.deb https://releases.hashicorp.com/vagrant/1.9.2/vagrant_1.9.2_x86_64.deb
+    echo "$VAGRANT_SHA256SUM  /tmp/vagrant.deb" | sha256sum -c -
+    sudo dpkg -i /tmp/vagrant.deb
+    sudo apt-get -y install qemu-kvm libvirt-bin libvirt-dev curl nfs-kernel-server git build-essential python-pip
+    sudo adduser $USER libvirtd
+    sudo pip install pyparsing python-logstash
+
+    run_stage cloudlab_setup
+
+    echo "Installing vagrant plugins..."
+    vagrant plugin list | grep vagrant-libvirt || vagrant plugin install vagrant-libvirt --plugin-version 0.0.35
+    vagrant plugin list | grep vagrant-mutate || vagrant plugin install vagrant-mutate
+
+    add_box ubuntu/trusty64
+  fi
+
+  if [ ! -d "$CORDDIR" ]
+  then
+    echo "Downloading CORD/XOS..."
+
+    if [ ! -e "~/.gitconfig" ]
+    then
+      echo "No ~/.gitconfig, setting testing defaults"
+      git config --global user.name 'Test User'
+      git config --global user.email 'test@null.com'
+      git config --global color.ui false
+    fi
+
+    # make sure we can find gerrit.opencord.org as DNS failures will fail the build
+    dig +short gerrit.opencord.org || (echo "ERROR: gerrit.opencord.org can't be looked up in DNS" && exit 1)
+
+    mkdir $CORDDIR && cd $CORDDIR
+    repo init -u https://gerrit.opencord.org/manifest -b master -g build,onos,orchestration,voltha
+    repo sync
+
+    # check out gerrit branches using repo
+    for gerrit_branch in ${GERRIT_BRANCHES[@]}; do
+      echo "Checking out opencord gerrit branch: $gerrit_branch"
+      repo download ${gerrit_branch/:/ }
+    done
+  fi
+}
+
+function cloudlab_setup() {
+
+  # Don't do anything if not a CloudLab node
+  [ ! -d /usr/local/etc/emulab ] && return
+
+  # The watchdog will sometimes reset groups, turn it off
+  if [ -e /usr/local/etc/emulab/watchdog ]
+  then
+    sudo /usr/bin/perl -w /usr/local/etc/emulab/watchdog stop
+    sudo mv /usr/local/etc/emulab/watchdog /usr/local/etc/emulab/watchdog-disabled
+  fi
+
+  # Mount extra space, if haven't already
+  if [ ! -d /mnt/extra ]
+  then
+    sudo mkdir -p /mnt/extra
+
+    # for NVME SSD on Utah Cloudlab, not supported by mkextrafs
+    if $(df | grep -q nvme0n1p1) && [ -e /usr/testbed/bin/mkextrafs ]
+    then
+      # set partition type of 4th partition to Linux, ignore errors
+      echo -e "t\n4\n82\np\nw\nq" | sudo fdisk /dev/nvme0n1 || true
+
+      sudo mkfs.ext4 /dev/nvme0n1p4
+      echo "/dev/nvme0n1p4 /mnt/extra/ ext4 defaults 0 0" | sudo tee -a /etc/fstab
+      sudo mount /mnt/extra
+      mount | grep nvme0n1p4 || (echo "ERROR: NVME mkfs/mount failed, exiting!" && exit 1)
+
+    elif [ -e /usr/testbed/bin/mkextrafs ]  # if on Clemson/Wisconsin Cloudlab
+    then
+      # Sometimes this command fails on the first try
+      sudo /usr/testbed/bin/mkextrafs -r /dev/sdb -qf "/mnt/extra/" || sudo /usr/testbed/bin/mkextrafs -r /dev/sdb -qf "/mnt/extra/"
+
+      # Check that the mount succeeded (sometimes mkextrafs succeeds but device not mounted)
+      mount | grep sdb || (echo "ERROR: mkextrafs failed, exiting!" && exit 1)
+    fi
+  fi
+
+  # replace /var/lib/libvirt/images with a symlink
+  [ -d /var/lib/libvirt/images/ ] && [ ! -h /var/lib/libvirt/images ] && sudo rmdir /var/lib/libvirt/images
+  sudo mkdir -p /mnt/extra/libvirt_images
+
+  if [ ! -e /var/lib/libvirt/images ]
+  then
+    sudo ln -s /mnt/extra/libvirt_images /var/lib/libvirt/images
+  fi
+}
+
+function vagrant_vms_up() {
+
+  # vagrant-libvirt 0.0.35 fails with libvirt networks created by others
+  # echo "Configuring libvirt networking..."
+  # cd ${CORDDIR}/build/ansible
+  # ansible-playbook opencloud-in-a-box-playbook.yml
+
+  echo "Bringing up OpenCloud-in-a-Box Vagrant VM's..."
+  cd $CORDDIR/build
+  sudo VAGRANT_CWD=$VAGRANT_CWD vagrant up head1 compute1 compute2 --provider libvirt
+
+  # This is a workaround for a weird issue with ARP cache timeout breaking 'vagrant ssh'
+  # It allows SSH'ing to the machine via 'ssh <machinename>'
+  echo "Configuring SSH for VM's..."
+  sudo VAGRANT_CWD=$VAGRANT_CWD vagrant ssh-config head1 compute1 compute2 > $SSHCONFIG
+
+  sudo chown -R ${USER} ${VAGRANT_CWD}/.vagrant
+}
+
+function opencloud_buildhost_prep() {
+
+  echo "Preparing build tools..."
+  cd ${CORDDIR}/build/platform-install
+  ansible-playbook -i inventory/opencloud opencloud-prep-playbook.yml
+}
+
+# Parse options
+GERRIT_BRANCHES=
+RUN_TEST=0
+SETUP_ONLY=0
+CLEANUP=0
+
+while getopts "b:chsv" opt; do
+  case ${opt} in
+    b ) GERRIT_BRANCHES+=("$OPTARG")
+      ;;
+    c ) CLEANUP=1
+      ;;
+    h ) echo "Usage:"
+      echo "    $0                install OpenCloud-in-a-Box [default]"
+      echo "    $0 -b <project:changeset/revision>  checkout a changesets from gerrit. Can"
+      echo "                      be used multiple times."
+      echo "    $0 -c             cleanup from previous test"
+      echo "    $0 -h             display this help message"
+      echo "    $0 -s             run initial setup phase only (don't start building CORD)"
+      echo "    $0 -v             print CiaB version and exit"
+      exit 0
+      ;;
+    s ) SETUP_ONLY=1
+      ;;
+    v ) echo "$VERSION_STRING ($REPO_BRANCH branch)"
+      exit 0
+      ;;
+    \? ) echo "Invalid option: -$OPTARG"
+      exit 1
+      ;;
+  esac
+done
+
+# What to do
+if [[ $CLEANUP -eq 1 ]]
+then
+  run_stage cleanup_from_previous_test
+fi
+
+echo ""
+echo "Preparing to install $VERSION_STRING ($REPO_BRANCH branch)"
+echo ""
+
+run_stage bootstrap
+
+
+if [[ $SETUP_ONLY -ne 0 ]]
+then
+  echo "Finished build environment setup, exiting..."
+  exit 0
+fi
+
+run_stage vagrant_vms_up
+run_stage opencloud_buildhost_prep
+
+exit 0
diff --git a/Vagrantfile b/targets/cord-in-a-box/Vagrantfile
similarity index 88%
rename from Vagrantfile
rename to targets/cord-in-a-box/Vagrantfile
index d7401ad..103710d 100644
--- a/Vagrantfile
+++ b/targets/cord-in-a-box/Vagrantfile
@@ -1,12 +1,14 @@
 # -*- mode: ruby -*-
 # vi: set ft=ruby :
 
+$cordpath = "../../.."
+
 Vagrant.configure(2) do |config|
 
   if (/cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM) != nil
-    config.vm.synced_folder "..", "/cord", mount_options: ["dmode=700,fmode=600"]
+    config.vm.synced_folder $cordpath, "/cord", mount_options: ["dmode=700,fmode=600"]
   else
-    config.vm.synced_folder "..", "/cord"
+    config.vm.synced_folder $cordpath, "/cord"
   end
   config.vm.synced_folder '.', '/vagrant', disabled: true
 
@@ -15,14 +17,14 @@
     d.vm.box = "ubuntu/trusty64"
     d.vm.hostname = "corddev"
     d.vm.network "private_network", ip: "10.100.198.200"
-    d.vm.provision :shell, path: "scripts/bootstrap_ansible.sh"
+    d.vm.provision :shell, path: $cordpath + "/build/scripts/bootstrap_ansible.sh"
     d.vm.provision :shell, inline: "PYTHONUNBUFFERED=1 ansible-playbook /cord/build/ansible/corddev.yml -c local"
     d.vm.provider "virtualbox" do |v|
       v.memory = 2048
     end
     d.vm.provider :libvirt do |v, override|
       v.memory = 2048
-      override.vm.synced_folder "..", "/cord", type: "nfs"
+      override.vm.synced_folder $cordpath, "/cord", type: "nfs"
     end
   end
 
@@ -46,7 +48,7 @@
         libvirt__network_name: "head-node-leaf-1",
         libvirt__forward_mode: "none",
         libvirt__dhcp_enabled: false
-    d.vm.provision :shell, path: "scripts/bootstrap_ansible.sh"
+    d.vm.provision :shell, path: $cordpath + "/build/scripts/bootstrap_ansible.sh"
     d.vm.provision :shell, inline: "PYTHONUNBUFFERED=1 ansible-playbook /cord/build/ansible/prod.yml -c local"
     d.vm.provision :shell, inline: "PYTHONUNBUFFERED=1 cd /cord/build/platform-install; ansible-playbook -i inventory/head-localhost deploy-elasticstack-playbook.yml"
     d.vm.provider "virtualbox" do |v|
@@ -56,7 +58,7 @@
       v.memory = 24576
       v.cpus = 8
       v.storage :file, :size => '100G', :type => 'qcow2'
-      override.vm.synced_folder "..", "/cord", type: "nfs"
+      override.vm.synced_folder $cordpath, "/cord", type: "nfs"
       override.vm.provision :shell, inline: "PYTHONUNBUFFERED=1 ansible-playbook /cord/build/ansible/add-extra-drive.yml -c local"
     end
   end
@@ -70,7 +72,7 @@
         virtualbox__intnet: "cord-fabric-network",
         libvirt__network_name: "cord-fabric-network",
         mac: "cc37ab000001"
-    s.vm.provision :shell, path: "scripts/bootstrap_ansible.sh"
+    s.vm.provision :shell, path: $cordpath + "/build/scripts/bootstrap_ansible.sh"
     s.vm.provision :shell, inline: "PYTHONUNBUFFERED=1 ansible-playbook /cord/build/ansible/fakeswitch.yml -c local"
     s.vm.provider "virtualbox" do |v|
       v.memory = 1048
@@ -116,9 +118,9 @@
       libvirt__network_name: "leaf-1-spine-2",
       libvirt__forward_mode: "none",
       libvirt__dhcp_enabled: false
-    s.vm.provision :shell, path: "scripts/bootstrap_ansible.sh"
+    s.vm.provision :shell, path: $cordpath + "/build/scripts/bootstrap_ansible.sh"
     if (ENV['FABRIC'] == "1")
-      s.vm.provision :shell, path: "scripts/install.sh", args: "-3f"
+      s.vm.provision :shell, path: $cordpath + "/build/scripts/install.sh", args: "-3f"
       s.vm.provision :shell, inline: "PYTHONUNBUFFERED=1 ansible-playbook /cord/build/ansible/leafswitch.yml -c local -e 'fabric=true net_prefix=10.6.1'"
     else
       s.vm.provision :shell, inline: "PYTHONUNBUFFERED=1 ansible-playbook /cord/build/ansible/leafswitch.yml -c local -e 'net_prefix=10.6.1'"
@@ -126,7 +128,7 @@
     s.vm.provider :libvirt do |v, override|
         v.memory = 512
         v.cpus = 1
-        override.vm.synced_folder "..", "/cord", type: "nfs"
+        override.vm.synced_folder $cordpath, "/cord", type: "nfs"
     end
     s.vm.provider "virtualbox" do |v, override|
         v.memory = 512
@@ -172,9 +174,9 @@
       libvirt__network_name: "leaf-2-spine-2",
       libvirt__forward_mode: "none",
       libvirt__dhcp_enabled: false
-    s.vm.provision :shell, path: "scripts/bootstrap_ansible.sh"
+    s.vm.provision :shell, path: $cordpath + "/build/scripts/bootstrap_ansible.sh"
     if (ENV['FABRIC'] == "1")
-      s.vm.provision :shell, path: "scripts/install.sh", args: "-3f"
+      s.vm.provision :shell, path: $cordpath + "/build/scripts/install.sh", args: "-3f"
       s.vm.provision :shell, inline: "PYTHONUNBUFFERED=1 ansible-playbook /cord/build/ansible/leafswitch.yml -c local -e 'fabric=true net_prefix=10.6.1'"
     else
       s.vm.provision :shell, inline: "PYTHONUNBUFFERED=1 ansible-playbook /cord/build/ansible/leafswitch.yml -c local -e 'net_prefix=10.6.1'"
@@ -182,7 +184,7 @@
     s.vm.provider :libvirt do |v, override|
         v.memory = 512
         v.cpus = 1
-        override.vm.synced_folder "..", "/cord", type: "nfs"
+        override.vm.synced_folder $cordpath, "/cord", type: "nfs"
     end
     s.vm.provider "virtualbox" do |v, override|
         v.memory = 512
@@ -214,9 +216,9 @@
       libvirt__network_name: "leaf-2-spine-1",
       libvirt__forward_mode: "none",
       libvirt__dhcp_enabled: false
-    s.vm.provision :shell, path: "scripts/bootstrap_ansible.sh"
+    s.vm.provision :shell, path: $cordpath + "/build/scripts/bootstrap_ansible.sh"
     if (ENV['FABRIC'] == "1")
-      s.vm.provision :shell, path: "scripts/install.sh", args: "-3f"
+      s.vm.provision :shell, path: $cordpath + "/build/scripts/install.sh", args: "-3f"
       s.vm.provision :shell, inline: "PYTHONUNBUFFERED=1 ansible-playbook /cord/build/ansible/spineswitch.yml -c local -e 'fabric=true net_prefix=10.6.1'"
     else
       s.vm.provision :shell, inline: "PYTHONUNBUFFERED=1 ansible-playbook /cord/build/ansible/spineswitch.yml -c local -e 'net_prefix=10.6.1'"
@@ -224,7 +226,7 @@
     s.vm.provider :libvirt do |v, override|
         v.memory = 512
         v.cpus = 1
-        override.vm.synced_folder "..", "/cord", type: "nfs"
+        override.vm.synced_folder $cordpath, "/cord", type: "nfs"
     end
     s.vm.provider "virtualbox" do |v, override|
         v.memory = 512
@@ -256,9 +258,9 @@
       libvirt__network_name: "leaf-2-spine-2",
       libvirt__forward_mode: "none",
       libvirt__dhcp_enabled: false
-    s.vm.provision :shell, path: "scripts/bootstrap_ansible.sh"
+    s.vm.provision :shell, path: $cordpath + "/build/scripts/bootstrap_ansible.sh"
     if (ENV['FABRIC'] == "1")
-      s.vm.provision :shell, path: "scripts/install.sh", args: "-3f"
+      s.vm.provision :shell, path: $cordpath + "/build/scripts/install.sh", args: "-3f"
       s.vm.provision :shell, inline: "PYTHONUNBUFFERED=1 ansible-playbook /cord/build/ansible/spineswitch.yml -c local -e 'fabric=true net_prefix=10.6.1'"
     else
       s.vm.provision :shell, inline: "PYTHONUNBUFFERED=1 ansible-playbook /cord/build/ansible/spineswitch.yml -c local -e 'net_prefix=10.6.1'"
@@ -266,7 +268,7 @@
     s.vm.provider :libvirt do |v, override|
         v.memory = 512
         v.cpus = 1
-        override.vm.synced_folder "..", "/cord", type: "nfs"
+        override.vm.synced_folder $cordpath, "/cord", type: "nfs"
     end
     s.vm.provider "virtualbox" do |v, override|
         v.memory = 512
@@ -279,7 +281,7 @@
     d.ssh.forward_agent = true
     d.vm.hostname = "testbox"
     d.vm.network "private_network", ip: "10.0.3.100", lxc__bridge_name: 'lxcbr0'
-    d.vm.provision :shell, path: "scripts/bootstrap_ansible.sh"
+    d.vm.provision :shell, path: $cordpath + "/build/scripts/bootstrap_ansible.sh"
     d.vm.provision :shell, inline: "PYTHONUNBUFFERED=1 ansible-playbook /cord/build/ansible/corddev.yml -c local"
     config.vm.provider :lxc do |lxc|
         # Same effect as 'customize ["modifyvm", :id, "--memory", "1024"]' for VirtualBox
diff --git a/targets/opencloud-in-a-box/Vagrantfile b/targets/opencloud-in-a-box/Vagrantfile
new file mode 100644
index 0000000..83c9ce3
--- /dev/null
+++ b/targets/opencloud-in-a-box/Vagrantfile
@@ -0,0 +1,66 @@
+# -*- mode: ruby -*-
+# vi: set ft=ruby :
+#
+# OpenCloud-in-a-Box Vagrantfile
+require 'yaml'
+settings = YAML.load_file('config/opencloud_in_a_box.yaml')
+
+Vagrant.configure(2) do |config|
+
+  config.vm.box = "ubuntu/trusty64"
+
+  config.vm.define "head1" do |h|
+    h.vm.hostname = "head1"
+    h.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: '*'
+    h.vm.provider :libvirt do |v|
+      v.memory = 16384
+      v.cpus = 8
+      v.machine_virtual_size = 100
+      v.management_network_name = settings['public_network_name'] # public network
+      v.management_network_address = settings['public_network_cidr']
+    end
+    h.vm.network "private_network", # management network, eth1
+      ip: "0.1.1.0", # not used, ignore
+      auto_config: false,
+      libvirt__network_name: settings['mgmt_network'],
+      libvirt__forward_mode: "none",
+      libvirt__dhcp_enabled: false
+  end
+
+  config.vm.define "compute1" do |c|
+    c.vm.hostname = "compute1"
+    c.vm.provider :libvirt do |v|
+      v.memory = 8192
+      v.cpus = 4
+      v.machine_virtual_size = 50
+      v.nested = true
+      v.management_network_name = settings['public_network_name'] # public network
+      v.management_network_address = settings['public_network_cidr']
+    end
+    c.vm.network "private_network", # management network, eth1
+      ip: "0.1.1.0",
+      auto_config: false,
+      libvirt__network_name: settings['mgmt_network'],
+      libvirt__forward_mode: "none",
+      libvirt__dhcp_enabled: false
+  end
+
+  config.vm.define "compute2" do |c|
+    c.vm.hostname = "compute2"
+    c.vm.provider :libvirt do |v|
+      v.memory = 8192
+      v.cpus = 4
+      v.machine_virtual_size = 50
+      v.nested = true
+      v.management_network_name = settings['public_network_name'] # public network
+      v.management_network_address = settings['public_network_cidr']
+    end
+    c.vm.network "private_network", # management network, eth1
+      ip: "0.1.1.0",
+      auto_config: false,
+      libvirt__network_name: settings['mgmt_network'],
+      libvirt__forward_mode: "none",
+      libvirt__dhcp_enabled: false
+  end
+
+end