Start of the CORD configuration
diff --git a/cord-hosts b/cord-hosts
new file mode 100644
index 0000000..3a85337
--- /dev/null
+++ b/cord-hosts
@@ -0,0 +1,7 @@
+head    ansible_ssh_host=node1.juju2.xos-pg0.clemson.cloudlab.us
+
+[compute]
+node2.juju2.xos-pg0.clemson.cloudlab.us
+
+[all:vars]
+cloudlab=true
diff --git a/cord-post-install.yml b/cord-post-install.yml
new file mode 100644
index 0000000..a46bfd9
--- /dev/null
+++ b/cord-post-install.yml
@@ -0,0 +1,23 @@
+# Play: Create credentials, set up some basic OpenStack
+- hosts: head
+  sudo: no
+  tasks:
+
+  - shell: uvt-kvm ip keystone
+    register: keystone_ip
+
+  - name: Create credentials
+    template: src=templates/admin-openrc-cord.sh.j2
+     dest={{ ansible_env['PWD'] }}/admin-openrc-cord.sh
+
+  - name: Copy credentials to nova-cloud-controller
+    shell: "scp admin-openrc.sh ubuntu@nova-cloud-controller:"
+
+  - name: Copy network setup script
+    sudo: yes
+    copy: src=scripts/network-setup.sh
+      dest=/usr/local/src/network-setup.sh
+      mode=0644
+
+  - name: Run network setup script
+    shell: ansible nova-cloud-controller -m script -u ubuntu -a "/usr/local/src/network-setup.sh"
diff --git a/cord-setup.yml b/cord-setup.yml
new file mode 100644
index 0000000..80e5a53
--- /dev/null
+++ b/cord-setup.yml
@@ -0,0 +1,213 @@
+---
+# Play: set up head node
+- hosts: head
+  sudo: yes
+  tasks:
+
+  - apt: name={{ item }} update_cache=yes
+    with_items:
+    - python-pycurl
+    - software-properties-common
+
+  - name: Add Juju repository
+    apt_repository: repo="ppa:juju/stable"
+
+  - name: Add Ansible repository
+    apt_repository: repo="ppa:ansible/ansible"
+
+  - name: Update Ansible cache
+    apt: update_cache=yes
+
+  - name: Install packages
+    apt: name={{ item }} state=latest
+    with_items:
+    - ansible
+    - uvtool
+    - git
+    - bzr
+    - juju-core
+    - juju-quickstart
+    - python-novaclient
+    - python-neutronclient
+    - python-keystoneclient
+    - python-glanceclient
+
+  - name: Get juju-ansible git repo
+    git: repo=https://github.com/cmars/juju-ansible.git
+      dest=/usr/local/src/juju-ansible
+
+  - name: Set up juju-ansible symlink
+    file: dest=/usr/local/bin/juju-ansible
+      src=/usr/local/src/juju-ansible/juju-ansible
+      state=link
+
+  - name: Set up juju-ansible-playbook symlink
+    file: dest=/usr/local/bin/juju-ansible-playbook
+      src=/usr/local/src/juju-ansible/juju-ansible
+      state=link
+
+  - name: Generate key to use in VMs
+    user: name={{ ansible_env['SUDO_USER'] }} generate_ssh_key=yes
+
+  - name: Get public key
+    shell: cat {{ ansible_env['PWD'] }}/.ssh/id_rsa.pub
+    register: sshkey
+
+  - name: Add key
+    authorized_key: user="{{ ansible_env['SUDO_USER'] }}"
+      key="{{ sshkey.stdout }}"
+
+  - name: (CloudLab) Set up extra disk space
+    shell: /usr/testbed/bin/mkextrafs -f /var/lib/uvtool/libvirt/images
+      creates=/var/lib/uvtool/libvirt/images/lost+found
+    when: cloudlab
+
+  - name: Add myself to libvirtd group
+    user: name={{ ansible_env['SUDO_USER'] }}
+      groups=libvirtd
+      append=yes
+
+  - name: Get trusty image for uvtool
+    shell: uvt-simplestreams-libvirt sync --source http://cloud-images.ubuntu.com/daily release=trusty arch=amd64
+
+# Play: create VMs to host OpenStack services
+- hosts: head
+  sudo: yes
+  tasks:
+  - name: Create VMs to host OpenCloud services
+    sudo: no
+    script: scripts/create-vms.sh
+
+  - include: tasks/vm-ips.yml
+
+  - name: Add VMs to /etc/hosts
+    template: src=templates/etc/hosts.j2
+      dest=/etc/hosts
+    notify:
+    - Reload dnsmasq
+
+  - name: Set up /etc/ansible/hosts
+    template: src=templates/etc/ansible/hosts.j2
+      dest=/etc/ansible/hosts
+
+  - name: Copy ansible.cfg to disable host key checking
+    sudo: no
+    copy: src=files/ansible.cfg
+      dest={{ ansible_env['PWD'] }}/.ansible.cfg
+
+  - name: Touch ~/.ssh/config
+    sudo: no
+    file: path={{ ansible_env['PWD'] }}/.ssh/config state=touch
+
+  - name: Disable host key checking in SSH
+    sudo: no
+    lineinfile: dest={{ ansible_env['PWD'] }}/.ssh/config
+      line="StrictHostKeyChecking no"
+
+  - name: Test that we can log into every VM
+    sudo: no
+    shell: ansible services -m ping -u ubuntu
+
+  handlers:
+  - name: Reload dnsmasq
+    shell: killall -HUP dnsmasq
+
+# Play: prepare compute nodes for installation
+- hosts: compute
+  sudo: yes
+  vars:
+    control_net: "{{ hostvars['head']['ansible_virbr0']['ipv4']['network'] }}/24"
+    gateway: "{{ hostvars['head']['ansible_default_ipv4']['address'] }}"
+  tasks:
+  - name: Install package needed by Juju
+    apt: name=python-yaml state=present
+
+  - name: Add key
+    authorized_key: user="{{ ansible_env['SUDO_USER'] }}"
+      key="{{ hostvars['head']['sshkey']['stdout'] }}"
+
+  - name: Add route via /etc/rc.local
+    template: src=templates/etc/rc.local.cloudlab
+      dest=/etc/rc.local
+      mode=0755
+    when: cloudlab
+    notify:
+    - run /etc/rc.local
+
+  - name: Add route via /etc/rc.local
+    template: src=templates/etc/rc.local
+      dest=/etc/rc.local
+      mode=0755
+    when: not cloudlab
+    notify:
+    - run /etc/rc.local
+
+  - name: Touch ~/.ssh/config
+    file: path=/var/lib/nova state=directory
+
+  - name: (CloudLab) Set up extra disk space
+    shell: /usr/testbed/bin/mkextrafs -f /var/lib/nova
+      creates=/var/lib/nova/lost+found
+    when: cloudlab
+
+  handlers:
+  - name: run /etc/rc.local
+    shell: /etc/rc.local
+
+# Play: Use libvirt hooks to set up iptables
+- hosts: head
+  sudo: yes
+  tasks:
+  - name: Enable port forwarding for services
+    copy: src=files/{{ item }}
+      dest={{ item }}
+      mode=0755
+    notify:
+    - reload libvirt config
+    - run qemu hook
+    with_items:
+#    - /etc/libvirt/hooks/daemon
+    - /etc/libvirt/hooks/qemu
+
+  handlers:
+  - name: reload libvirt config
+    shell: killall -HUP libvirtd
+
+  - name: run qemu hook
+    shell: /etc/libvirt/hooks/qemu start start
+
+# Play: Install services using Juju
+- hosts: head
+  vars:
+    charm_src: /usr/local/src/charms/trusty
+  tasks:
+  - name: Initialize Juju
+    sudo: no
+    shell: juju generate-config
+      creates={{ ansible_env['PWD'] }}/.juju/environments.yaml
+
+  - shell: uvt-kvm ip juju
+    register: juju_ip
+
+  - name: Juju config file
+    sudo: no
+    template: src=templates/environments.yaml.j2
+      dest={{ ansible_env['PWD'] }}/.juju/environments.yaml
+
+  - name: Bootstrap Juju
+    sudo: no
+    shell: juju bootstrap
+      creates={{ ansible_env['PWD'] }}/.juju/environments/manual.jenv
+
+  - name: Add virtual machines to Juju's control
+    script: scripts/juju-cord-setup.py
+
+  - name: Add compute nodes to Juju's control
+    shell: juju add-machine ssh:{{ item }}
+    with_items: "{{ groups['compute'] }}"
+
+  - name: Copy cord.yaml bundle
+    copy: src=cord.yaml dest={{ ansible_env['PWD'] }}/cord.yaml
+
+  - name: Deploy OpenStack services with Juju
+    shell: juju quickstart cord.yaml
diff --git a/cord.yaml b/cord.yaml
new file mode 100644
index 0000000..4332a95
--- /dev/null
+++ b/cord.yaml
@@ -0,0 +1,251 @@
+machines:
+  '1':
+    constraints: arch=amd64
+  '2':
+    constraints: arch=amd64
+  '3':
+    constraints: arch=amd64
+  '4':
+    constraints: arch=amd64
+  '5':
+    constraints: arch=amd64
+  '6':
+    constraints: arch=amd64
+  '7':
+    constraints: arch=amd64
+  '8':
+    constraints: arch=amd64
+  '9':
+    constraints: arch=amd64
+  '10':
+    constraints: arch=amd64
+  '11':
+    constraints: arch=amd64
+relations:
+- - nova-compute:amqp
+  - rabbitmq-server:amqp
+- - neutron-gateway:amqp
+  - rabbitmq-server:amqp
+- - keystone:shared-db
+  - mysql:shared-db
+- - nova-cloud-controller:identity-service
+  - keystone:identity-service
+- - glance:identity-service
+  - keystone:identity-service
+- - neutron-api:identity-service
+  - keystone:identity-service
+- - neutron-openvswitch:neutron-plugin-api
+  - neutron-api:neutron-plugin-api
+- - neutron-api:shared-db
+  - mysql:shared-db
+- - neutron-api:amqp
+  - rabbitmq-server:amqp
+- - neutron-gateway:neutron-plugin-api
+  - neutron-api:neutron-plugin-api
+- - glance:shared-db
+  - mysql:shared-db
+- - glance:amqp
+  - rabbitmq-server:amqp
+- - nova-cloud-controller:image-service
+  - glance:image-service
+- - nova-compute:image-service
+  - glance:image-service
+- - nova-cloud-controller:cloud-compute
+  - nova-compute:cloud-compute
+- - nova-cloud-controller:amqp
+  - rabbitmq-server:amqp
+- - nova-cloud-controller:quantum-network-service
+  - neutron-gateway:quantum-network-service
+- - nova-compute:neutron-plugin
+  - neutron-openvswitch:neutron-plugin
+- - neutron-openvswitch:amqp
+  - rabbitmq-server:amqp
+- - openstack-dashboard:identity-service
+  - keystone:identity-service
+- - nova-cloud-controller:shared-db
+  - mysql:shared-db
+- - nova-cloud-controller:neutron-api
+  - neutron-api:neutron-api
+- - ntp:juju-info
+  - nova-compute:juju-info
+- - ntp:juju-info
+  - neutron-gateway:juju-info
+- - nagios
+  - nrpe
+- - mysql:juju-info
+  - nrpe:general-info
+- - rabbitmq-server
+  - nrpe
+- - keystone
+  - nrpe
+- - glance
+  - nrpe
+- - nova-cloud-controller
+  - nrpe
+- - neutron-gateway
+  - nrpe
+- - openstack-dashboard
+  - nrpe
+- - neutron-api
+  - nrpe
+- - ceilometer
+  - mongodb
+- - ceilometer
+  - rabbitmq-server
+- - ceilometer:identity-service
+  - keystone:identity-service
+- - ceilometer:ceilometer-service
+  - ceilometer-agent:ceilometer-service
+- - ceilometer
+  - nagios
+- - ceilometer
+  - nrpe
+- - nova-compute
+  - nagios
+- - nova-compute
+  - nrpe
+- - nova-compute:nova-ceilometer
+  - ceilometer-agent:nova-ceilometer
+series: trusty
+services:
+  ceilometer:
+    charm: cs:trusty/ceilometer-17
+    num_units: 1
+    options:
+      openstack-origin: cloud:trusty-kilo
+    to:
+    - '8'
+  ceilometer-agent:
+    charm: cs:trusty/ceilometer-agent-13
+    num_units: 0
+  glance:
+    annotations:
+      gui-x: '250'
+      gui-y: '0'
+    charm: cs:trusty/glance-28
+    num_units: 1
+    options:
+      ha-mcastport: 5402
+      openstack-origin: cloud:trusty-kilo
+    to:
+    - '4'
+  keystone:
+    annotations:
+      gui-x: '500'
+      gui-y: '0'
+    charm: cs:trusty/keystone-31
+    num_units: 1
+    options:
+      admin-password: 'ADMIN_PASS'
+      ha-mcastport: 5403
+      https-service-endpoints: False
+      openstack-origin: cloud:trusty-kilo
+      use-https: no
+    to:
+    - '3'
+  mongodb:
+    charm: cs:trusty/mongodb-33
+    num_units: 1
+    to:
+    - '8'
+  mysql:
+    annotations:
+      gui-x: '0'
+      gui-y: '250'
+    charm: cs:trusty/percona-cluster-31
+    num_units: 1
+    options:
+      max-connections: 20000
+    to:
+    - '1'
+  nagios:
+    charm: cs:trusty/nagios-10
+    num_units: 1
+    to:
+    - '9'
+  neutron-api:
+    annotations:
+      gui-x: '500'
+      gui-y: '500'
+    charm: cs:trusty/neutron-api-21
+    num_units: 1
+    options:
+      #neutron-security-groups: true
+      openstack-origin: cloud:trusty-kilo
+    to:
+    - '10'
+  neutron-gateway:
+    annotations:
+      gui-x: '0'
+      gui-y: '0'
+    charm: cs:trusty/neutron-gateway-7
+    num_units: 1
+    options:
+      #ext-port: eth1
+      openstack-origin: cloud:trusty-kilo
+    to:
+    - '6'
+  neutron-openvswitch:
+    annotations:
+      gui-x: '250'
+      gui-y: '500'
+    charm: cs:trusty/neutron-openvswitch-13
+    num_units: 0
+  nova-cloud-controller:
+    annotations:
+      gui-x: '0'
+      gui-y: '500'
+    charm: cs:trusty/nova-cloud-controller-64
+    num_units: 1
+    options:
+      console-access-protocol: novnc
+      network-manager: Neutron
+      openstack-origin: cloud:trusty-kilo
+      #quantum-security-groups: 'yes'
+    to:
+    - '5'
+  nova-compute:
+    annotations:
+      gui-x: '250'
+      gui-y: '250'
+    charm: cs:trusty/nova-compute-33
+    num_units: 1
+    options:
+      config-flags: firewall_driver=nova.virt.firewall.NoopFirewallDriver
+      disable-neutron-security-groups: True
+      #enable-live-migration: true
+      #enable-resize: true
+      #migration-auth-type: ssh
+      openstack-origin: cloud:trusty-kilo
+      #manage-neutron-plugin-legacy-mode: False
+    to:
+    - '11'
+  nrpe:
+    charm: cs:trusty/nrpe-4
+    num_units: 0
+  ntp:
+    annotations:
+      gui-x: '1000'
+      gui-y: '0'
+    charm: cs:trusty/ntp-14
+    num_units: 0
+  openstack-dashboard:
+    annotations:
+      gui-x: '500'
+      gui-y: '-250'
+    charm: cs:trusty/openstack-dashboard-19
+    num_units: 1
+    options:
+      openstack-origin: cloud:trusty-kilo
+    to:
+    - '7'
+  rabbitmq-server:
+    annotations:
+      gui-x: '500'
+      gui-y: '250'
+    charm: cs:trusty/rabbitmq-server-42
+    num_units: 1
+    options:
+      ssl: 'off'
+    to:
+    - '2'
diff --git a/scripts/juju-cord-setup.py b/scripts/juju-cord-setup.py
new file mode 100755
index 0000000..ba19ffd
--- /dev/null
+++ b/scripts/juju-cord-setup.py
@@ -0,0 +1,39 @@
+#!/usr/bin/python
+
+import subprocess
+import json
+import socket
+
+# Assumption: VMs have same hostname as service that runs inside
+machines = ["mysql", "rabbitmq-server", "keystone", "glance", "nova-cloud-controller",
+            "neutron-gateway", "openstack-dashboard", "ceilometer", "nagios", "neutron-api"]
+
+
+# Figure out Juju ID of machine we should install on
+def get_machine(status, service):
+    if service == "mongodb":
+        service = "ceilometer"
+    for key, value in status['machines'].iteritems():
+        (hostname, aliaslist, ipaddrlist) = socket.gethostbyaddr(value['dns-name'])
+        if hostname == service:
+            return key
+    return None
+
+def get_juju_status():
+    output = subprocess.check_output("juju status --format=json", shell=True)
+    status = json.loads(output)
+    return status
+
+def addmachines():
+    status = get_juju_status()
+
+    for machine in machines:
+        if get_machine(status, machine) == None:
+            ipaddr = socket.gethostbyname(machine)
+            subprocess.check_call("juju add-machine ssh:%s" % ipaddr, shell=True)
+
+def main():
+    addmachines()
+
+if  __name__ =='__main__':
+    main()
diff --git a/templates/admin-openrc-cord.sh.j2 b/templates/admin-openrc-cord.sh.j2
new file mode 100644
index 0000000..ec7ab9d
--- /dev/null
+++ b/templates/admin-openrc-cord.sh.j2
@@ -0,0 +1,5 @@
+export OS_USERNAME=admin
+export OS_PASSWORD=ADMIN_PASS
+export OS_TENANT_NAME=admin
+export OS_AUTH_URL=http://{{ keystone_ip.stdout }}:5000/v2.0
+export OS_REGION_NAME=RegionOne