Merge branch 'master' of github.com:open-cloud/xos into feature/diagnostic
diff --git a/README.md b/README.md
index 75b07dd..7bed9c5 100644
--- a/README.md
+++ b/README.md
@@ -6,11 +6,14 @@
 Additional design notes, presentations, and other collateral are 
 also available at http://xosproject.org and http://cord.onosproject.org.
 
-One quick way to get started is to build and run the containers in
-`containers/` (see the README in that directory for more information).
-
-Another quick way to get started is to look at the collection of
+The best way to get started is to look at the collection of
 canned configurations in `xos/configurations/`. The `cord` 
 configuration in that directory corresponds to our current 
 CORD development environment, and the `README.md` you'll find there
 will help you get started.
+
+Source tree layout:
+ * applications -- stand-alone applications that run on top of XOS.
+ * containers -- common Dockerfiles used by various XOS configurations
+ * views -- mechanisms to extend XOS with customized views
+ * xos -- XOS internals
diff --git a/containers/README.md b/containers/README.md
index 0fcdb13..b4a8ea8 100644
--- a/containers/README.md
+++ b/containers/README.md
@@ -60,12 +60,16 @@
 `http://localhost:8000` and log in using the default `padmin@vicci.org` account
 with password `letmein`.
 
-#### Configuring XOS for OpenStack
+## Configuring XOS for OpenStack
+
+There are many possible configurations of XOS. The best way to get started
+is to find the configuration that best matches your needs and modify it as
+necessary. The available "canned" configurations can be found i `../xos/configurations/`.
 
 If you have your own OpenStack cluster, and you would like to configure XOS to
-control it, copy the `admin-openrc.sh` credentials file for your cluster to
-this directory.  Make sure that OpenStack commands work from the local machine
-using the credentials, e.g., `source ./admin-openrc.sh; nova list`.  Then run:
+control it, then take the following steps. Copy the `admin-openrc.sh` credentials 
+file for your cluster to this directory.  Make sure that OpenStack commands work 
+from the local machine using the credentials, e.g., `source ./admin-openrc.sh; nova list`.  Then run:
 
 ```
 $ make
diff --git a/views/ngXosLib/karma.conf.js b/views/ngXosLib/karma.conf.js
index 06939fb..b75f95b 100644
--- a/views/ngXosLib/karma.conf.js
+++ b/views/ngXosLib/karma.conf.js
@@ -65,7 +65,7 @@
 
     // level of logging
     // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
-    logLevel: config.LOG_INFO,
+    logLevel: config.LOG_DEBUG,
 
 
     // enable / disable watching file and executing tests whenever any file changes
diff --git a/views/ngXosLib/package.json b/views/ngXosLib/package.json
index 1f8713c..9e13e28 100644
--- a/views/ngXosLib/package.json
+++ b/views/ngXosLib/package.json
@@ -28,6 +28,14 @@
     "gulp-concat": "^2.6.0",
     "gulp-ng-annotate": "^1.1.0",
     "gulp-uglify": "^1.4.2",
+    "jasmine-core": "^2.4.1",
+    "karma": "^0.13.19",
+    "karma-babel-preprocessor": "^6.0.1",
+    "karma-jasmine": "^0.3.6",
+    "karma-mocha-reporter": "^1.1.3",
+    "karma-ng-html2js-preprocessor": "^0.2.0",
+    "karma-phantomjs-launcher": "^0.2.1",
+    "phantomjs": "^2.1.3",
     "wiredep": "^3.0.0-beta",
     "wrench": "^1.5.8"
   }
diff --git a/views/ngXosLib/xosHelpers/spec/csrftoken.test.js b/views/ngXosLib/xosHelpers/spec/csrftoken.test.js
index 6a74040..e49c52b 100644
--- a/views/ngXosLib/xosHelpers/spec/csrftoken.test.js
+++ b/views/ngXosLib/xosHelpers/spec/csrftoken.test.js
@@ -1,20 +1,22 @@
 'use strict';
 
-describe('The xos.helper module', () => {
+describe('The xos.helper module', function(){
   
   var app, httpProvider;
 
   beforeEach(module('xos.helpers'));
+
   beforeEach(function(){
-    module(function($httpProvider){
-      httpProvider = $httpProvider;
+    module(function(_$httpProvider_){
+      console.log('beforeEach');
+      httpProvider = _$httpProvider_;
     });
   });
 
-
-
-  it('should set SetCSRFToken interceptor', inject(($http) => {
-    expect(httpProvider.interceptors).toContain('SetCSRFToken');
+  it('should set SetCSRFToken interceptor', inject(function($http){
+    console.log('httpProvider',httpProvider);
+    expect(true).toBeTrue();
+    // expect(httpProvider.interceptors).toContain('SetCSRFToken');
   }));
 
 });
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/xosHelpers.module.js b/views/ngXosLib/xosHelpers/src/xosHelpers.module.js
index 1f73be1..25600aa 100644
--- a/views/ngXosLib/xosHelpers/src/xosHelpers.module.js
+++ b/views/ngXosLib/xosHelpers/src/xosHelpers.module.js
@@ -1,12 +1,19 @@
 (function() {
     'use strict';
 
+    angular.module('bugSnag', []).factory('$exceptionHandler', function () {
+      return function (exception, cause) {
+        Bugsnag.notifyException(exception, {diagnostics:{cause: cause}});
+      };
+    });
+
     angular
         .module('xos.helpers',[
           'ngCookies',
           'xos.xos',
           'xos.hpcapi',
-          'xos.xoslib'
+          'xos.xoslib',
+          'bugSnag'
         ])
         .config(config);
 
diff --git a/views/ngXosViews/ceilometerDashboard/env/default.js b/views/ngXosViews/ceilometerDashboard/env/default.js
index 67006ec..f76b607 100644
--- a/views/ngXosViews/ceilometerDashboard/env/default.js
+++ b/views/ngXosViews/ceilometerDashboard/env/default.js
@@ -7,7 +7,7 @@
 // (works only for local environment as both application are served on the same domain)
 
 module.exports = {
-  host: 'http://clnode067.clemson.cloudlab.us:9999/',
-  xoscsrftoken: 'prHoBeRKIHqQE53sKYo3EfzHAgaVIQ1z',
-  xossessionid: 'mp5xe6345ef4fgs6n0t5rfd0su33c12x'
+  host: 'http://clnode078.clemson.cloudlab.us:9999/',
+  xoscsrftoken: 'Lbrkulk7c9fQOloSjhQEqLdDDFRNHsuL',
+  xossessionid: '7j0w1m7t4qcyu472voe32jz6ck9dnq14'
 };
diff --git a/views/ngXosViews/ceilometerDashboard/spec/ceilometer.test.js b/views/ngXosViews/ceilometerDashboard/spec/ceilometer.test.js
index bc8b2e2..cbd8ca0 100644
--- a/views/ngXosViews/ceilometerDashboard/spec/ceilometer.test.js
+++ b/views/ngXosViews/ceilometerDashboard/spec/ceilometer.test.js
@@ -47,11 +47,11 @@
       it('should load corresponding meters', () => {
         vm.loadSliceMeter(vm.services[0].slice[0]);
 
+        httpBackend.flush();
+
         expect(vm.selectedSlice).toEqual('slice-a-1');
         expect(vm.selectedTenant).toEqual('id-a-1');
 
-        httpBackend.flush();
-
         expect(Object.keys(vm.selectedResources).length).toBe(2);
         expect(vm.selectedResources['resource-1'].length).toBe(2);
         expect(vm.selectedResources['resource-2'].length).toBe(1);
diff --git a/views/ngXosViews/ceilometerDashboard/src/js/main.js b/views/ngXosViews/ceilometerDashboard/src/js/main.js
index 8882dda..12f5e72 100644
--- a/views/ngXosViews/ceilometerDashboard/src/js/main.js
+++ b/views/ngXosViews/ceilometerDashboard/src/js/main.js
@@ -31,7 +31,7 @@
     $rootScope.stateName = toState.name;
   })
 })
-.service('Ceilometer', function($http, $q, lodash){
+.service('Ceilometer', function($http, $q){
 
   this.getMappings = () => {
     let deferred = $q.defer();
@@ -161,15 +161,17 @@
 
         // visualization info
         this.loader = true;
-        this.selectedSlice = slice.slice;
-        this.selectedTenant = slice.project_id;
-
-        // store the status
-        Ceilometer.selectedSlice = slice;
-        Ceilometer.selectedService = service_name;
+        this.error = null;
+        this.ceilometerError = null;
 
         Ceilometer.getMeters({tenant: slice.project_id})
         .then((sliceMeters) => {
+          this.selectedSlice = slice.slice;
+          this.selectedTenant = slice.project_id;
+
+          // store the status
+          Ceilometer.selectedSlice = slice;
+          Ceilometer.selectedService = service_name;
           this.selectedResources = lodash.groupBy(sliceMeters, 'resource_name');
 
           // hacky
@@ -178,7 +180,13 @@
           }
         })
         .catch(err => {
-          this.error = (err.data && err.data.detail) ? err.data.detail : 'An Error occurred. Please try again later.';
+
+          // this means that ceilometer is not yet ready
+          if(err.status === 503){
+            return this.ceilometerError = err.data.detail.specific_error;
+          }
+
+          this.error = (err.data && err.data.detail.specific_error) ? err.data.detail.specific_error : 'An Error occurred. Please try again later.';
         })
         .finally(() => {
           this.loader = false;
diff --git a/views/ngXosViews/ceilometerDashboard/src/templates/ceilometer-dashboard.tpl.html b/views/ngXosViews/ceilometerDashboard/src/templates/ceilometer-dashboard.tpl.html
index 23afc1a..fe7720c 100644
--- a/views/ngXosViews/ceilometerDashboard/src/templates/ceilometer-dashboard.tpl.html
+++ b/views/ngXosViews/ceilometerDashboard/src/templates/ceilometer-dashboard.tpl.html
@@ -59,6 +59,9 @@
         </article>
         <!-- METERS -->
         <article ng-hide="vm.showStats" class="meters animate-slide-left">
+          <div class="alert alert-danger" ng-show="vm.ceilometerError">
+            {{vm.ceilometerError}}
+          </div>
           <div class="col-sm-4 animate-slide-left" ng-hide="!vm.selectedSlice">
             <div class="list-group">
               <div class="list-group-item">
diff --git a/xos/configurations/common/fixtures.yaml b/xos/configurations/common/fixtures.yaml
index c5e9dd1..6419211 100644
--- a/xos/configurations/common/fixtures.yaml
+++ b/xos/configurations/common/fixtures.yaml
@@ -21,3 +21,6 @@
 
     bridge:
       type: tosca.nodes.NetworkParameterType
+
+    neutron_port_name:
+      type: tosca.nodes.NetworkParameterType
diff --git a/xos/configurations/common/make-nodes-yaml.sh b/xos/configurations/common/make-nodes-yaml.sh
index 74b8d0b..65e16bb 100644
--- a/xos/configurations/common/make-nodes-yaml.sh
+++ b/xos/configurations/common/make-nodes-yaml.sh
@@ -18,7 +18,7 @@
         type: tosca.nodes.Site
 EOF
 
-NODES=$( bash -c "source $SETUPDIR/admin-openrc.sh ; nova hypervisor-list" |grep -v ID|grep -v +|awk '{print $4}' )
+NODES=$( bash -c "source $SETUPDIR/admin-openrc.sh ; nova host-list" |grep compute|awk '{print $2}' )
 I=0
 for NODE in $NODES; do
     echo $NODE
diff --git a/xos/configurations/cord-pod/Makefile b/xos/configurations/cord-pod/Makefile
new file mode 100644
index 0000000..606f106
--- /dev/null
+++ b/xos/configurations/cord-pod/Makefile
@@ -0,0 +1,32 @@
+.PHONY: xos
+xos: nodes.yaml images.yaml vtn_network_cfg_json virtualbng_json
+	sudo docker-compose up -d
+	../common/wait_for_xos_port.sh 80
+	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/setup.yaml
+	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/nodes.yaml
+	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/images.yaml
+
+vtn:
+	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/vtn-external.yaml
+
+cord:
+	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/mgmt-net.yaml
+	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/common/fixtures.yaml
+	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/cord-vtn-vsg.yaml
+
+nodes.yaml:
+	export SETUPDIR=.; bash ../common/make-nodes-yaml.sh
+
+images.yaml:
+	export SETUPDIR=.; bash ../common/make-images-yaml.sh
+
+virtualbng_json:
+	export SETUPDIR=.; bash ./make-virtualbng-json.sh
+
+vtn_network_cfg_json:
+	export SETUPDIR=.; bash ./make-vtn-networkconfig-json.sh
+
+.PHONY: local_containers
+local_containers:
+	cd ../../../containers/xos; make devel
+	cd ../../../containers/synchronizer; make
diff --git a/xos/configurations/cord-pod/NOTES.txt b/xos/configurations/cord-pod/NOTES.txt
new file mode 100644
index 0000000..d832f2b
--- /dev/null
+++ b/xos/configurations/cord-pod/NOTES.txt
@@ -0,0 +1,37 @@
+Notes on setup
+
+Requirements:
+* admin-openrc.sh: Admin credentials for your OpenStack cloud
+* id_rsa[.pub]: Keypair for use by the various services
+* node_key: Private key that allows root login to the compute nodes
+
+Steps for bringing up the POD:
+
+OpenStack
+* Configure management net
+  - mgmtbr on head nodes
+  - dnsmasq on head1 using cord config file
+* Install OpenStack using the openstack-cluster-install repo
+
+VTN
+* onos-cord VM is created by openstack-cluster-install
+* Bring up ONOS
+  # cd cord; docker-compose up -d
+* On each compute node it's necessary perform a few manual steps (FIX ME)
+  - Disable neutron-plugin-openvswitch-agent. As root:
+    # service neutron-plugin-openvswitch-agent stop
+    # echo manual > /etc/init/neutron-plugin-openvswitch-agent.override
+  - Clean up OVS: delete br-int and any other bridges
+  - Listen for connections from VTN:
+    # ovs-appctl -t ovsdb-server ovsdb-server/add-remote ptcp:6641
+
+XOS
+* xos VM is created by openstack-cluster-install
+  - requirements listed above should already be satisfied by install
+* cd xos/xos/configurations/cord-pod
+* Bring up XOS cord-pod configuration
+  # make
+  # make vtn
+  # make cord
+* Login to XOS at http://xos
+  - padmin@vicci.org / letmein
diff --git a/xos/configurations/cord-pod/README.md b/xos/configurations/cord-pod/README.md
new file mode 100644
index 0000000..1824ab6
--- /dev/null
+++ b/xos/configurations/cord-pod/README.md
@@ -0,0 +1,79 @@
+# XOS Configuration for CORD development POD
+
+## Introduction
+
+This directory holds files that are used to configure a development POD for
+CORD.  For more information on the CORD project, check out
+[the CORD website](http://cord.onosproject.org/).
+
+XOS is composed of several core services:
+
+  * A database backend (postgres)
+  * A webserver front end (django)
+  * A synchronizer daemon that interacts with the openstack backend
+  * A synchronizer for each configured XOS service
+
+Each service runs in a separate Docker container.  The containers are built
+automatically by [Docker Hub](https://hub.docker.com/u/xosproject/) using
+the HEAD of the XOS repository.
+
+## How to bring up CORD
+
+Installing a CORD POD requires three steps:
+ 1. Installing OpenStack on a cluster
+ 2. Setting up the ONOS VTN app and configuring OVS on the nova-compute nodes to be
+    controlled by VTN
+ 3. Bringing up XOS with the CORD services
+
+### Installing OpenStack
+
+Follow the instructions in the [README.md](https://github.com/open-cloud/openstack-cluster-setup/blob/master/README.md)
+file of the [open-cloud/openstack-cluster-setup](https://github.com/open-cloud/openstack-cluster-setup/)
+repository.
+
+### Setting up ONOS VTN
+
+The OpenStack installer above creates a VM called *onos-cord* on the head node.
+To bring up ONOS in this VM, log into the head node and run:
+```
+$ ssh ubuntu@onos-cord
+ubuntu@onos-cord:~$ cd cord; docker-compose up -d
+```
+
+Currently it's also necessary to do some manual configuration on each compute
+node.  As root do the following:
+ 1. Disable neutron-plugin-openvswitch-agent, if running:
+```
+$ service neutron-plugin-openvswitch-agent stop
+$ echo manual > /etc/init/neutron-plugin-openvswitch-agent.override
+```
+ 2. Delete *br-int* and all other bridges from OVS
+ 3. Configure OVS to listen for connections from VTN:
+```
+$ ovs-appctl -t ovsdb-server ovsdb-server/add-remote ptcp:6641
+```
+
+### Bringing up XOS
+
+The OpenStack installer above creates a VM called *xos* on the head node.
+To bring up XOS in this VM, first log into the head node and run:
+```
+$ ssh ubuntu@xos
+ubuntu@xos:~$ cd xos/xos/configurations/cord-pod
+```
+
+Next, put the following files in this directory:
+
+ * *admin-openrc.sh*: Admin credentials for your OpenStack cloud
+ * *id_rsa[.pub]*: A keypair that will be used by the various services
+ * *node_key*: A private key that allows root login to the compute nodes
+
+Then XOS can be brought up for CORD by running a few 'make' commands:
+```
+ubuntu@xos:~/xos/xos/configurations/cord-pod$ make
+ubuntu@xos:~/xos/xos/configurations/cord-pod$ make vtn
+ubuntu@xos:~/xos/xos/configurations/cord-pod$ make cord
+```
+
+After the first 'make' command above, you will be able to login to XOS at
+*http://xos/* using username/password `padmin@vicci.org/letmein`.
diff --git a/xos/configurations/cord-pod/admin-openrc.sh b/xos/configurations/cord-pod/admin-openrc.sh
new file mode 100644
index 0000000..f27fdac
--- /dev/null
+++ b/xos/configurations/cord-pod/admin-openrc.sh
@@ -0,0 +1,6 @@
+# Replace with the OpenStack admin credentials for your cluster
+export OS_TENANT_NAME=admin
+export OS_USERNAME=admin
+export OS_PASSWORD=admin
+export OS_AUTH_URL=http://localhost:35357/v2.0
+
diff --git a/xos/tosca/samples/cord.yaml b/xos/configurations/cord-pod/cord-vtn-vsg.yaml
similarity index 65%
copy from xos/tosca/samples/cord.yaml
copy to xos/configurations/cord-pod/cord-vtn-vsg.yaml
index a9baf25..d9fda9b 100644
--- a/xos/tosca/samples/cord.yaml
+++ b/xos/configurations/cord-pod/cord-vtn-vsg.yaml
@@ -1,6 +1,6 @@
 tosca_definitions_version: tosca_simple_yaml_1_0
 
-description: Setup CORD-related services -- vOLT, vCPE, vBNG.
+description: Just enough Tosca to get the vSG slice running on the CORD POD
 
 imports:
    - custom_types/xos.yaml
@@ -11,64 +11,88 @@
     service_volt:
       type: tosca.nodes.Service
       requirements:
-          - vcpe_tenant:
-              node: service_vcpe
+          - vsg_tenant:
+              node: service_vsg
               relationship: tosca.relationships.TenantOfService
       properties:
           view_url: /admin/cord/voltservice/$id$/
           kind: vOLT
 
-    Private:
-      type: tosca.nodes.NetworkTemplate
+    public_addresses:
+      type: tosca.nodes.AddressPool
+      properties:
+          addresses: 207.141.192.128/27
 
-    # networks required by vCPE
-    lan_network:

-      type: tosca.nodes.network.Network

-      properties:

-          ip_version: 4

-      requirements:

-          - network_template:

-              node: Private

-              relationship: tosca.relationships.UsesNetworkTemplate

-          - owner:

-              node: mysite_vcpe

-              relationship: tosca.relationships.MemberOfSlice

-          - connection:

-              node: mysite_vcpe

-              relationship: tosca.relationships.ConnectsToSlice
-
-    service_vcpe:
-      type: tosca.nodes.VCPEService
+    service_vsg:
+      type: tosca.nodes.VSGService
       requirements:
           - vbng_tenant:
               node: service_vbng
               relationship: tosca.relationships.TenantOfService
       properties:
-          view_url: /admin/cord/vcpeservice/$id$/
+          view_url: /admin/cord/vsgservice/$id$/
           backend_network_label: hpc_client
           public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
+          private_key_fn: /opt/xos/synchronizers/vcpe/vcpe_private_key
+          wan_container_gateway_ip: 207.141.192.158
+          wan_container_gateway_mac: a4:23:05:34:56:78
+          wan_container_netbits: 27
       artifacts:
-          pubkey: /opt/xos/observers/vcpe/vcpe_public_key
+          pubkey: /opt/xos/synchronizers/vcpe/vcpe_public_key
 
     service_vbng:
       type: tosca.nodes.VBNGService
       properties:
           view_url: /admin/cord/vbngservice/$id$/
-          vbng_url: http://10.0.3.136:8181/onos/virtualbng/
+# if unspecified, vbng observer will look for an ONOSApp Tenant and
+# generate a URL from its IP address
+#          vbng_url: http://10.11.10.24:8181/onos/virtualbng/
+
+    Private:
+      type: tosca.nodes.NetworkTemplate
+
+    management:
+      type: tosca.nodes.network.Network.XOS
+      properties:
+          no-create: true
+          no-delete: true
+          no-update: true
 
     mysite:
       type: tosca.nodes.Site
 
-    mysite_vcpe:
-      description: vCPE Controller Slice
-      type: tosca.nodes.Slice
+    # Networks required by the CORD setup
+    mysite_vsg-access:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
       requirements:
-          - vcpe_service:
-              node: service_vcpe
+          - network_template:
+              node: Private
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - owner:
+              node: mysite_vsg
+              relationship: tosca.relationships.MemberOfSlice
+          - connection:
+              node: mysite_vsg
+              relationship: tosca.relationships.ConnectsToSlice
+
+    # CORD Slices
+    mysite_vsg:
+      description: vSG Controller Slice
+      type: tosca.nodes.Slice
+      properties:
+          network: noauto
+      requirements:
+          - vsg_service:
+              node: service_vsg
               relationship: tosca.relationships.MemberOfService
           - site:
               node: mysite
               relationship: tosca.relationships.MemberOfSite
+          - management:
+              node: management
+              relationship: tosca.relationships.ConnectsToNetwork
 
     # Let's add a user who can be administrator of the household
     johndoe@myhouse.com:
@@ -82,14 +106,14 @@
               node: mysite
               relationship: tosca.relationships.MemberOfSite
 
-    # Now let's add a subscriber
+    # A subscriber
     My House:
        type: tosca.nodes.CORDSubscriber
        properties:
-           service_specific_id: 1234
-           firewall_enable: true
-           cdn_enable: true
-           url_filter_enable: true
+           service_specific_id: 123
+           firewall_enable: false
+           cdn_enable: false
+           url_filter_enable: false
            url_filter_level: R
        requirements:
           - house_admin:
@@ -99,7 +123,7 @@
     Mom's PC:
        type: tosca.nodes.CORDUser
        properties:
-           mac: 010203040506
+           mac: 01:02:03:04:05:06
            level: PG_13
        requirements:
            - household:
@@ -109,7 +133,7 @@
     Dad's PC:
        type: tosca.nodes.CORDUser
        properties:
-           mac: 90E2Ba82F975
+           mac: 90:E2:BA:82:F9:75
            level: PG_13
        requirements:
            - household:
@@ -119,7 +143,7 @@
     Jack's Laptop:
        type: tosca.nodes.CORDUser
        properties:
-           mac: 685B359D91D5
+           mac: 68:5B:35:9D:91:D5
            level: PG_13
        requirements:
            - household:
@@ -129,7 +153,7 @@
     Jill's Laptop:
        type: tosca.nodes.CORDUser
        properties:
-           mac: 34363BC9B6A6
+           mac: 34:36:3B:C9:B6:A6
            level: PG_13
        requirements:
            - household:
@@ -139,9 +163,9 @@
     My Volt:
         type: tosca.nodes.VOLTTenant
         properties:
-            service_specific_id: 1234
+            service_specific_id: 123
             s_tag: 222
-            c_tag: 432
+            c_tag: 111
         requirements:
             - provider_service:
                 node: service_volt
@@ -149,8 +173,3 @@
             - subscriber:
                 node: My House
                 relationship: tosca.relationships.BelongsToSubscriber
-
-
-
-
-
diff --git a/xos/configurations/cord-pod/docker-compose.yml b/xos/configurations/cord-pod/docker-compose.yml
new file mode 100644
index 0000000..6f442af
--- /dev/null
+++ b/xos/configurations/cord-pod/docker-compose.yml
@@ -0,0 +1,89 @@
+xos_db:
+    image: xosproject/xos-postgres
+    expose:
+        - "5432"
+
+xos_synchronizer_openstack:
+    command: bash -c "sleep 120; python /opt/xos/synchronizers/openstack/xos-synchronizer.py"
+    image: xosproject/xos-synchronizer-openstack
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: openstack
+    links:
+        - xos_db
+    volumes:
+        - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
+        - ../cord//xos_cord_config:/opt/xos/xos_configuration/xos_cord_config:ro
+        - .:/root/setup:ro
+        - ../vtn/files/xos_vtn_config:/opt/xos/xos_configuration/xos_vtn_config:ro
+        - ./images:/opt/xos/images:ro
+
+xos_synchronizer_onos:
+    image: xosproject/xos-synchronizer-openstack
+    command: bash -c "python /opt/xos/synchronizers/onos/onos-synchronizer.py -C /opt/xos/synchronizers/onos/onos_synchronizer_config"
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: onos
+    links:
+        - xos_db
+    volumes:
+        - .:/root/setup:ro
+        - ./id_rsa:/opt/xos/synchronizers/onos/onos_key:ro  # private key
+
+xos_synchronizer_vcpe:
+    image: xosproject/xos-synchronizer-openstack
+    command: bash -c "sleep 120; cp /root/setup/node_key /opt/xos/synchronizers/vcpe/; chmod 0600 /opt/xos/synchronizers/vcpe/node_key; python /opt/xos/synchronizers/vcpe/vcpe-synchronizer.py -C /root/setup/files/vcpe_synchronizer_config"
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: vcpe
+    links:
+        - xos_db
+    volumes:
+        - .:/root/setup:ro
+        - ./id_rsa:/opt/xos/synchronizers/vcpe/vcpe_private_key:ro  # private key
+
+xos_synchronizer_vtn:
+    image: xosproject/xos-synchronizer-openstack
+    command: bash -c "sleep 120; python /opt/xos/synchronizers/vtn/vtn-synchronizer.py -C /opt/xos/synchronizers/vtn/vtn_synchronizer_config"
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: vtn
+    links:
+        - xos_db
+    volumes:
+        - .:/root/setup:ro
+
+#xos_synchronizer_vbng:
+#    image: xosproject/xos-synchronizer-openstack
+#    command: bash -c "sleep 120; python /opt/xos/synchronizers/vbng/vbng-synchronizer.py -C /opt/xos/synchronizers/vbng/vbng_synchronizer_config"
+#    labels:
+#        org.xosproject.kind: synchronizer
+#        org.xosproject.target: vbng
+#    links:
+#        - xos_db
+
+#xos_synchronizer_monitoring_channel:
+#    image: xosproject/xos-synchronizer-openstack
+#    command: bash -c "sleep 120; python /opt/xos/synchronizers/monitoring_channel/monitoring_channel_synchronizer.py -C /opt/xos/synchronizers/monitoring_channel/monitoring_channel_synchronizer_config"
+#    labels:
+#        org.xosproject.kind: synchronizer
+#        org.xosproject.target: monitoring_channel
+#    links:
+#        - xos_db
+#    volumes:
+#        - ./id_rsa:/opt/xos/synchronizers/monitoring_channel/monitoring_channel_private_key:ro  # private key
+
+xos:
+    command: python /opt/xos/manage.py runserver 0.0.0.0:80 --insecure --makemigrations
+    image: xosproject/xos
+    links:
+        - xos_db
+    ports:
+        - "80:80"
+    volumes:
+        - .:/root/setup:ro
+        - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
+        - ../cord/xos_cord_config:/opt/xos/xos_configuration/xos_cord_config:ro
+        - ../vtn/files/xos_vtn_config:/opt/xos/xos_configuration/xos_vtn_config:ro
+        - ./id_rsa.pub:/opt/xos/synchronizers/onos/onos_key.pub:ro
+        - ./id_rsa.pub:/opt/xos/synchronizers/vcpe/vcpe_public_key:ro
diff --git a/xos/configurations/cord-pod/files/vcpe_synchronizer_config b/xos/configurations/cord-pod/files/vcpe_synchronizer_config
new file mode 100644
index 0000000..46ee0c3
--- /dev/null
+++ b/xos/configurations/cord-pod/files/vcpe_synchronizer_config
@@ -0,0 +1,47 @@
+
+[plc]
+name=plc
+deployment=VICCI
+
+[db]
+name=xos
+user=postgres
+password=password
+host=localhost
+port=5432
+
+[api]
+host=128.112.171.237
+port=8000
+ssl_key=None
+ssl_cert=None
+ca_ssl_cert=None
+ratelimit_enabled=0
+omf_enabled=0
+mail_support_address=support@localhost
+nova_enabled=True
+
+[observer]
+name=vcpe
+dependency_graph=/opt/xos/synchronizers/vcpe/model-deps
+steps_dir=/opt/xos/synchronizers/vcpe/steps
+sys_dir=/opt/xos/synchronizers/vcpe/sys
+deleters_dir=/opt/xos/synchronizers/vcpe/deleters
+log_file=console
+#/var/log/hpc.log
+driver=None
+pretend=False
+backoff_disabled=True
+save_ansible_output=True
+# set proxy_ssh to false on cloudlab
+full_setup=True
+proxy_ssh=True
+proxy_ssh_key=/root/setup/node_key
+proxy_ssh_user=root
+
+[networking]
+use_vtn=True
+
+[feefie]
+client_id='vicci_dev_central'
+user_id='pl'
diff --git a/xos/configurations/cord-pod/images/README.md b/xos/configurations/cord-pod/images/README.md
new file mode 100644
index 0000000..aca55a9
--- /dev/null
+++ b/xos/configurations/cord-pod/images/README.md
@@ -0,0 +1,5 @@
+# VM images for XOS
+
+Any Cloud image files placed in this directory (with suffix .img) will be automatically
+imported by XOS and added to Glance (OpenStack's image repository).  For instance, the image
+`trusty-server-multi-nic.img` will be imported with name `trusty-server-multi-nic`.
diff --git a/xos/configurations/cord-pod/make-virtualbng-json.sh b/xos/configurations/cord-pod/make-virtualbng-json.sh
new file mode 100644
index 0000000..993643c
--- /dev/null
+++ b/xos/configurations/cord-pod/make-virtualbng-json.sh
@@ -0,0 +1,38 @@
+FN=$SETUPDIR/virtualbng.json
+
+rm -f $FN
+
+cat >> $FN <<EOF
+{
+    "localPublicIpPrefixes" : [
+        "10.254.0.128/25"
+    ],
+    "nextHopIpAddress" : "10.254.0.1",
+    "publicFacingMac" : "00:00:00:00:00:66",
+    "xosIpAddress" : "10.11.10.1",
+    "xosRestPort" : "9999",
+    "hosts" : {
+EOF
+
+NODES=$( sudo bash -c "source $SETUPDIR/admin-openrc.sh ; nova hypervisor-list" |grep -v ID|grep -v +|awk '{print $4}' )
+
+NODECOUNT=0
+for NODE in $NODES; do
+    ((NODECOUNT++))
+done
+
+I=0
+for NODE in $NODES; do
+    echo $NODE
+    ((I++))
+    if [[ "$I" -lt "$NODECOUNT" ]]; then
+        echo "      \"$NODE\" : \"of:0000000000000001/1\"," >> $FN
+    else
+        echo "      \"$NODE\" : \"of:0000000000000001/1\"" >> $FN
+    fi
+done
+
+cat >> $FN <<EOF
+    }
+}
+EOF
diff --git a/xos/configurations/cord-pod/make-vtn-networkconfig-json.sh b/xos/configurations/cord-pod/make-vtn-networkconfig-json.sh
new file mode 100755
index 0000000..5239267
--- /dev/null
+++ b/xos/configurations/cord-pod/make-vtn-networkconfig-json.sh
@@ -0,0 +1,83 @@
+FN=$SETUPDIR/vtn-network-cfg.json
+
+echo "Writing to $FN"
+
+rm -f $FN
+
+cat >> $FN <<EOF
+{
+    "apps" : {
+        "org.onosproject.cordvtn" : {
+            "cordvtn" : {
+                "privateGatewayMac" : "00:00:00:00:00:01",
+                "localManagementIp": "172.27.0.1/24",
+                "ovsdbPort": "6641",
+                "sshPort": "22",
+                "sshUser": "root",
+                "sshKeyFile": "/root/node_key",
+                "publicGateways": [
+                    {
+                        "gatewayIp": "207.141.192.158",
+                        "gatewayMac": "a4:23:05:34:56:78"
+                    }
+                ],
+                "nodes" : [
+EOF
+
+NODES=$( sudo bash -c "source $SETUPDIR/admin-openrc.sh ; nova hypervisor-list" |grep -v ID|grep -v +|awk '{print $4}' )
+
+# XXX disabled - we don't need or want the nm node at this time
+# also configure ONOS to manage the nm node
+#NM="neutron-gateway"
+#NODES="$NODES $NM"
+
+NODECOUNT=0
+for NODE in $NODES; do
+    ((NODECOUNT++))
+done
+
+I=0
+for NODE in $NODES; do
+    echo $NODE
+    NODEIP=`getent hosts $NODE | awk '{ print $1 }'`
+
+    PHYPORT=mlx0
+    # How to set LOCALIP?
+    LOCALIPNET="192.168.199"
+
+    ((I++))
+    cat >> $FN <<EOF
+                    {
+                      "hostname": "$NODE",
+                      "hostManagementIp": "$NODEIP/24",
+                      "bridgeId": "of:000000000000000$I",
+                      "dataPlaneIntf": "$PHYPORT",
+                      "dataPlaneIp": "$LOCALIPNET.$I/24"
+EOF
+    if [[ "$I" -lt "$NODECOUNT" ]]; then
+        echo "                    }," >> $FN
+    else
+        echo "                    }" >> $FN
+    fi
+done
+
+# get the openstack admin password and username
+source $SETUPDIR/admin-openrc.sh
+NEUTRON_URL=`keystone endpoint-get --service network|grep publicURL|awk '{print $4}'`
+
+cat >> $FN <<EOF
+                ]
+            }
+        },
+        "org.onosproject.openstackswitching" : {
+            "openstackswitching" : {
+                 "do_not_push_flows" : "true",
+                 "neutron_server" : "$NEUTRON_URL/v2.0/",
+                 "keystone_server" : "$OS_AUTH_URL/",
+                 "user_name" : "$OS_USERNAME",
+                 "password" : "$OS_PASSWORD"
+             }
+        }
+    }
+}
+EOF
diff --git a/xos/configurations/cord/vtn.yaml b/xos/configurations/cord-pod/mgmt-net.yaml
similarity index 91%
rename from xos/configurations/cord/vtn.yaml
rename to xos/configurations/cord-pod/mgmt-net.yaml
index 68c0fdb..2bd0173 100644
--- a/xos/configurations/cord/vtn.yaml
+++ b/xos/configurations/cord-pod/mgmt-net.yaml
@@ -1,12 +1,12 @@
 tosca_definitions_version: tosca_simple_yaml_1_0
 
-description: Some VTN related stuff
-
+description: Set up management network for CORD POD
 imports:
    - custom_types/xos.yaml
 
 topology_template:
   node_templates:
+
     management_template:
       type: tosca.nodes.NetworkTemplate
       properties:
@@ -17,6 +17,7 @@
       type: tosca.nodes.network.Network
       properties:
           ip_version: 4
+          cidr: 172.27.0.0/24
       requirements:
           - network_template:
               node: management_template
@@ -37,4 +38,3 @@
           - site:
               node: mysite
               relationship: tosca.relationships.MemberOfSite
-
diff --git a/xos/configurations/cord-pod/setup.yaml b/xos/configurations/cord-pod/setup.yaml
new file mode 100644
index 0000000..c13f0eb
--- /dev/null
+++ b/xos/configurations/cord-pod/setup.yaml
@@ -0,0 +1,61 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: >
+    * Adds OpenCloud Sites, Deployments, and Controllers.
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+
+    MyDeployment:
+      type: tosca.nodes.Deployment
+      properties:
+          flavors: m1.large, m1.medium, m1.small
+
+    MyOpenStack:
+      type: tosca.nodes.Controller
+      requirements:
+          - deployment:
+              node: MyDeployment
+              relationship: tosca.relationships.ControllerDeployment
+      properties:
+          backend_type: OpenStack
+          version: Kilo
+          auth_url: { get_script_env: [ SELF, adminrc, OS_AUTH_URL, LOCAL_FILE] }
+          admin_user: { get_script_env: [ SELF, adminrc, OS_USERNAME, LOCAL_FILE] }
+          admin_password: { get_script_env: [ SELF, adminrc, OS_PASSWORD, LOCAL_FILE] }
+          admin_tenant: { get_script_env: [ SELF, adminrc, OS_TENANT_NAME, LOCAL_FILE] }
+          domain: Default
+      artifacts:
+          adminrc: /root/setup/admin-openrc.sh
+
+    mysite:
+      type: tosca.nodes.Site
+      properties:
+          display_name: MySite
+          site_url: http://xosproject.org/
+      requirements:
+          - deployment:
+               node: MyDeployment
+               relationship: tosca.relationships.SiteDeployment
+               requirements:
+                   - controller:
+                       node: MyOpenStack
+                       relationship: tosca.relationships.UsesController
+
+    # This user already exists in XOS with this password
+    # It's an example of how to create new users
+    padmin@vicci.org:
+      type: tosca.nodes.User
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+      properties:
+          is_admin: true
+          is_active: true
+          firstname: XOS
+          lastname: admin
+          password: letmein
diff --git a/xos/configurations/cord-pod/vtn-external.yaml b/xos/configurations/cord-pod/vtn-external.yaml
new file mode 100644
index 0000000..0aaee67
--- /dev/null
+++ b/xos/configurations/cord-pod/vtn-external.yaml
@@ -0,0 +1,30 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Set up ONOS VTN app
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+
+    service_ONOS_VTN:
+      type: tosca.nodes.ONOSService
+      requirements:
+      properties:
+          kind: onos
+          view_url: /admin/onos/onosservice/$id$/
+          no_container: true
+          rest_hostname: onos-cord
+
+    VTN_ONOS_app:
+      type: tosca.nodes.ONOSVTNApp
+      requirements:
+          - onos_tenant:
+              node: service_ONOS_VTN
+              relationship: tosca.relationships.TenantOfService
+      properties:
+          dependencies: org.onosproject.drivers, org.onosproject.drivers.ovsdb, org.onosproject.openflow-base, org.onosproject.ovsdb-base, org.onosproject.dhcp, org.onosproject.cordvtn, org.onosproject.olt, org.onosproject.igmp, org.onosproject.cordmcast
+          rest_onos/v1/network/configuration/: { get_artifact: [ SELF, vtn_network_cfg_json, LOCAL_FILE ] }
+      artifacts:
+          vtn_network_cfg_json: /root/setup/vtn-network-cfg.json
diff --git a/xos/configurations/cord/README-VTN.md b/xos/configurations/cord/README-VTN.md
index 2d9b7aa..b3c0c61 100644
--- a/xos/configurations/cord/README-VTN.md
+++ b/xos/configurations/cord/README-VTN.md
@@ -1,4 +1,4 @@
-vtn notes:
+# vtn notes:
 
 see also: https://github.com/hyunsun/documentations/wiki/Neutron-ONOS-Integration-for-CORD-VTN#onos-setup
 
@@ -15,7 +15,7 @@
         use_vtn=True
     supervisorctl restart observer
 
-ctl node:
+### ctl node:
 
     # set ONOS_VTN_HOSTNAME to the host where the VTN container was installed
     ONOS_VTN_HOSTNAME="cp-2.smbaker-xos5.xos-pg0.clemson.cloudlab.us"
@@ -30,7 +30,7 @@
     # not still an issue lurking...
     cat > /usr/local/etc/neutron/plugins/ml2/conf_onos.ini <<EOF
     [onos]
-    url_path = http://$ONOS_VTN_HOSTNAME:8181/onos/openstackswitching
+    url_path = http://$ONOS_VTN_HOSTNAME:8181/onos/cordvtn
     username = karaf
     password = karaf
     EOF
@@ -41,7 +41,7 @@
     # files. Maybe it can be restarted using systemctl instead...
     /usr/bin/neutron-server --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugins/ml2/ml2_conf.ini --config-file /usr/local/etc/neutron/plugins/ml2/conf_onos.ini
 
-Compute nodes and nm nodes:
+### Compute nodes and nm nodes:
 
     cd xos/configurations/cord/dataplane
     ./generate-bm.sh > hosts-bm
@@ -55,22 +55,14 @@
 
 Additional compute node stuff:
 
-Br-flat-lan-1 needs to be deleted, since VTN will be attaching br-int directly to the eth device that br-flat-lan-1 was using. Additionally, we need to assign an IP address to br-int (sounds like Hyunsun is working on having VTN do that for us). Adding the route was not in Hyunsun's instructions, but I found I had to do it in order to get the compute nodes to talk to one another.
+I've been deleting any existing unused bridges. Not sure if it's necesary.
 
     ovs-vsctl del-br br-tun
     ovs-vsctl del-br br-flat-lan-1
-    ip addr add <addr-that-was-assinged-to-flat-lan-1> dev br-int
-    ip link set br-int up
-    ip route add <network-that-was-assigned-to-flat-lan-1>/24 dev br-int
-    
-To get the management network working, we need to create management network template, slice, and network. configurations/cord/vtn.yaml will do this for you. Then add a connection to the management network for any slice that needs management connectivity. Note the subnet that gets assigned to the management network. Management-gateway-ip is the .1 address on the subnet. On the compute node:
 
-    ip addr add <management-gateway-ip>/24 dev br-int
+To get the management network working, we need to create management network template, slice, and network. configurations/cord/vtn.yaml will do this for you. Then add a connection to the management network for any slice that needs management connectivity.
     
-For development, I suggest using the bash configuration (remember to start the ONOS observer manually) so that 
-there aren't a bunch of preexisting Neutron networks and nova instances to get in the way. 
-
-Notes:
+### Notes:
 * I've configured the OpenvSwitch switches to use port 6641 instead of port 6640. This is because the VTN app listens on 6640
 itself, and since we're running it in docker 'host' networking mode now, it would conflict with an Openvswitch that was
 also listening on 6640.
@@ -79,7 +71,7 @@
 * Note that the VTN Synchronizer isn't started automatically. It's only use for inter-Service connectivity, so no need to mess with it until intra-Slice connectivity is working first. 
 * Note that the VTN Synchronizer won't connect non-access networks. Any network templates you want VTN to connect must have Access set to "Direct" or "Indirect". 
 
-There is no management network yet, so no way to SSH into the slices. I've been setting up a VNC tunnel, like this:
+In case management network isn't working, you can use a VNC tunnel, like this:
 
     # on compute node, run the following and note the IP address and port number
     virsh vncdisplay <instance-id>
@@ -92,13 +84,13 @@
 
 Then open a VNC session to the local port on your local machine. You'll have a console on the Instance. The username is "Ubuntu" and the password can be obtained from your cloudlab experiment description
 
-Things that can be tested:
+### Things that can be tested:
 
 * Create an Instance, it should have a Private network, and there should be a tap attached from the instance to br-int
 * Two Instances in the same Slice can talk to one another. They can be on the same machine or different machines.
 * Two Slices can talk to one another if the slices are associated with Services and those Services have a Tenancy relationship between them. Note that 1) The VTN Synchronizer must be running, 2) There must be a Private network with Access=[Direct|Indirect], and 3) The connectivity is unidirectional, from subscriber service to provider service.
 
-Testing service composition
+### Testing service composition
 
 1. Change the private network template's 'Access' field from None to Direct
 2. Create a Service, Service-A
@@ -113,3 +105,47 @@
 11. You should see the pings arrive and responses sent out. Note that the ping responses will not reach Slice-1, since VTN traffic is unidirectional.
 12. Delete the Tenancy relation you created in Step #7. The ping traffic should no longer appear in the tcpdump.
 
+### Getting external connectivity working on cloudlab
+
+On head node:
+
+    ovs-vsctl del-br br-flat-lan-1
+    ifconfig eth2 10.123.0.1
+    iptables --table nat --append POSTROUTING --out-interface br-ex -j MASQUERADE
+    arp -s 10.123.0.3 fa:16:3e:ea:11:0a
+    
+Substitute for your installation:
+
+    10.123.0.3 = wan_ip of vSG
+    10.123.0.1 = wan gateway
+    fa:16:3e:ea:11:0a = wan_mac of vSG
+    00:8c:fa:5b:09:d8 = wan_mac of gateway
+    
+### Setting up a test-client
+
+Before setting up VTN, create a bridge and attach it to the dataplane device on each compute node:
+
+    brctl addbr br-inject
+    brctl addif br-inject eth3   # substitute dataplane eth device here, may be different on each compute node
+    ip link set br-inject up
+    ip link set dev br-inject promisc on
+    
+Then update the network-config attribute of the VTN ONOS App in XOS to use a dataplaneIntf of br-inject instead of the eth device. Bring up VTN and a VSG. WAN connectivity and everything else should be working fine. 
+
+Add a new slice, mysite_client, and make sure to give it both a private and a management network. Bring up an instance on the same node as the vSG you want to test. On the compute node, run the following:
+
+    $MAC=<make-up-some-mac>
+    $INSTANCE=<instance-id>
+    virsh attach-interface --domain $INSTANCE --type bridge --source br-inject --model virtio --mac $MAC --config --live
+    
+Log into the vSG via the management interface. Inside of the vSG run the following:
+
+    STAG=<your s-tag here>
+    CTAG=<your c-tag here>
+    ip link add link eth2 eth2.$STAG type vlan id $STAG
+    ip link add link eth2.$STAG eth2.$STAG.$CTAG type vlan id $CTAG
+    ip link set eth2.$STAG up
+    ip link set eth2.$STAG.$CTAG up
+    ip addr add 192.168.0.2/24 dev eth2.$STAG.$CTAG
+    ip route del default
+    ip route add default via 192.168.0.1
diff --git a/xos/configurations/cord/cord.yaml b/xos/configurations/cord/cord.yaml
index f0b45de..07d4b68 100644
--- a/xos/configurations/cord/cord.yaml
+++ b/xos/configurations/cord/cord.yaml
@@ -11,8 +11,8 @@
     service_volt:
       type: tosca.nodes.Service
       requirements:
-          - vcpe_tenant:
-              node: service_vcpe
+          - vsg_tenant:
+              node: service_vsg
               relationship: tosca.relationships.TenantOfService
           - lan_network:
               node: lan_network
@@ -24,14 +24,20 @@
           view_url: /admin/cord/voltservice/$id$/
           kind: vOLT
 
-    service_vcpe:
-      type: tosca.nodes.VCPEService
+    # set a pool of addresses that we can hand out for the VSG Wan.
+    public_addresses:
+      type: tosca.nodes.AddressPool
+      properties:
+          addresses: 10.123.0.0/24 10.124.0.0/24
+
+    service_vsg:
+      type: tosca.nodes.VSGService
       requirements:
           - vbng_tenant:
               node: service_vbng
               relationship: tosca.relationships.TenantOfService
       properties:
-          view_url: /admin/cord/vcpeservice/$id$/
+          view_url: /admin/cord/vsgservice/$id$/
           backend_network_label: hpc_client
           public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
           private_key_fn: /opt/xos/synchronizers/vcpe/vcpe_private_key
@@ -145,6 +151,7 @@
                    "rabbit.user": "<rabbit_user>",
                    "rabbit.password": "<rabbit_password>",
                    "rabbit.host": "<rabbit_host>",
+                   "publish.kafka": "false",
                    "publish.rabbit": "true",
                    "volt.events.rabbit.topic": "notifications.info",
                    "volt.events.rabbit.exchange": "voltlistener",
@@ -190,13 +197,13 @@
               node: Private
               relationship: tosca.relationships.UsesNetworkTemplate
           - owner:
-              node: mysite_vcpe
+              node: mysite_vsg
               relationship: tosca.relationships.MemberOfSlice
           - connection:
-              node: mysite_vcpe
+              node: mysite_vsg
               relationship: tosca.relationships.ConnectsToSlice
           - connection:
-              node: mysite_volt
+              node: mysite_vsg
               relationship: tosca.relationships.ConnectsToSlice
 
     wan_network:
@@ -208,13 +215,13 @@
               node: Private
               relationship: tosca.relationships.UsesNetworkTemplate
           - owner:
-              node: mysite_vcpe
+              node: mysite_vsg
               relationship: tosca.relationships.MemberOfSlice
           - connection:
-              node: mysite_vcpe
+              node: mysite_vsg
               relationship: tosca.relationships.ConnectsToSlice
           - connection:
-              node: mysite_vbng
+              node: mysite_vsg
               relationship: tosca.relationships.ConnectsToSlice
 
     Private-Direct:
@@ -265,18 +272,18 @@
 
 
     # CORD Slices
-    mysite_vcpe:
-      description: vCPE Controller Slice
+    mysite_vsg:
+      description: vSG Controller Slice
       type: tosca.nodes.Slice
       requirements:
-          - vcpe_service:
-              node: service_vcpe
+          - vsg_service:
+              node: service_vsg
               relationship: tosca.relationships.MemberOfService
           - site:
               node: mysite
               relationship: tosca.relationships.MemberOfSite
-          - vcpe_docker_image:
-              node: docker-vcpe
+          - vsg_docker_image:
+              node: docker-vsg
               relationship: tosca.relationships.UsesImage
 #      properties:
 #          default_isolation: container
@@ -442,8 +449,8 @@
                 node: mysite_clients
                 relationship: tosca.relationships.MemberOfSlice
 
-    # docker image for vcpe containers
-    docker-vcpe:
+    # docker image for vsg containers
+    docker-vsg:
       # TODO: need to attach this to mydeployment
       type: tosca.nodes.Image
       properties:
diff --git a/xos/configurations/cord/dataplane/cleanup.sh b/xos/configurations/cord/dataplane/cleanup.sh
index 9860de7..120454d 100755
--- a/xos/configurations/cord/dataplane/cleanup.sh
+++ b/xos/configurations/cord/dataplane/cleanup.sh
@@ -26,8 +26,11 @@
 echo "Waiting 5 seconds..."
 sleep 5
 
+cleanup_network lan_network
 cleanup_network wan_network
 cleanup_network mysite_vcpe-private
+cleanup_network mysite_vsg-access
+cleanup_network management
 
 echo "Deleting networks"
 # Delete all networks beginning with mysite_
@@ -42,3 +45,5 @@
 neutron net-delete public_network || true
 neutron net-delete hpc_client_network || true
 neutron net-delete ceilometer_network || true
+neutron net-delete management || true
+neutron net-delete mysite_vsg-access || true
diff --git a/xos/configurations/cord/make-vtn-networkconfig-json.sh b/xos/configurations/cord/make-vtn-networkconfig-json.sh
old mode 100755
new mode 100644
index c60a939..2cccd65
--- a/xos/configurations/cord/make-vtn-networkconfig-json.sh
+++ b/xos/configurations/cord/make-vtn-networkconfig-json.sh
@@ -9,15 +9,27 @@
     "apps" : {
         "org.onosproject.cordvtn" : {
             "cordvtn" : {
-                "gatewayMac" : "00:00:00:00:00:01",
+                "privateGatewayMac" : "00:00:00:00:00:01",
+                "localManagementIp": "172.27.0.1/24",
+                "ovsdbPort": "6641",
+                "sshPort": "22",
+                "sshUser": "root",
+                "sshKeyFile": "/root/node_key",
+                "publicGateways": [
+                    {
+                        "gatewayIp": "10.123.0.1",
+                        "gatewayMac": "00:8c:fa:5b:09:d8"
+                    }
+                ],
                 "nodes" : [
 EOF
 
 NODES=$( sudo bash -c "source $SETUPDIR/admin-openrc.sh ; nova hypervisor-list" |grep -v ID|grep -v +|awk '{print $4}' )
 
+# XXX disabled - we don't need or want the nm node at this time
 # also configure ONOS to manage the nm node
-NM=`grep "^nm" /root/setup/fqdn.map | awk '{ print $2 }'`
-NODES="$NODES $NM"
+# NM=`grep "^nm" /root/setup/fqdn.map | awk '{ print $2 }'`
+# NODES="$NODES $NM"
 
 NODECOUNT=0
 for NODE in $NODES; do
@@ -39,11 +51,10 @@
     cat >> $FN <<EOF
                     {
                       "hostname": "$NODE",
-                      "ovsdbIp": "$NODEIP",
-                      "ovsdbPort": "6641",
+                      "hostManagementIp": "$NODEIP/24",
                       "bridgeId": "of:000000000000000$I",
-                      "phyPortName": "$PHYPORT",
-                      "localIp": "$LOCALIP"
+                      "dataPlaneIntf": "$PHYPORT",
+                      "dataPlaneIp": "$LOCALIP/24"
 EOF
     if [[ "$I" -lt "$NODECOUNT" ]]; then
         echo "                    }," >> $FN
diff --git a/xos/configurations/frontend/Makefile b/xos/configurations/frontend/Makefile
index 130153a..5c0ce0e 100644
--- a/xos/configurations/frontend/Makefile
+++ b/xos/configurations/frontend/Makefile
@@ -23,3 +23,9 @@
 
 enter-xos:
 	sudo docker exec -ti frontend_xos_1 bash
+
+mock-cord:
+	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/common/fixtures.yaml
+	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/frontend/mocks/cord.yaml
+	sudo docker exec frontend_xos_1 cp /opt/xos/configurations/cord/xos_cord_config /opt/xos/xos_configuration/
+	sudo docker exec frontend_xos_1 touch /opt/xos/xos/settings.py
diff --git a/xos/configurations/frontend/README.md b/xos/configurations/frontend/README.md
index a0ee72e..c8f4097 100644
--- a/xos/configurations/frontend/README.md
+++ b/xos/configurations/frontend/README.md
@@ -37,17 +37,11 @@
 
 You can find a Swagger documentation for endpoint at: `http://0.0.0.0:9000/docs/`
 
-## Test
+## Populate the Data Model with custom data
 
-To run the FE tests, navigate to: `xos/core/xoslib`, and run 'npm test'.
+Sometimes while developing the GUI is usefull to have control over the DataModel. Sample `tosca` recipes for different configuration are defined in the `mocks` folder, and corresponding `make` commands are provided.
 
-This will install the required `npm` dependencies and run the test.
-
-Tests are runned in a headless browser (_PhantomJs_) by _Karma_ and the assertions are made with _Jasmine_. This is a pretty common standard for FE testing so you should feel at home.
-
-You can find the tests in the `spec/` folder, each source file has a corresponding `.test` file in it.
-
-After test have run you can find a Coverage report in `xos/core/xoslib/coverage` folder
+- Bring up the **CORD** data model: `make mock-cord`
 
 ## JS Styleguide
 
diff --git a/xos/configurations/frontend/docker-compose.yml b/xos/configurations/frontend/docker-compose.yml
index 6b71d2e..c7c9c19 100644
--- a/xos/configurations/frontend/docker-compose.yml
+++ b/xos/configurations/frontend/docker-compose.yml
@@ -23,3 +23,4 @@
       - ../../core/xoslib:/opt/xos/core/xoslib
       - ../../core/static:/opt/xos/core/static
       - ../../templates/admin:/opt/xos/templates/admin
+      - ../../configurations:/opt/xos/configurations
diff --git a/xos/configurations/frontend/mocks/cord.yaml b/xos/configurations/frontend/mocks/cord.yaml
new file mode 100644
index 0000000..8c84d8f
--- /dev/null
+++ b/xos/configurations/frontend/mocks/cord.yaml
@@ -0,0 +1,534 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Setup CORD-related services -- vOLT, vCPE, vBNG.
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    # CORD Services
+    service_volt:
+      type: tosca.nodes.Service
+      requirements:
+          - vcpe_tenant:
+              node: service_vsg
+              relationship: tosca.relationships.TenantOfService
+          - lan_network:
+              node: lan_network
+              relationship: tosca.relationships.UsesNetwork
+          - wan_network:
+              node: wan_network
+              relationship: tosca.relationships.UsesNetwork
+      properties:
+          view_url: /admin/cord/voltservice/$id$/
+          kind: vOLT
+
+    service_vsg:
+      type: tosca.nodes.VSGService
+      requirements:
+          - vbng_tenant:
+              node: service_vbng
+              relationship: tosca.relationships.TenantOfService
+      properties:
+          view_url: /admin/cord/vsgservice/$id$/
+          backend_network_label: hpc_client
+          #public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
+          #private_key_fn: /opt/xos/synchronizers/vcpe/vcpe_private_key
+      #artifacts:
+          #pubkey: /opt/xos/synchronizers/vcpe/vcpe_public_key
+
+    service_vbng:
+      type: tosca.nodes.VBNGService
+      properties:
+          view_url: /admin/cord/vbngservice/$id$/
+# if unspecified, vbng observer will look for an ONOSApp Tenant and
+# generate a URL from its IP address
+#          vbng_url: http://10.11.10.24:8181/onos/virtualbng/
+
+    service_ONOS_vBNG:
+      type: tosca.nodes.ONOSService
+      requirements:
+      properties:
+          kind: onos
+          view_url: /admin/onos/onosservice/$id$/
+          #public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
+      #artifacts:
+          #pubkey: /opt/xos/synchronizers/onos/onos_key.pub
+
+#
+# To actually bring up the vBNG app
+# - Set up the dataplane using the ansible script
+# - Log into the vBNG ONOS and run 'devices' to get switch dpID
+# - Change the dpID values in vBNG ONOS app in XOS GUI
+# - (Synchronizer should copy the files to ONOS container immediately)
+# - Log into service_ONOS_vBNG VM and restart ONOS Docker container
+#   (Should roll this step into a Synchronizer)
+#f
+    vBNG_ONOS_app:
+      type: tosca.nodes.ONOSvBNGApp
+      requirements:
+          - onos_tenant:
+              node: service_ONOS_vBNG
+              relationship: tosca.relationships.TenantOfService
+          - vbng_service:
+              node: service_vbng
+              relationship: tosca.relationships.UsedByService
+      properties:
+          dependencies: org.onosproject.proxyarp, org.onosproject.virtualbng, org.onosproject.openflow, org.onosproject.fwd
+          config_network-cfg.json: >
+            {
+              "ports" : {
+                "of:0000000000000001/1" : {
+                  "interfaces" : [
+                    {
+                      "ips"  : [ "10.0.1.253/24" ],
+                      "mac"  : "00:00:00:00:00:99"
+                    }
+                  ]
+                },
+                "of:0000000000000001/2" : {
+                  "interfaces" : [
+                    {
+                      "ips"  : [ "10.254.0.2/24" ],
+                      "mac"  : "00:00:00:00:00:98"
+                    }
+                  ]
+                }
+              }
+            }
+          #config_virtualbng.json: { get_artifact: [ SELF, virtualbng_json, LOCAL_FILE] }
+      #artifacts:
+          #virtualbng_json: /root/setup/virtualbng.json
+
+    service_ONOS_vOLT:
+      type: tosca.nodes.ONOSService
+      requirements:
+      properties:
+          kind: onos
+          view_url: /admin/onos/onosservice/$id$/
+          #public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
+          rest_onos/v1/network/configuration/: >
+            {
+              "devices" : {
+                "of:0000000000000001" : {
+                  "accessDevice" : {
+                    "uplink" : "2",
+                    "vlan"   : "222",
+                    "defaultVlan" : "1"
+                  },
+                  "basic" : {
+                    "driver" : "pmc-olt"
+                  }
+                }
+              }
+            }
+      #artifacts:
+          #pubkey: /opt/xos/synchronizers/onos/onos_key.pub
+
+
+    vOLT_ONOS_app:
+      type: tosca.nodes.ONOSvOLTApp
+      requirements:
+          - onos_tenant:
+              node: service_ONOS_vOLT
+              relationship: tosca.relationships.TenantOfService
+          - volt_service:
+              node: service_volt
+              relationship: tosca.relationships.UsedByService
+      properties:
+          install_dependencies: onos-ext-notifier-1.0-SNAPSHOT.oar, onos-ext-volt-event-publisher-1.0-SNAPSHOT.oar
+          dependencies: org.onosproject.openflow-base, org.onosproject.olt, org.ciena.onos.ext_notifier, org.ciena.onos.volt_event_publisher
+          component_config: >
+             {
+                "org.ciena.onos.ext_notifier.KafkaNotificationBridge":{
+                   "rabbit.user": "<rabbit_user>",
+                   "rabbit.password": "<rabbit_password>",
+                   "rabbit.host": "<rabbit_host>",
+                   "publish.rabbit": "true",
+                   "volt.events.rabbit.topic": "notifications.info",
+                   "volt.events.rabbit.exchange": "voltlistener",
+                   "volt.events.opaque.info": "{project_id: <keystone_tenant_id>, user_id: <keystone_user_id>}",
+                   "publish.volt.events": "true"
+                }
+             }
+#          config_network-cfg.json: >
+#            {
+#              "devices" : {
+#                "of:0000000000000001" : {
+#                  "accessDevice" : {
+#                    "uplink" : "2",
+#                    "vlan"   : "222",
+#                    "defaultVlan" : "1"
+#                  },
+#                  "basic" : {
+#                    "driver" : "default"
+#                  }
+#                }
+#              }
+#            }
+
+    # Network templates
+    Private:
+      type: tosca.nodes.NetworkTemplate
+
+    Public network hack:
+      type: tosca.nodes.NetworkTemplate
+      properties:
+          visibility: private
+          translation: NAT
+          shared_network_name: tun0-net
+
+
+    # Networks required by the CORD setup
+    lan_network:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
+      requirements:
+          - network_template:
+              node: Private
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - owner:
+              node: mysite_vcpe
+              relationship: tosca.relationships.MemberOfSlice
+          - connection:
+              node: mysite_vcpe
+              relationship: tosca.relationships.ConnectsToSlice
+          - connection:
+              node: mysite_volt
+              relationship: tosca.relationships.ConnectsToSlice
+
+    wan_network:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
+      requirements:
+          - network_template:
+              node: Private
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - owner:
+              node: mysite_vcpe
+              relationship: tosca.relationships.MemberOfSlice
+          - connection:
+              node: mysite_vcpe
+              relationship: tosca.relationships.ConnectsToSlice
+          - connection:
+              node: mysite_vbng
+              relationship: tosca.relationships.ConnectsToSlice
+
+    Private-Direct:
+      type: tosca.nodes.NetworkTemplate
+      properties:
+          access: direct
+
+    Private-Indirect:
+      type: tosca.nodes.NetworkTemplate
+      properties:
+          access: indirect
+
+    subscriber_network:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
+      requirements:
+          - network_template:
+              node: Private
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - owner:
+              node: mysite_volt
+              relationship: tosca.relationships.MemberOfSlice
+          - connection:
+              node: mysite_volt
+              relationship: tosca.relationships.ConnectsToSlice
+          - connection:
+              node: mysite_clients
+              relationship: tosca.relationships.ConnectsToSlice
+
+    public_network:
+      type: tosca.nodes.network.Network
+      properties:
+      requirements:
+          - network_template:
+              node: Public network hack
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - owner:
+              node: mysite_vbng
+              relationship: tosca.relationships.MemberOfSlice
+          - connection:
+              node: mysite_vbng
+              relationship: tosca.relationships.ConnectsToSlice
+
+
+    mysite:
+      type: tosca.nodes.Site
+
+
+    # CORD Slices
+    mysite_vcpe:
+      description: vCPE Controller Slice
+      type: tosca.nodes.Slice
+      requirements:
+          - vcpe_service:
+              node: service_vsg
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+          - vcpe_docker_image:
+              node: docker-vcpe
+              relationship: tosca.relationships.UsesImage
+#      properties:
+#          default_isolation: container
+
+    mysite_onos_vbng:
+      description: ONOS Controller Slice for vBNG
+      type: tosca.nodes.Slice
+      requirements:
+          - ONOS:
+              node: service_ONOS_vBNG
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+
+    mysite_onos_volt:
+      description: ONOS Controller Slice for vOLT
+      type: tosca.nodes.Slice
+      requirements:
+          - ONOS:
+              node: service_ONOS_vOLT
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+
+    mysite_vbng:
+      description: slice running OVS controlled by vBNG
+      type: tosca.nodes.Slice
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+
+    mysite_volt:
+      description: OVS controlled by vOLT
+      type: tosca.nodes.Slice
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+
+    mysite_clients:
+      description: slice for clients at the subscriber
+      type: tosca.nodes.Slice
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+
+
+    # Virtual machines
+    onos_app_1:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: Ubuntu
+            version: 14.10
+      requirements:
+          - slice:
+                node: mysite_onos_vbng
+                relationship: tosca.relationships.MemberOfSlice
+
+    onos_app_2:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: Ubuntu
+            version: 14.10
+      requirements:
+          - slice:
+                node: mysite_onos_volt
+                relationship: tosca.relationships.MemberOfSlice
+
+    # VM for running the OVS controlled by vBNG
+    ovs_vbng:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: ubuntu
+            version: 14.04
+      requirements:
+          - slice:
+                node: mysite_vbng
+                relationship: tosca.relationships.MemberOfSlice
+
+    # VM for running the OVS controlled by vOLT
+    ovs_volt:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: ubuntu
+            version: 14.04
+      requirements:
+          - slice:
+                node: mysite_volt
+                relationship: tosca.relationships.MemberOfSlice
+
+    # A subscriber client VM
+    client1:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: ubuntu
+            version: 14.04
+      requirements:
+          - slice:
+                node: mysite_clients
+                relationship: tosca.relationships.MemberOfSlice
+
+    # docker image for vcpe containers
+    docker-vcpe:
+      # TODO: need to attach this to mydeployment
+      type: tosca.nodes.Image
+      properties:
+        kind: container
+        container_format: na
+        disk_format: na
+        path: andybavier/docker-vcpe
+        tag: develop
+
+    # Let's add a user who can be administrator of the household
+    johndoe@myhouse.com:
+      type: tosca.nodes.User
+      properties:
+          password: letmein
+          firstname: john
+          lastname: doe
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+
+    # A subscriber
+    My House:
+       type: tosca.nodes.CORDSubscriber
+       properties:
+           service_specific_id: 123
+           firewall_enable: false
+           cdn_enable: false
+           url_filter_enable: false
+           url_filter_level: R
+       requirements:
+          - house_admin:
+              node: johndoe@myhouse.com
+              relationship: tosca.relationships.AdminPrivilege
+
+    Mom's PC:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 01:02:03:04:05:06
+           level: PG_13
+       requirements:
+           - household:
+               node: My House
+               relationship: tosca.relationships.SubscriberDevice
+
+    Dad's PC:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 90:E2:BA:82:F9:75
+           level: PG_13
+       requirements:
+           - household:
+               node: My House
+               relationship: tosca.relationships.SubscriberDevice
+
+    Jack's Laptop:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 68:5B:35:9D:91:D5
+           level: PG_13
+       requirements:
+           - household:
+               node: My House
+               relationship: tosca.relationships.SubscriberDevice
+
+    Jill's Laptop:
+       type: tosca.nodes.CORDUser
+       properties:
+           mac: 34:36:3B:C9:B6:A6
+           level: PG_13
+       requirements:
+           - household:
+               node: My House
+               relationship: tosca.relationships.SubscriberDevice
+
+    My Volt:
+        type: tosca.nodes.VOLTTenant
+        properties:
+            service_specific_id: 123
+            s_tag: 222
+            c_tag: 432
+        requirements:
+            - provider_service:
+                node: service_volt
+                relationship: tosca.relationships.MemberOfService
+            - subscriber:
+                node: My House
+                relationship: tosca.relationships.BelongsToSubscriber
diff --git a/xos/configurations/opencloud/cdn-content.yaml b/xos/configurations/opencloud/cdn-content.yaml
index d4d1445..ebf6b82 100644
--- a/xos/configurations/opencloud/cdn-content.yaml
+++ b/xos/configurations/opencloud/cdn-content.yaml
@@ -111,37 +111,113 @@
                   node: main_service_provider
                   relationship: tosca.relationships.MemberOfServiceProvider
 
-    downloads.onosproject.org:
-        type: tosca.nodes.CDNPrefix
-        requirements:
-             - content_provider:
-                   node: on_lab_content
+    # Create CDN prefix onlab.vicci.org
+    onlab.vicci.org:

+        type: tosca.nodes.CDNPrefix

+        requirements:

+             - content_provider:

+                   node: on_lab_content

                    relationship: tosca.relationships.MemberOfContentProvider
-             - default_origin_server:
-                   node: http_downloads.onosproject.org
+
+    http_onos-videos.s3.amazonaws.com:
+        type: tosca.nodes.OriginServer

+        requirements:

+             - content_provider:

+                   node: on_lab_content

+                   relationship: tosca.relationships.MemberOfContentProvider
+
+    # Create origin server s3-us-west-1.amazonaws.com
+    http_s3-us-west-1.amazonaws.com:

+        type: tosca.nodes.OriginServer

+        requirements:

+             - content_provider:

+                   node: on_lab_content

+                   relationship: tosca.relationships.MemberOfContentProvider

+

+    # Create origin server s3.amazonaws.com

+    http_s3.amazonaws.com:

+        type: tosca.nodes.OriginServer

+        requirements:

+             - content_provider:

+                   node: on_lab_content

+                   relationship: tosca.relationships.MemberOfContentProvider
+
+    # Test Content Provider
+
+    testcp2:
+        type: tosca.nodes.ContentProvider

+        requirements:

+            - service_provider:

+                  node: main_service_provider

+                  relationship: tosca.relationships.MemberOfServiceProvider
+
+    http_www.cs.arizona.edu:
+        type: tosca.nodes.OriginServer

+        requirements:

+             - content_provider:

+                   node: testcp2

+                   relationship: tosca.relationships.MemberOfContentProvider
+
+    test-cdn.opencloud.us:
+        type: tosca.nodes.CDNPrefix

+        requirements:

+             - content_provider:

+                   node: testcp2

+                   relationship: tosca.relationships.MemberOfContentProvider

+

+             - default_origin_server:

+                   node: http_www.cs.arizona.edu

                    relationship: tosca.relationships.DefaultOriginServer
 
-    onlab.vicci.org:
-        type: tosca.nodes.CDNPrefix
-        requirements:
-             - content_provider:
-                   node: on_lab_content
-                   relationship: tosca.relationships.MemberOfContentProvider
-             - default_origin_server:
-                   node: http_onlab.vicci.org
-                   relationship: tosca.relationships.DefaultOriginServer
+    # Health Checks
 
-    http_downloads.onosproject.org:
-        type: tosca.nodes.OriginServer
+    healthcheck_dns_onlab.vicci.org:
+        type: tosca.nodes.HpcHealthCheck
         requirements:
-             - content_provider:
-                   node: on_lab_content
-                   relationship: tosca.relationships.MemberOfContentProvider
+           - hpc_service:
+                 node: HyperCache
+                 relationship: tosca.relationships.MemberOfService
+        properties:
+           kind: dns
+           resource_name: onlab.vicci.org
 
-    http_onlab.vicci.org:
-        type: tosca.nodes.OriginServer
+    healthcheck_dns_test-cdn.opencloud.us:
+        type: tosca.nodes.HpcHealthCheck
         requirements:
-             - content_provider:
-                   node: on_lab_content
-                   relationship: tosca.relationships.MemberOfContentProvider
+           - hpc_service:
+                 node: HyperCache
+                 relationship: tosca.relationships.MemberOfService
+        properties:
+           kind: dns
+           resource_name: test-cdn.opencloud.us
 
+    healthcheck_http_test-cdn-index:
+        type: tosca.nodes.HpcHealthCheck
+        requirements:
+           - hpc_service:
+                 node: HyperCache
+                 relationship: tosca.relationships.MemberOfService
+        properties:
+           kind: http
+           resource_name: test-cdn.opencloud.us:/
+           result_contains: Lowenthal
+
+    healthcheck_http_onlab_onos_image:
+        type: tosca.nodes.HpcHealthCheck
+        requirements:
+           - hpc_service:
+                 node: HyperCache
+                 relationship: tosca.relationships.MemberOfService
+        properties:
+           kind: http
+           resource_name: onlab.vicci.org:/onos/vm/onos-tutorial-1.1.0r220-ovf.zip
+
+    healthcheck_http_onlab_mininet_image:
+        type: tosca.nodes.HpcHealthCheck
+        requirements:
+           - hpc_service:
+                 node: HyperCache
+                 relationship: tosca.relationships.MemberOfService
+        properties:
+           kind: http
+           resource_name: onlab.vicci.org:/mininet-vm/mininet-2.1.0-130919-ubuntu-13.04-server-amd64-ovf.zip
diff --git a/xos/configurations/opencloud/cdn-opencloud.yaml b/xos/configurations/opencloud/cdn-opencloud.yaml
index 4a13233..f66e0f2 100644
--- a/xos/configurations/opencloud/cdn-opencloud.yaml
+++ b/xos/configurations/opencloud/cdn-opencloud.yaml
@@ -40,7 +40,7 @@
       description: HyperCache Slice
       type: tosca.nodes.Slice
       properties:
-          exposed_ports: tcp 2120:2128, tcp 3200:3209, tcp 8006, tcp 8009, tcp 8015
+          exposed_ports: tcp 2120:2128, tcp 3200:3209, tcp 8006, tcp 8009, tcp 8015, tcp 80
       requirements:
           - cdn_service:
               node: HyperCache
diff --git a/xos/configurations/opencloud/docker-compose.yml b/xos/configurations/opencloud/docker-compose.yml
index 828175e..b44c828 100644
--- a/xos/configurations/opencloud/docker-compose.yml
+++ b/xos/configurations/opencloud/docker-compose.yml
@@ -5,8 +5,8 @@
 
 xos_synchronizer_openstack:
     image: xosproject/xos-synchronizer-openstack
-    #command: bash -c "update-ca-certificates; sleep 120; python /opt/xos/synchronizers/openstack/xos-synchronizer.py"
-    command: sleep 86400
+    command: bash -c "update-ca-certificates; sleep 120; python /opt/xos/synchronizers/openstack/xos-synchronizer.py"
+    #command: sleep 86400
     labels:
         org.xosproject.kind: synchronizer
         org.xosproject.target: openstack
@@ -15,6 +15,36 @@
     volumes:
         - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
         - /usr/local/share/ca-certificates:/usr/local/share/ca-certificates:ro
+        - ./files/xos_opencloud_config:/opt/xos/xos_configuration/xos_opencloud_config:ro
+        - ./images:/opt/xos/images:ro
+
+xos_synchronizer_hpc:
+    image: xosproject/xos-synchronizer-openstack
+    command: bash -c "sleep 120; python /opt/xos/synchronizers/hpc/hpc-synchronizer.py -C /opt/xos/synchronizers/hpc/hpc_synchronizer_config"
+    #command: sleep 86400
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: hpc
+    links:
+        - xos_db
+    volumes:
+        - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
+        - /usr/local/share/ca-certificates:/usr/local/share/ca-certificates:ro
+        - ./files/xos_opencloud_config:/opt/xos/xos_configuration/xos_opencloud_config:ro
+
+xos_watcher_hpc:
+    image: xosproject/xos-synchronizer-openstack
+    command: bash -c "sleep 120; python /opt/xos/synchronizers/hpc/hpc_watcher.py"
+    #command: sleep 86400
+    labels:
+        org.xosproject.kind: watcher
+        org.xosproject.target: hpc
+    links:
+        - xos_db
+    volumes:
+        - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
+        - /usr/local/share/ca-certificates:/usr/local/share/ca-certificates:ro
+        - ./files/xos_opencloud_config:/opt/xos/xos_configuration/xos_opencloud_config:ro
 
 # FUTURE
 #xos_swarm_synchronizer:
@@ -32,3 +62,4 @@
         - xos_db
     volumes:
       - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
+      - ./files/xos_opencloud_config:/opt/xos/xos_configuration/xos_opencloud_config:ro
diff --git a/xos/configurations/opencloud/files/xos_opencloud_config b/xos/configurations/opencloud/files/xos_opencloud_config
new file mode 100644
index 0000000..62291b6
--- /dev/null
+++ b/xos/configurations/opencloud/files/xos_opencloud_config
@@ -0,0 +1,3 @@
+[server]
+restapi_hostname=portal.opencloud.us
+restapi_port=80
diff --git a/xos/configurations/test/README b/xos/configurations/test/README.md
similarity index 86%
rename from xos/configurations/test/README
rename to xos/configurations/test/README.md
index 31f7786..37af594 100644
--- a/xos/configurations/test/README
+++ b/xos/configurations/test/README.md
@@ -1,2 +1,4 @@
+#CORD Test Configuration
+
 This configuration launches the XOS container on cloudlab and runs a test suite. The test results will be printed to
 the console, and then the docker container will exit. 
diff --git a/xos/configurations/vtn/Makefile b/xos/configurations/vtn/Makefile
index 335f83d..1315b39 100644
--- a/xos/configurations/vtn/Makefile
+++ b/xos/configurations/vtn/Makefile
@@ -8,9 +8,10 @@
 xos: vtn_network_cfg_json
 	sudo MYIP=$(MYIP) docker-compose up -d
 	bash ../common/wait_for_xos.sh
+	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/common/fixtures.yaml
 	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/common/base.yaml
 	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/nodes.yaml
-	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/tosca/samples/vtn.yaml
+	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/vtn/vtn.yaml
 
 containers:
 	cd ../../../containers/xos; make devel
diff --git a/xos/tosca/samples/cord.yaml b/xos/configurations/vtn/cord-vtn-vsg.yaml
similarity index 65%
rename from xos/tosca/samples/cord.yaml
rename to xos/configurations/vtn/cord-vtn-vsg.yaml
index a9baf25..1b26bba 100644
--- a/xos/tosca/samples/cord.yaml
+++ b/xos/configurations/vtn/cord-vtn-vsg.yaml
@@ -1,6 +1,6 @@
 tosca_definitions_version: tosca_simple_yaml_1_0
 
-description: Setup CORD-related services -- vOLT, vCPE, vBNG.
+description: Just enough Tosca to get the vSG slice running on VTN-Cloudlab
 
 imports:
    - custom_types/xos.yaml
@@ -11,64 +11,89 @@
     service_volt:
       type: tosca.nodes.Service
       requirements:
-          - vcpe_tenant:
-              node: service_vcpe
+          - vsg_tenant:
+              node: service_vsg
               relationship: tosca.relationships.TenantOfService
       properties:
           view_url: /admin/cord/voltservice/$id$/
           kind: vOLT
 
-    Private:
-      type: tosca.nodes.NetworkTemplate
+    public_addresses:
+      type: tosca.nodes.AddressPool
+      properties:
+          addresses: 10.123.0.0/24 10.124.0.0/24
 
-    # networks required by vCPE
-    lan_network:

-      type: tosca.nodes.network.Network

-      properties:

-          ip_version: 4

-      requirements:

-          - network_template:

-              node: Private

-              relationship: tosca.relationships.UsesNetworkTemplate

-          - owner:

-              node: mysite_vcpe

-              relationship: tosca.relationships.MemberOfSlice

-          - connection:

-              node: mysite_vcpe

-              relationship: tosca.relationships.ConnectsToSlice
-
-    service_vcpe:
-      type: tosca.nodes.VCPEService
+    service_vsg:
+      type: tosca.nodes.VSGService
       requirements:
           - vbng_tenant:
               node: service_vbng
               relationship: tosca.relationships.TenantOfService
       properties:
-          view_url: /admin/cord/vcpeservice/$id$/
+          view_url: /admin/cord/vsgservice/$id$/
           backend_network_label: hpc_client
           public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
+          private_key_fn: /opt/xos/synchronizers/vcpe/vcpe_private_key
+          wan_container_gateway_ip: 10.123.0.1
+          wan_container_gateway_mac: 00:8c:fa:5b:09:d8
+          wan_container_netbits: 24
+          dns_servers: 8.8.8.8, 8.8.4.4
       artifacts:
-          pubkey: /opt/xos/observers/vcpe/vcpe_public_key
+          pubkey: /opt/xos/synchronizers/vcpe/vcpe_public_key
 
     service_vbng:
       type: tosca.nodes.VBNGService
       properties:
           view_url: /admin/cord/vbngservice/$id$/
-          vbng_url: http://10.0.3.136:8181/onos/virtualbng/
+# if unspecified, vbng observer will look for an ONOSApp Tenant and
+# generate a URL from its IP address
+#          vbng_url: http://10.11.10.24:8181/onos/virtualbng/
+
+    Private:
+      type: tosca.nodes.NetworkTemplate
+
+    management:
+      type: tosca.nodes.network.Network.XOS
+      properties:
+          no-create: true
+          no-delete: true
+          no-update: true
 
     mysite:
       type: tosca.nodes.Site
 
-    mysite_vcpe:
-      description: vCPE Controller Slice
-      type: tosca.nodes.Slice
+    # Networks required by the CORD setup
+    mysite_vsg-access:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
       requirements:
-          - vcpe_service:
-              node: service_vcpe
+          - network_template:
+              node: Private
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - owner:
+              node: mysite_vsg
+              relationship: tosca.relationships.MemberOfSlice
+          - connection:
+              node: mysite_vsg
+              relationship: tosca.relationships.ConnectsToSlice
+
+    # CORD Slices
+    mysite_vsg:
+      description: vSG Controller Slice
+      type: tosca.nodes.Slice
+      properties:
+          network: noauto
+      requirements:
+          - vsg_service:
+              node: service_vsg
               relationship: tosca.relationships.MemberOfService
           - site:
               node: mysite
               relationship: tosca.relationships.MemberOfSite
+          - management:
+              node: management
+              relationship: tosca.relationships.ConnectsToNetwork
 
     # Let's add a user who can be administrator of the household
     johndoe@myhouse.com:
@@ -82,14 +107,14 @@
               node: mysite
               relationship: tosca.relationships.MemberOfSite
 
-    # Now let's add a subscriber
+    # A subscriber
     My House:
        type: tosca.nodes.CORDSubscriber
        properties:
-           service_specific_id: 1234
-           firewall_enable: true
-           cdn_enable: true
-           url_filter_enable: true
+           service_specific_id: 123
+           firewall_enable: false
+           cdn_enable: false
+           url_filter_enable: false
            url_filter_level: R
        requirements:
           - house_admin:
@@ -99,7 +124,7 @@
     Mom's PC:
        type: tosca.nodes.CORDUser
        properties:
-           mac: 010203040506
+           mac: 01:02:03:04:05:06
            level: PG_13
        requirements:
            - household:
@@ -109,7 +134,7 @@
     Dad's PC:
        type: tosca.nodes.CORDUser
        properties:
-           mac: 90E2Ba82F975
+           mac: 90:E2:BA:82:F9:75
            level: PG_13
        requirements:
            - household:
@@ -119,7 +144,7 @@
     Jack's Laptop:
        type: tosca.nodes.CORDUser
        properties:
-           mac: 685B359D91D5
+           mac: 68:5B:35:9D:91:D5
            level: PG_13
        requirements:
            - household:
@@ -129,7 +154,7 @@
     Jill's Laptop:
        type: tosca.nodes.CORDUser
        properties:
-           mac: 34363BC9B6A6
+           mac: 34:36:3B:C9:B6:A6
            level: PG_13
        requirements:
            - household:
@@ -139,7 +164,7 @@
     My Volt:
         type: tosca.nodes.VOLTTenant
         properties:
-            service_specific_id: 1234
+            service_specific_id: 123
             s_tag: 222
             c_tag: 432
         requirements:
@@ -149,8 +174,3 @@
             - subscriber:
                 node: My House
                 relationship: tosca.relationships.BelongsToSubscriber
-
-
-
-
-
diff --git a/xos/configurations/vtn/docker-compose.yml b/xos/configurations/vtn/docker-compose.yml
index e7bb6b1..0fa718b 100644
--- a/xos/configurations/vtn/docker-compose.yml
+++ b/xos/configurations/vtn/docker-compose.yml
@@ -21,7 +21,7 @@
 
 xos_synchronizer_onos:
     image: xosproject/xos-synchronizer-openstack
-    command: bash -c "python /opt/xos/synchronizers/onos/onos-observer.py -C /opt/xos/synchronizers/onos/onos_observer_config"
+    command: bash -c "python /opt/xos/synchronizers/onos/onos-synchronizer.py -C /opt/xos/synchronizers/onos/onos_synchronizer_config"
     labels:
         org.xosproject.kind: synchronizer
         org.xosproject.target: onos
@@ -42,7 +42,7 @@
 
 xos:
     image: xosproject/xos
-    command: python /opt/xos/manage.py runserver 0.0.0.0:8000 --insecure --makemigrations
+    command: bash -c "python /opt/xos/manage.py runserver 0.0.0.0:8000 --insecure --makemigrations"
     ports:
         - "9999:8000"
     links:
diff --git a/xos/tosca/samples/vtn.yaml b/xos/configurations/vtn/vtn.yaml
similarity index 71%
rename from xos/tosca/samples/vtn.yaml
rename to xos/configurations/vtn/vtn.yaml
index 50e8c86..3928ba1 100644
--- a/xos/tosca/samples/vtn.yaml
+++ b/xos/configurations/vtn/vtn.yaml
@@ -1,12 +1,44 @@
 tosca_definitions_version: tosca_simple_yaml_1_0
 
-description: Setup CORD-related services -- vOLT, vCPE, vBNG.
+description: Some VTN related stuff
 
 imports:
    - custom_types/xos.yaml
 
 topology_template:
   node_templates:
+    management_template:
+      type: tosca.nodes.NetworkTemplate
+      properties:
+          visibility: private
+          translation: none
+
+    management:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
+          cidr: 172.27.0.0/24
+      requirements:
+          - network_template:
+              node: management_template
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - owner:
+              node: mysite_management
+              relationship: tosca.relationships.MemberOfSlice
+
+    mysite:
+      type: tosca.nodes.Site
+
+    mysite_management:
+      description: This slice exists solely to own the management network
+      type: tosca.nodes.Slice
+      properties:
+          network: noauto
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+
     service_ONOS_VTN:
       type: tosca.nodes.ONOSService
       requirements:
@@ -14,8 +46,10 @@
           kind: onos
           view_url: /admin/onos/onosservice/$id$/
           public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
+          node_key: { get_artifact: [ SELF, nodekey, LOCAL_FILE] }
       artifacts:
           pubkey: /opt/xos/synchronizers/onos/onos_key.pub
+          nodekey: /root/setup/node_key
 
     VTN_ONOS_app:
       type: tosca.nodes.ONOSVTNApp
@@ -24,7 +58,7 @@
               node: service_ONOS_VTN
               relationship: tosca.relationships.TenantOfService
       properties:
-          dependencies: org.onosproject.drivers, org.onosproject.drivers.ovsdb, org.onosproject.lldpprovider, org.onosproject.openflow-base, org.onosproject.ovsdb-base, org.onosproject.dhcp, org.onosproject.openstackswitching, org.onosproject.cordvtn
+          dependencies: org.onosproject.drivers, org.onosproject.drivers.ovsdb, org.onosproject.lldpprovider, org.onosproject.openflow-base, org.onosproject.ovsdb-base, org.onosproject.dhcp, org.onosproject.cordvtn
           rest_onos/v1/network/configuration/: { get_artifact: [ SELF, vtn_network_cfg_json, LOCAL_FILE ] }
       artifacts:
           vtn_network_cfg_json: /root/setup/vtn-network-cfg.json
diff --git a/xos/core/admin.py b/xos/core/admin.py
index f0d402e..28d99fd 100644
--- a/xos/core/admin.py
+++ b/xos/core/admin.py
@@ -42,13 +42,7 @@
     # FIXME: Need to clean this up by separating Javascript from Python
     if (obj.pk):
         script = """
-        <script type="text/javascript">
-            $(document).ready(function () {
-                $("#show_details_%d").click(function () {
-                    $("#status%d").dialog({modal: true, height: 200, width: 200 });
-                });
-            });
-        </script>
+        <script type="text/javascript">$(document).ready(function () {$("#show_details_%d").click(function () {$("#status%d").dialog({modal: true, height: 200, width: 200 });});});</script>
         """%(obj.pk,obj.pk)
 
         div = """
@@ -1262,7 +1256,7 @@
                ]
     readonly_fields = ('backend_status_text', )
 
-    suit_form_tabs =(('general','Image Details'),('instances','Instances'),('imagedeployments','Deployments'), ('controllerimages', 'Controllers'))
+    suit_form_tabs =(('general','Image Details'),('instances','Instances'),('imagedeployments','Deployments'), ('admin-only', 'Admin-Only'))
 
     inlines = [InstanceInline, ControllerImagesInline]
 
@@ -1840,7 +1834,7 @@
     verbose_name_plural = "Controller Networks"
     verbose_name = "Controller Network"
     suit_classes = 'suit-tab suit-tab-admin-only'
-    fields = ['backend_status_icon', 'controller','net_id','subnet_id']
+    fields = ['backend_status_icon', 'controller','net_id','subnet_id','subnet']
     readonly_fields = ('backend_status_icon', )
 
 class NetworkForm(forms.ModelForm):
@@ -1904,7 +1898,7 @@
     suit_form_tabs = (('general','Network Template Details'), ('netparams', 'Parameters') )
 
 class PortAdmin(XOSBaseAdmin):
-    list_display = ("backend_status_icon", "name", "id", "ip")
+    list_display = ("backend_status_icon", "id", "ip")
     list_display_links = ('backend_status_icon', 'id')
     readonly_fields = ("subnet", )
     inlines = [NetworkParameterInline]
diff --git a/xos/core/models/__init__.py b/xos/core/models/__init__.py
index a022cae..628a3bb 100644
--- a/xos/core/models/__init__.py
+++ b/xos/core/models/__init__.py
@@ -26,7 +26,7 @@
 from .instance import Instance
 from .reservation import ReservedResource
 from .reservation import Reservation
-from .network import Network, NetworkParameterType, NetworkParameter, Port, NetworkTemplate, Router, NetworkSlice, ControllerNetwork
+from .network import Network, NetworkParameterType, NetworkParameter, Port, NetworkTemplate, Router, NetworkSlice, ControllerNetwork, AddressPool
 from .billing import Account, Invoice, Charge, UsableObject, Payment
 from .program import Program
 
diff --git a/xos/core/models/instance.py b/xos/core/models/instance.py
index 62a86c4..7f13eb8 100644
--- a/xos/core/models/instance.py
+++ b/xos/core/models/instance.py
@@ -101,6 +101,9 @@
     volumes = models.TextField(null=True, blank=True, help_text="Comma-separated list of directories to expose to parent context")
     parent = models.ForeignKey("Instance", null=True, blank=True, help_text="Parent Instance for containers nested inside of VMs")
 
+    def get_controller (self):
+        return self.node.site_deployment.controller
+
     def __unicode__(self):
         if self.name and Slice.objects.filter(id=self.slice_id) and (self.name != self.slice.name):
             # NOTE: The weird check on self.slice_id was due to a problem when
@@ -183,6 +186,9 @@
 
     # return an address that the synchronizer can use to SSH to the instance
     def get_ssh_ip(self):
+        management=self.get_network_ip("management")
+        if management:
+            return management
         return self.get_network_ip("nat")
 
     @staticmethod
diff --git a/xos/core/models/network.py b/xos/core/models/network.py
index a019091..80ee9ba 100644
--- a/xos/core/models/network.py
+++ b/xos/core/models/network.py
@@ -1,7 +1,7 @@
 import os
 import socket
 import sys
-from django.db import models
+from django.db import models, transaction
 from core.models import PlCoreBase, Site, Slice, Instance, Controller
 from core.models import ControllerLinkManager,ControllerLinkDeletionManager
 from django.contrib.contenttypes.models import ContentType
@@ -259,6 +259,7 @@
     ip = models.GenericIPAddressField(help_text="Instance ip address", blank=True, null=True)
     port_id = models.CharField(null=True, blank=True, max_length=256, help_text="Neutron port id")
     mac = models.CharField(null=True, blank=True, max_length=256, help_text="MAC address associated with this port")
+    xos_created = models.BooleanField(default=False) # True if XOS created this port in Neutron, False if port created by Neutron and observed by XOS
 
     class Meta:
         unique_together = ('network', 'instance')
@@ -337,4 +338,60 @@
     def __unicode__(self):
         return self.parameter.name
 
+class AddressPool(PlCoreBase):
+    name = models.CharField(max_length=32)
+    addresses = models.TextField(blank=True, null=True)
+    inuse = models.TextField(blank=True, null=True)
+
+    def __unicode__(self): return u'%s' % (self.name)
+
+    def get_address(self):
+        with transaction.atomic():
+            ap = AddressPool.objects.get(pk=self.pk)
+            if ap.addresses:
+                avail_ips = ap.addresses.split()
+            else:
+                avail_ips = []
+
+            if ap.inuse:
+                inuse_ips = ap.inuse.split()
+            else:
+                inuse_ips = []
+
+            while avail_ips:
+                addr = avail_ips.pop(0)
+
+                if addr in inuse_ips:
+                    # This may have happened if someone re-ran the tosca
+                    # recipe and 'refilled' the AddressPool while some addresses
+                    # were still in use.
+                    continue
+
+                inuse_ips.insert(0,addr)
+
+                ap.inuse = " ".join(inuse_ips)
+                ap.addresses = " ".join(avail_ips)
+                ap.save()
+                return addr
+
+            addr = None
+        return addr
+
+    def put_address(self, addr):
+        with transaction.atomic():
+            ap = AddressPool.objects.get(pk=self.pk)
+            addresses = ap.addresses or ""
+            parts = addresses.split()
+            if addr not in parts:
+                parts.insert(0,addr)
+                ap.addresses = " ".join(parts)
+
+            inuse = ap.inuse or ""
+            parts = inuse.split()
+            if addr in parts:
+                parts.remove(addr)
+                ap.inuse = " ".join(parts)
+
+            ap.save()
+
 
diff --git a/xos/core/models/plcorebase.py b/xos/core/models/plcorebase.py
index 0822bf5..99acc15 100644
--- a/xos/core/models/plcorebase.py
+++ b/xos/core/models/plcorebase.py
@@ -224,6 +224,9 @@
         self._initial = self._dict # for PlModelMixIn
         self.silent = False
 
+    def get_controller(self):
+        return self.controller
+
     def can_update(self, user):
         return user.can_update_root()
 
diff --git a/xos/core/models/service.py b/xos/core/models/service.py
index b5ba737..6ece1b3 100644
--- a/xos/core/models/service.py
+++ b/xos/core/models/service.py
@@ -554,6 +554,22 @@
         self.set_attribute("instance_id", value)
 
     @property
+    def external_hostname(self):
+        return self.get_attribute("external_hostname", "")
+
+    @external_hostname.setter
+    def external_hostname(self, value):
+        self.set_attribute("external_hostname", value)
+
+    @property
+    def external_container(self):
+        return self.get_attribute("external_container", "")
+
+    @external_container.setter
+    def external_container(self, value):
+        self.set_attribute("external_container", value)
+
+    @property
     def creator(self):
         from core.models import User
         if getattr(self, "cached_creator", None):
@@ -645,12 +661,15 @@
                 instance = self.pick_least_loaded_instance_in_slice(slices)
 
             if not instance:
-                flavors = Flavor.objects.filter(name="m1.small")
-                if not flavors:
-                    raise XOSConfigurationError("No m1.small flavor")
-
                 slice = self.provider_service.slices.all()[0]
 
+                flavor = slice.default_flavor
+                if not flavor:
+                    flavors = Flavor.objects.filter(name="m1.small")
+                    if not flavors:
+                        raise XOSConfigurationError("No m1.small flavor")
+                    flavor = flavors[0]
+
                 if slice.default_isolation == "container_vm":
                     (node, parent) = ContainerVmScheduler(slice).pick()
                 else:
@@ -661,7 +680,7 @@
                                 image = self.image,
                                 creator = self.creator,
                                 deployment = node.site_deployment.deployment,
-                                flavor = flavors[0],
+                                flavor = flavor,
                                 isolation = slice.default_isolation,
                                 parent = parent)
                 self.save_instance(instance)
diff --git a/xos/core/models/site.py b/xos/core/models/site.py
index 1bdef36..b98c40a 100644
--- a/xos/core/models/site.py
+++ b/xos/core/models/site.py
@@ -310,6 +310,11 @@
     site = models.ForeignKey(Site,related_name='controllersite')
     controller = models.ForeignKey(Controller, null=True, blank=True, related_name='controllersite')
     tenant_id = StrippedCharField(null=True, blank=True, max_length=200, db_index=True, help_text="Keystone tenant id")
+
+    def delete(self, *args, **kwds):
+        pdb.set_trace()
+        super(ControllerSite, self).delete(*args, **kwds)
+
     
     class Meta:
         unique_together = ('site', 'controller') 
diff --git a/xos/core/models/tag.py b/xos/core/models/tag.py
index d774800..76a4e2e 100644
--- a/xos/core/models/tag.py
+++ b/xos/core/models/tag.py
@@ -27,6 +27,10 @@
     def can_update(self, user):
         return user.can_update_root()
 
+    @classmethod
+    def select_by_content_object(cls, obj):
+        return cls.objects.filter(content_type=ContentType.objects.get_for_model(obj), object_id=obj.id)
+
     @staticmethod
     def select_by_user(user):
         return Tag.objects.all()
diff --git a/xos/core/views/legacyapi.py b/xos/core/views/legacyapi.py
index 4657116..b5592c0 100644
--- a/xos/core/views/legacyapi.py
+++ b/xos/core/views/legacyapi.py
@@ -121,6 +121,13 @@
         for ps_node in ps_site.nodes.all():
             node_ids.append(ps_id_to_pl_id(ps_node.id))
 
+        if ps_site.location:
+            longitude = ps_site.location.longitude
+            latitude = ps_site.location.latitude
+        else:
+            longitude = 0
+            latitude = 0
+
         site = {"site_id": ps_id_to_pl_id(ps_site.id),
                 "node_ids": node_ids,
                 "pcu_ids": [],
@@ -134,8 +141,8 @@
                 "url": None,
                 "site_tag_ids": [],
                 "enabled": True,
-                "longitude": float(ps_site.location.longitude),
-                "latitude": float(ps_site.location.latitude),
+                "longitude": float(longitude),
+                "latitude": float(latitude),
                 "slice_ids": slice_ids,
                 "login_base": ps_site.login_base,
                 "peer_id": None}
@@ -285,7 +292,7 @@
             'hostipmap':hostipmap,
             'hostnatmap':hostnatmap,
             'hostprivmap':hostprivmap,
-            'instances': instances,
+            'slivers': instances,
             'interfaces': allinterfaces,
             'sites': sites,
             'nodes': nodes}
diff --git a/xos/core/xoslib/methods/ceilometerview.py b/xos/core/xoslib/methods/ceilometerview.py
index f26d84a..9e46aa7 100644
--- a/xos/core/xoslib/methods/ceilometerview.py
+++ b/xos/core/xoslib/methods/ceilometerview.py
@@ -3,6 +3,7 @@
 import urllib2
 import pytz
 import datetime
+import time
 from rest_framework.decorators import api_view
 from rest_framework.response import Response
 from rest_framework.reverse import reverse
@@ -29,17 +30,23 @@
     if not monitoring_channel:
         raise XOSMissingField("Monitoring channel is missing for this tenant...Create one and invoke this REST API")
     #TODO: Wait until URL is completely UP
+    MAX_ATTEMPTS = 5
+    attempts = 0
     while True:
         try:
-            response = urllib2.urlopen(monitoring_channel.ceilometer_url,timeout=1)
+            response = urllib2.urlopen(monitoring_channel.ceilometer_url)
             break
         except urllib2.HTTPError, e:
-            logger.info('SRIKANTH: HTTP error %(reason)s' % {'reason':e.reason})
+            logger.info('HTTP error %(reason)s' % {'reason':e.reason})
             break
         except urllib2.URLError, e:
-            logger.info('SRIKANTH: URL error %(reason)s' % {'reason':e.reason})
+            attempts += 1
+            if attempts >= MAX_ATTEMPTS:
+                raise XOSServiceUnavailable("Ceilometer channel is not ready yet...Try again later")
+            logger.info('URL error %(reason)s' % {'reason':e.reason})
+            time.sleep(1)
             pass
-    logger.info("SRIKANTH: Ceilometer proxy URL for user %(user)s is %(url)s" % {'user':user.username,'url':monitoring_channel.ceilometer_url})
+    logger.info("Ceilometer proxy URL for user %(user)s is %(url)s" % {'user':user.username,'url':monitoring_channel.ceilometer_url})
     return monitoring_channel.ceilometer_url
 
 def getTenantControllerTenantMap(user, slice=None):
@@ -215,6 +222,7 @@
         self._kwapi_meters_info = self._get_kwapi_meters_info()
         self._ipmi_meters_info = self._get_ipmi_meters_info()
         self._vcpe_meters_info = self._get_vcpe_meters_info()
+        self._volt_meters_info = self._get_volt_meters_info()
         self._sdn_meters_info = self._get_sdn_meters_info()
 
         # Storing the meters info of all services together.
@@ -226,6 +234,7 @@
                                self._kwapi_meters_info,
                                self._ipmi_meters_info,
                                self._vcpe_meters_info,
+                               self._volt_meters_info,
                                self._sdn_meters_info)
         self._all_meters_info = {}
         for service_meters in all_services_meters:
@@ -328,6 +337,16 @@
         return self._list(only_meters=self._vcpe_meters_info.keys(),
                           except_meters=except_meters)
 
+    def list_volt(self, except_meters=None):
+        """Returns a list of meters tied to volt service
+
+        :Parameters:
+          - `except_meters`: The list of meter names we don't want to show
+        """
+
+        return self._list(only_meters=self._volt_meters_info.keys(),
+                          except_meters=except_meters)
+
     def list_sdn(self, except_meters=None):
         """Returns a list of meters tied to sdn service
 
@@ -942,6 +961,39 @@
             }),
         ])
 
+    def _get_volt_meters_info(self):
+        """Returns additional info for each meter
+
+        That will be used for augmenting the Ceilometer meter
+        """
+
+        # TODO(lsmola) Unless the Ceilometer will provide the information
+        # below, I need to define it as a static here. I will be joining this
+        # to info that I am able to obtain from Ceilometer meters, hopefully
+        # some day it will be supported all.
+        return datastructures.SortedDict([
+            ('volt.device', {
+                'type': _("VOLT"),
+                'label': '',
+                'description': _("Existence of olt device"),
+            }),
+            ('volt.device.disconnect', {
+                'type': _("VOLT"),
+                'label': '',
+                'description': _("Olt device disconnected"),
+            }),
+            ('volt.device.subscriber', {
+                'type': _("VOLT"),
+                'label': '',
+                'description': _("Existence of olt subscriber"),
+            }),
+            ('volt.device.subscriber.unregister', {
+                'type': _("VOLT"),
+                'label': '',
+                'description': _("Olt subscriber unregistered"),
+            }),
+        ])
+
     def _get_sdn_meters_info(self):
         """Returns additional info for each meter
 
@@ -1114,6 +1166,7 @@
             _('Nova'): meters.list_nova(),
             _('Neutron'): meters.list_neutron(),
             _('VCPE'): meters.list_vcpe(),
+            _('VOLT'): meters.list_volt(),
             _('SDN'): meters.list_sdn(),
         }
         meters = []
@@ -1184,6 +1237,7 @@
             _('Nova'): meters.list_nova(),
             _('Neutron'): meters.list_neutron(),
             _('VCPE'): meters.list_vcpe(),
+            _('VOLT'): meters.list_volt(),
             _('SDN'): meters.list_sdn(),
         }
         report_rows = []
@@ -1192,8 +1246,13 @@
                 query = make_query(tenant_id=meter["project_id"],resource_id=meter["resource_id"])
                 if additional_query:
                     query = query + additional_query
-                statistics = statistic_list(request, meter["name"],
+                try:
+                    statistics = statistic_list(request, meter["name"],
                                         ceilometer_url=tenant_ceilometer_url, query=query, period=3600*24)
+                except Exception as e:
+                    logger.error('Exception during statistics query for meter %(meter)s and reason:%(reason)s' % {'meter':meter["name"], 'reason':str(e)})
+                    statistics = None
+
                 if not statistics:
                     continue
                 statistic = statistics[-1]
@@ -1336,6 +1395,7 @@
                 _('Nova'): meters.list_nova(except_meters=exclude_nova_meters_info),
                 _('Neutron'): meters.list_neutron(except_meters=exclude_neutron_meters_info),
                 _('VCPE'): meters.list_vcpe(),
+                _('VOLT'): meters.list_volt(),
                 _('SDN'): meters.list_sdn(),
             }
             for service,meters in services.items():
@@ -1343,8 +1403,13 @@
                     query = make_query(tenant_id=meter["project_id"],resource_id=meter["resource_id"])
                     if additional_query:
                         query = query + additional_query
-                    statistics = statistic_list(request, meter["name"],
+                    try:
+                        statistics = statistic_list(request, meter["name"],
                                             ceilometer_url=tenant_ceilometer_url, query=query, period=3600*24)
+                    except Exception as e:
+                        logger.error('Exception during statistics query for meter %(meter)s and reason:%(reason)s' % {'meter':meter["name"], 'reason':str(e)})
+                        statistics = None
+
                     if not statistics:
                         continue
                     statistic = statistics[-1]
diff --git a/xos/core/xoslib/static/js/vendor/ngXosHelpers.js b/xos/core/xoslib/static/js/vendor/ngXosHelpers.js
index e8f063f..82a141e 100644
--- a/xos/core/xoslib/static/js/vendor/ngXosHelpers.js
+++ b/xos/core/xoslib/static/js/vendor/ngXosHelpers.js
@@ -1 +1 @@
-!function(){"use strict";function e(e,n,o){e.interceptors.push("SetCSRFToken"),n.startSymbol("{$"),n.endSymbol("$}"),o.defaults.stripTrailingSlashes=!1}angular.module("xos.helpers",["ngCookies","xos.xos","xos.hpcapi","xos.xoslib"]).config(e),e.$inject=["$httpProvider","$interpolateProvider","$resourceProvider"]}(),function(){"use strict";function e(){return{request:function(e){return-1===e.url.indexOf(".html")&&(e.url+="?no_hyperlinks=1"),e}}}angular.module("xos.helpers").factory("NoHyperlinks",e)}(),function(){"use strict";function e(e){return{request:function(n){return"GET"!==n.method&&(n.headers["X-CSRFToken"]=e.get("xoscsrftoken")),n}}}angular.module("xos.helpers").factory("SetCSRFToken",e),e.$inject=["$cookies"]}(),function(){"use strict";function e(e){return r||(r=new e({domain:""})),r}function n(e){return t||(t=new e({domain:""})),t}function o(e){return i||(i=new e({domain:""})),i}angular.module("xos.helpers").service("XosApi",e).service("XoslibApi",n).service("HpcApi",o);var r,t,i;e.$inject=["xos"],n.$inject=["xoslib"],o.$inject=["hpcapi"]}();
\ No newline at end of file
+!function(){"use strict";function e(e,n,o){e.interceptors.push("SetCSRFToken"),n.startSymbol("{$"),n.endSymbol("$}"),o.defaults.stripTrailingSlashes=!1}e.$inject=["$httpProvider","$interpolateProvider","$resourceProvider"],angular.module("bugSnag",[]).factory("$exceptionHandler",function(){return function(e,n){Bugsnag.notifyException(e,{diagnostics:{cause:n}})}}),angular.module("xos.helpers",["ngCookies","xos.xos","xos.hpcapi","xos.xoslib","bugSnag"]).config(e)}(),function(){"use strict";function e(){return{request:function(e){return-1===e.url.indexOf(".html")&&(e.url+="?no_hyperlinks=1"),e}}}angular.module("xos.helpers").factory("NoHyperlinks",e)}(),function(){"use strict";function e(e){return{request:function(n){return"GET"!==n.method&&(n.headers["X-CSRFToken"]=e.get("xoscsrftoken")),n}}}e.$inject=["$cookies"],angular.module("xos.helpers").factory("SetCSRFToken",e)}(),function(){"use strict";function e(e){return t||(t=new e({domain:""})),t}function n(e){return r||(r=new e({domain:""})),r}function o(e){return i||(i=new e({domain:""})),i}e.$inject=["xos"],n.$inject=["xoslib"],o.$inject=["hpcapi"],angular.module("xos.helpers").service("XosApi",e).service("XoslibApi",n).service("HpcApi",o);var t,r,i}();
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/xosCeilometerDashboard.js b/xos/core/xoslib/static/js/xosCeilometerDashboard.js
index 10435f4..1df27f4 100644
--- a/xos/core/xoslib/static/js/xosCeilometerDashboard.js
+++ b/xos/core/xoslib/static/js/xosCeilometerDashboard.js
@@ -1 +1 @@
-"use strict";angular.module("xos.ceilometerDashboard",["ngResource","ngCookies","ngLodash","ui.router","xos.helpers","ngAnimate","chart.js","ui.bootstrap.accordion"]).config(["$stateProvider","$urlRouterProvider",function(e,t){e.state("ceilometerDashboard",{url:"/",template:"<ceilometer-dashboard></ceilometer-dashboard>"}).state("samples",{url:"/:name/:tenant/samples",template:"<ceilometer-samples></ceilometer-samples>"}),t.otherwise("/")}]).config(["$httpProvider",function(e){e.interceptors.push("NoHyperlinks")}]).run(["$rootScope",function(e){e.stateName="ceilometerDashboard",e.$on("$stateChangeStart",function(t,n){e.stateName=n.name})}]).service("Ceilometer",["$http","$q","lodash",function(e,t,n){this.getMappings=function(){var n=t.defer();return e.get("/xoslib/xos-slice-service-mapping/").then(function(e){n.resolve(e.data)})["catch"](function(e){n.reject(e)}),n.promise},this.getMeters=function(n){var s=t.defer();return e.get("/xoslib/meters/",{cache:!0,params:n}).then(function(e){s.resolve(e.data)})["catch"](function(e){s.reject(e)}),s.promise},this.getSamples=function(n,s){var a=t.defer();return e.get("/xoslib/metersamples/",{params:{meter:n,tenant:s}}).then(function(e){a.resolve(e.data)})["catch"](function(e){a.reject(e)}),a.promise},this.getStats=function(n){var s=t.defer();return e.get("/xoslib/meterstatistics/",{cache:!0,params:n}).then(function(e){s.resolve(e.data)})["catch"](function(e){s.reject(e)}),s.promise},this.selectedService=null,this.selectedSlice=null,this.selectedResource=null}]).directive("ceilometerDashboard",["lodash",function(e){return{restrict:"E",scope:{},bindToController:!0,controllerAs:"vm",templateUrl:"templates/ceilometer-dashboard.tpl.html",controller:["Ceilometer",function(t){var n=this;this.showStats=!1,this.accordion={open:{}},this.openPanels=function(){t.selectedService&&(n.accordion.open[t.selectedService]=!0,t.selectedSlice&&(n.loadSliceMeter(t.selectedSlice,t.selectedService),n.selectedSlice=t.selectedSlice,t.selectedResource&&(n.selectedResource=t.selectedResource)))},this.loadMappings=function(){n.loader=!0,t.getMappings().then(function(e){n.services=e,n.openPanels()})["catch"](function(e){n.error=e.data&&e.data.detail?e.data.detail:"An Error occurred. Please try again later."})["finally"](function(){n.loader=!1})},this.loadMappings(),this.loadSliceMeter=function(s,a){t.selectedSlice=null,t.selectedService=null,t.selectedResources=null,n.loader=!0,n.selectedSlice=s.slice,n.selectedTenant=s.project_id,t.selectedSlice=s,t.selectedService=a,t.getMeters({tenant:s.project_id}).then(function(s){n.selectedResources=e.groupBy(s,"resource_name"),t.selectedResource&&(n.selectedMeters=n.selectedResources[t.selectedResource])})["catch"](function(e){n.error=e.data&&e.data.detail?e.data.detail:"An Error occurred. Please try again later."})["finally"](function(){n.loader=!1})},this.selectedMeters=null,this.selectMeters=function(e,s){n.selectedMeters=e,t.selectedResource=s,n.selectedResource=s}}]}}]).directive("ceilometerSamples",["lodash","$stateParams",function(e,t){return{restrict:"E",scope:{},bindToController:!0,controllerAs:"vm",templateUrl:"templates/ceilometer-samples.tpl.html",controller:["Ceilometer",function(n){var s=this;if(this.chartColors=["#286090","#F7464A","#46BFBD","#FDB45C","#97BBCD","#4D5360","#8c4f9f"],this.chart={series:[],labels:[],data:[]},Chart.defaults.global.colours=this.chartColors,this.chartType="line",!t.name||!t.tenant)throw new Error("Missing Name and Tenant Params!");this.name=t.name,this.tenant=t.tenant,this.getLabels=function(e){return e.reduce(function(e,t){var n=new Date(t.timestamp);return e.push(n.getHours()+":"+((n.getMinutes()<10?"0":"")+n.getMinutes())+":"+n.getSeconds()),e},[])},this.getData=function(e){return e.reduce(function(e,t){return e.push(t.volume),e},[])},this.chartMeters=[],this.addMeterToChart=function(t){s.chart.labels=s.getLabels(e.sortBy(s.samplesList[t],"timestamp")),s.chart.series.push(t),s.chart.data.push(s.getData(e.sortBy(s.samplesList[t],"timestamp"))),s.chartMeters.push(s.samplesList[t][0]),e.remove(s.sampleLabels,{id:t})},this.removeFromChart=function(t){s.chart.data.splice(s.chart.series.indexOf(t.project_id),1),s.chart.series.splice(s.chart.series.indexOf(t.project_id),1),s.chartMeters.splice(e.findIndex(s.chartMeters,{project_id:t.project_id}),1),s.sampleLabels.push({id:t.project_id,name:t.resource_name||t.project_id})},this.formatSamplesLabels=function(t){return e.uniq(t,"project_id").reduce(function(e,t){return e.push({id:t.project_id,name:t.resource_name||t.project_id}),e},[])},this.showSamples=function(){s.loader=!0,n.getSamples(s.name).then(function(t){s.samplesList=e.groupBy(t,"project_id"),s.sampleLabels=s.formatSamplesLabels(t),s.addMeterToChart(s.tenant)})["catch"](function(e){s.error=e.data.detail})["finally"](function(){s.loader=!1})},this.showSamples()}]}}]).directive("ceilometerStats",function(){return{restrict:"E",scope:{name:"=name",tenant:"=tenant"},bindToController:!0,controllerAs:"vm",templateUrl:"templates/ceilometer-stats.tpl.html",controller:["$scope","Ceilometer",function(e,t){var n=this;this.getStats=function(e){n.loader=!0,t.getStats({tenant:e}).then(function(e){n.stats=e})["catch"](function(e){n.error=e.data})["finally"](function(){n.loader=!1})},e.$watch(function(){return n.name},function(e){e&&n.getStats(n.tenant)})}]}}),angular.module("xos.ceilometerDashboard").run(["$templateCache",function(e){e.put("templates/accordion-group.html",'<div class="panel {{panelClass || \'panel-default\'}}">\n  <div class="panel-heading" ng-keypress="toggleOpen($event)">\n    <h3>\n      <a href tabindex="0" class="accordion-toggle" ng-click="toggleOpen()" uib-accordion-transclude="heading"><span ng-class="{\'text-muted\': isDisabled}">{{heading}}</span></a>\n    </h3>\n  </div>\n  <div class="panel-collapse collapse" uib-collapse="!isOpen">\n	  <div class="panel-body" ng-transclude></div>\n  </div>\n</div>\n'),e.put("templates/accordion.html",'<div class="panel-group" ng-transclude></div>'),e.put("templates/ceilometer-dashboard.tpl.html",'<div class="row">\n  <div class="col-sm-10">\n    <h1>XOS Monitoring Statistics</h1>\n  </div>\n  <div class="col-xs-2 text-right">\n    <a href="" class="btn btn-default" \n      ng-show="vm.selectedSlice && !vm.showStats"\n      ng-click="vm.showStats = true">\n      <i class="glyphicon glyphicon-transfer"></i>\n    </a>\n    <a href="" class="btn btn-default" \n      ng-show="vm.selectedSlice && vm.showStats"\n      ng-click="vm.showStats = false">\n      <i class="glyphicon glyphicon-transfer"></i>\n    </a>\n  </div>\n</div>\n\n<div class="row" ng-show="vm.loader">\n  <div class="col-xs-12">\n    <div class="loader">Loading</div>\n  </div>\n</div>\n\n<section ng-hide="vm.loader" ng-class="{animate: !vm.loader}">\n  <div class="row">\n    <div class="col-sm-3 service-list">\n        <h3>XOS Service: </h3>\n        <uib-accordion close-others="true" template-url="templates/accordion.html">\n          <uib-accordion-group\n            ng-repeat="service in vm.services | orderBy:\'-service\'"\n            template-url="templates/accordion-group.html"\n            is-open="vm.accordion.open[service.service]"\n            heading="{{service.service}}">\n            <h4>Slices:</h4>\n            <a ng-repeat="slice in service.slices" \n              ng-class="{active: slice.slice === vm.selectedSlice}"\n              ng-click="vm.loadSliceMeter(slice, service.service)"\n              href="#" class="list-group-item" >\n              {{slice.slice}} <i class="glyphicon glyphicon-chevron-right pull-right"></i>\n            </a>\n          </uib-accordion-group>\n        </uib-accordion>\n    </div>\n    <section class="side-container col-sm-9">\n      <div class="row">\n        <!-- STATS -->\n        <article ng-hide="!vm.showStats" class="stats animate-slide-left">\n          <div class="col-xs-12">\n            <div class="list-group">\n              <div class="list-group-item">\n                <h3>Stats</h3>\n              </div>\n              <div class="list-group-item">\n                <ceilometer-stats ng-if="vm.selectedSlice" name="vm.selectedSlice" tenant="vm.selectedTenant"></ceilometer-stats>\n              </div>\n            </div>\n          </div>\n        </article>\n        <!-- METERS -->\n        <article ng-hide="vm.showStats" class="meters animate-slide-left">\n          <div class="col-sm-4 animate-slide-left" ng-hide="!vm.selectedSlice">\n            <div class="list-group">\n              <div class="list-group-item">\n                <h3>Resources</h3>\n              </div>\n              <a href="#" \n                ng-click="vm.selectMeters(meters, resource)" \n                class="list-group-item" \n                ng-repeat="(resource, meters) in vm.selectedResources" \n                ng-class="{active: resource === vm.selectedResource}">\n                {{resource}} <i class="glyphicon glyphicon-chevron-right pull-right"></i>\n              </a>\n            </div>\n          </div>\n          <div class="col-sm-8 animate-slide-left" ng-hide="!vm.selectedMeters">\n            <div class="list-group">\n              <div class="list-group-item">\n                <h3>Meters</h3>\n              </div>\n              <div class="list-group-item">\n                <div class="row">\n                  <div class="col-xs-6">\n                    <label>Name:</label>\n                  </div>\n                  <div class="col-xs-3">\n                    <label>Unit:</label>\n                  </div>\n                  <div class="col-xs-3"></div>\n                </div>\n                <div class="row" ng-repeat="meter in vm.selectedMeters" style="margin-bottom: 10px;">\n                  <div class="col-xs-6">\n                    {{meter.name}}\n                  </div>\n                  <div class="col-xs-3">\n                    {{meter.unit}}\n                  </div>\n                  <div class="col-xs-3">\n                    <a ui-sref="samples({name: meter.name, tenant: meter.project_id})" class="btn btn-primary">\n                      <i class="glyphicon glyphicon-search"></i>\n                    </a>\n                  </div>\n                </div>\n              </div>\n            </div>\n          </div>\n        </article>\n      </div>\n    </section>\n  </div>\n</section>\n<section ng-if="!vm.loader && vm.error">\n  <div class="alert alert-danger">\n    {{vm.error}}\n  </div>\n</section>\n'),e.put("templates/ceilometer-samples.tpl.html",'<!-- <pre>{{ vm | json}}</pre> -->\n\n<div class="row">\n  <div class="col-xs-10">\n    <h1>{{vm.name | uppercase}}</h1>\n  </div>\n  <div class="col-xs-2">\n    <a ui-sref="ceilometerDashboard" class="btn btn-primary pull-right">\n      <i class="glyphicon glyphicon-arrow-left"></i> Back to list\n    </a>\n  </div>\n</div>\n<div class="row" ng-show="vm.loader">\n  <div class="col-xs-12">\n    <div class="loader">Loading</div>\n  </div>\n</div>\n<section ng-if="!vm.loader && !vm.error">\n  <div class="row">\n    <form class="form-inline col-xs-8" ng-submit="vm.addMeterToChart(vm.addMeterValue)">\n      <select ng-model="vm.addMeterValue" class="form-control" ng-options="resource.id as resource.name for resource in vm.sampleLabels"></select>\n      <button class="btn btn-success"> \n        <i class="glyphicon glyphicon-plus"></i> Add\n      </button>\n    </form>\n    <div class="col-xs-4 text-right">\n      <a ng-click="vm.chartType = \'line\'" class="btn" ng-class="{\'btn-default\': vm.chartType != \'bar\', \'btn-primary\': vm.chartType == \'line\'}">Lines</a>\n      <a ng-click="vm.chartType = \'bar\'" class="btn" ng-class="{\'btn-default\': vm.chartType != \'line\', \'btn-primary\': vm.chartType == \'bar\'}">Bars</a>\n    </div>\n  </div>\n  <div class="row" ng-if="!vm.loader">\n    <div class="col-xs-12">\n      <canvas ng-if="vm.chartType === \'line\'" id="line" class="chart chart-line" chart-data="vm.chart.data" chart-options="{datasetFill: false}"\n        chart-labels="vm.chart.labels" chart-legend="false" chart-series="vm.chart.series">\n      </canvas>\n      <canvas ng-if="vm.chartType === \'bar\'" id="bar" class="chart chart-bar" chart-data="vm.chart.data"\n        chart-labels="vm.chart.labels" chart-legend="false" chart-series="vm.chart.series">\n      </canvas>\n      <!-- <pre>{{vm.chartMeters | json}}</pre> -->\n    </div>\n  </div>\n  <div class="row" ng-if="!vm.loader">\n    <div class="col-xs-12">\n      <a ng-click="vm.removeFromChart(meter)" class="btn btn-chart" ng-style="{\'background-color\': vm.chartColors[$index]}" ng-repeat="meter in vm.chartMeters">\n        {{meter.resource_name || meter.resource_id}}\n      </a>\n    </div>\n  </div>\n</section>\n<section ng-if="!vm.loader && vm.error">\n  <div class="alert alert-danger">\n    {{vm.error}}\n  </div>\n</section>'),e.put("templates/ceilometer-stats.tpl.html",'<div ng-show="vm.loader" class="loader">Loading</div>\n\n<section ng-if="!vm.loader && !vm.error">\n\n  <div class="alert alert-danger" ng-if="vm.stats.length == 0">\n    No result\n  </div>  \n\n  <table class="table" ng-if="vm.stats.length > 0">\n    <tr>\n      <th>\n        <a ng-click="order = \'category\'">Type:</a>\n      </th>\n      <th>\n        <a ng-click="order = \'resource_name\'">Resource:</a>\n      </th>\n      <th>\n        <a ng-click="order = \'meter\'">Meter:</a>\n      </th>\n      <th>\n        Unit:\n      </th>\n      <th>\n        Value:\n      </th>\n    </tr>\n    <!-- <tr>\n      <td>\n        <input type="text" ng-model="query.category">\n      </td>\n      <td>\n        <input type="text" ng-model="query.resource_name">\n      </td>\n      <td>\n        <input type="text" ng-model="query.meter">\n      </td>\n      <td>\n        <input type="text" ng-model="query.unit">\n      </td>\n      <td>\n        <input type="text" ng-model="query.value">\n      </td>\n    </tr> -->\n    <tr ng-repeat="item in vm.stats | orderBy:order">\n      <td>{{item.category}}</td>\n      <td>{{item.resource_name}}</td>\n      <td>{{item.meter}}</td>\n      <td>{{item.unit}}</td>\n      <td>{{item.value}}</td>\n    </tr>\n  </table>\n</section>\n\n<section ng-if="!vm.loader && vm.error">\n  <div class="alert alert-danger">\n    {{vm.error}}\n  </div>\n</section>\n')}]),angular.module("xos.ceilometerDashboard").run(["$location",function(e){e.path("/")}]),angular.bootstrap(angular.element("#xosCeilometerDashboard"),["xos.ceilometerDashboard"]);
\ No newline at end of file
+"use strict";angular.module("xos.ceilometerDashboard",["ngResource","ngCookies","ngLodash","ui.router","xos.helpers","ngAnimate","chart.js","ui.bootstrap.accordion"]).config(["$stateProvider","$urlRouterProvider",function(e,t){e.state("ceilometerDashboard",{url:"/",template:"<ceilometer-dashboard></ceilometer-dashboard>"}).state("samples",{url:"/:name/:tenant/samples",template:"<ceilometer-samples></ceilometer-samples>"}),t.otherwise("/")}]).config(["$httpProvider",function(e){e.interceptors.push("NoHyperlinks")}]).run(["$rootScope",function(e){e.stateName="ceilometerDashboard",e.$on("$stateChangeStart",function(t,n){e.stateName=n.name})}]).service("Ceilometer",["$http","$q",function(e,t){this.getMappings=function(){var n=t.defer();return e.get("/xoslib/xos-slice-service-mapping/").then(function(e){n.resolve(e.data)})["catch"](function(e){n.reject(e)}),n.promise},this.getMeters=function(n){var s=t.defer();return e.get("/xoslib/meters/",{cache:!0,params:n}).then(function(e){s.resolve(e.data)})["catch"](function(e){s.reject(e)}),s.promise},this.getSamples=function(n,s){var r=t.defer();return e.get("/xoslib/metersamples/",{params:{meter:n,tenant:s}}).then(function(e){r.resolve(e.data)})["catch"](function(e){r.reject(e)}),r.promise},this.getStats=function(n){var s=t.defer();return e.get("/xoslib/meterstatistics/",{cache:!0,params:n}).then(function(e){s.resolve(e.data)})["catch"](function(e){s.reject(e)}),s.promise},this.selectedService=null,this.selectedSlice=null,this.selectedResource=null}]).directive("ceilometerDashboard",["lodash",function(e){return{restrict:"E",scope:{},bindToController:!0,controllerAs:"vm",templateUrl:"templates/ceilometer-dashboard.tpl.html",controller:["Ceilometer",function(t){var n=this;this.showStats=!1,this.accordion={open:{}},this.openPanels=function(){t.selectedService&&(n.accordion.open[t.selectedService]=!0,t.selectedSlice&&(n.loadSliceMeter(t.selectedSlice,t.selectedService),n.selectedSlice=t.selectedSlice,t.selectedResource&&(n.selectedResource=t.selectedResource)))},this.loadMappings=function(){n.loader=!0,t.getMappings().then(function(e){n.services=e,n.openPanels()})["catch"](function(e){n.error=e.data&&e.data.detail?e.data.detail:"An Error occurred. Please try again later."})["finally"](function(){n.loader=!1})},this.loadMappings(),this.loadSliceMeter=function(s,r){t.selectedSlice=null,t.selectedService=null,t.selectedResources=null,n.loader=!0,n.error=null,n.ceilometerError=null,t.getMeters({tenant:s.project_id}).then(function(a){n.selectedSlice=s.slice,n.selectedTenant=s.project_id,t.selectedSlice=s,t.selectedService=r,n.selectedResources=e.groupBy(a,"resource_name"),t.selectedResource&&(n.selectedMeters=n.selectedResources[t.selectedResource])})["catch"](function(e){return 503===e.status?n.ceilometerError=e.data.detail.specific_error:void(n.error=e.data&&e.data.detail.specific_error?e.data.detail.specific_error:"An Error occurred. Please try again later.")})["finally"](function(){n.loader=!1})},this.selectedMeters=null,this.selectMeters=function(e,s){n.selectedMeters=e,t.selectedResource=s,n.selectedResource=s}}]}}]).directive("ceilometerSamples",["lodash","$stateParams",function(e,t){return{restrict:"E",scope:{},bindToController:!0,controllerAs:"vm",templateUrl:"templates/ceilometer-samples.tpl.html",controller:["Ceilometer",function(n){var s=this;if(this.chartColors=["#286090","#F7464A","#46BFBD","#FDB45C","#97BBCD","#4D5360","#8c4f9f"],this.chart={series:[],labels:[],data:[]},Chart.defaults.global.colours=this.chartColors,this.chartType="line",!t.name||!t.tenant)throw new Error("Missing Name and Tenant Params!");this.name=t.name,this.tenant=t.tenant,this.getLabels=function(e){return e.reduce(function(e,t){var n=new Date(t.timestamp);return e.push(n.getHours()+":"+((n.getMinutes()<10?"0":"")+n.getMinutes())+":"+n.getSeconds()),e},[])},this.getData=function(e){return e.reduce(function(e,t){return e.push(t.volume),e},[])},this.chartMeters=[],this.addMeterToChart=function(t){s.chart.labels=s.getLabels(e.sortBy(s.samplesList[t],"timestamp")),s.chart.series.push(t),s.chart.data.push(s.getData(e.sortBy(s.samplesList[t],"timestamp"))),s.chartMeters.push(s.samplesList[t][0]),e.remove(s.sampleLabels,{id:t})},this.removeFromChart=function(t){s.chart.data.splice(s.chart.series.indexOf(t.project_id),1),s.chart.series.splice(s.chart.series.indexOf(t.project_id),1),s.chartMeters.splice(e.findIndex(s.chartMeters,{project_id:t.project_id}),1),s.sampleLabels.push({id:t.project_id,name:t.resource_name||t.project_id})},this.formatSamplesLabels=function(t){return e.uniq(t,"project_id").reduce(function(e,t){return e.push({id:t.project_id,name:t.resource_name||t.project_id}),e},[])},this.showSamples=function(){s.loader=!0,n.getSamples(s.name).then(function(t){s.samplesList=e.groupBy(t,"project_id"),s.sampleLabels=s.formatSamplesLabels(t),s.addMeterToChart(s.tenant)})["catch"](function(e){s.error=e.data.detail})["finally"](function(){s.loader=!1})},this.showSamples()}]}}]).directive("ceilometerStats",function(){return{restrict:"E",scope:{name:"=name",tenant:"=tenant"},bindToController:!0,controllerAs:"vm",templateUrl:"templates/ceilometer-stats.tpl.html",controller:["$scope","Ceilometer",function(e,t){var n=this;this.getStats=function(e){n.loader=!0,t.getStats({tenant:e}).then(function(e){n.stats=e})["catch"](function(e){n.error=e.data})["finally"](function(){n.loader=!1})},e.$watch(function(){return n.name},function(e){e&&n.getStats(n.tenant)})}]}}),angular.module("xos.ceilometerDashboard").run(["$templateCache",function(e){e.put("templates/accordion-group.html",'<div class="panel {{panelClass || \'panel-default\'}}">\n  <div class="panel-heading" ng-keypress="toggleOpen($event)">\n    <h3>\n      <a href tabindex="0" class="accordion-toggle" ng-click="toggleOpen()" uib-accordion-transclude="heading"><span ng-class="{\'text-muted\': isDisabled}">{{heading}}</span></a>\n    </h3>\n  </div>\n  <div class="panel-collapse collapse" uib-collapse="!isOpen">\n	  <div class="panel-body" ng-transclude></div>\n  </div>\n</div>\n'),e.put("templates/accordion.html",'<div class="panel-group" ng-transclude></div>'),e.put("templates/ceilometer-dashboard.tpl.html",'<div class="row">\n  <div class="col-sm-10">\n    <h1>XOS Monitoring Statistics</h1>\n  </div>\n  <div class="col-xs-2 text-right">\n    <a href="" class="btn btn-default" \n      ng-show="vm.selectedSlice && !vm.showStats"\n      ng-click="vm.showStats = true">\n      <i class="glyphicon glyphicon-transfer"></i>\n    </a>\n    <a href="" class="btn btn-default" \n      ng-show="vm.selectedSlice && vm.showStats"\n      ng-click="vm.showStats = false">\n      <i class="glyphicon glyphicon-transfer"></i>\n    </a>\n  </div>\n</div>\n\n<div class="row" ng-show="vm.loader">\n  <div class="col-xs-12">\n    <div class="loader">Loading</div>\n  </div>\n</div>\n\n<section ng-hide="vm.loader" ng-class="{animate: !vm.loader}">\n  <div class="row">\n    <div class="col-sm-3 service-list">\n        <h3>XOS Service: </h3>\n        <uib-accordion close-others="true" template-url="templates/accordion.html">\n          <uib-accordion-group\n            ng-repeat="service in vm.services | orderBy:\'-service\'"\n            template-url="templates/accordion-group.html"\n            is-open="vm.accordion.open[service.service]"\n            heading="{{service.service}}">\n            <h4>Slices:</h4>\n            <a ng-repeat="slice in service.slices" \n              ng-class="{active: slice.slice === vm.selectedSlice}"\n              ng-click="vm.loadSliceMeter(slice, service.service)"\n              href="#" class="list-group-item" >\n              {{slice.slice}} <i class="glyphicon glyphicon-chevron-right pull-right"></i>\n            </a>\n          </uib-accordion-group>\n        </uib-accordion>\n    </div>\n    <section class="side-container col-sm-9">\n      <div class="row">\n        <!-- STATS -->\n        <article ng-hide="!vm.showStats" class="stats animate-slide-left">\n          <div class="col-xs-12">\n            <div class="list-group">\n              <div class="list-group-item">\n                <h3>Stats</h3>\n              </div>\n              <div class="list-group-item">\n                <ceilometer-stats ng-if="vm.selectedSlice" name="vm.selectedSlice" tenant="vm.selectedTenant"></ceilometer-stats>\n              </div>\n            </div>\n          </div>\n        </article>\n        <!-- METERS -->\n        <article ng-hide="vm.showStats" class="meters animate-slide-left">\n          <div class="alert alert-danger" ng-show="vm.ceilometerError">\n            {{vm.ceilometerError}}\n          </div>\n          <div class="col-sm-4 animate-slide-left" ng-hide="!vm.selectedSlice">\n            <div class="list-group">\n              <div class="list-group-item">\n                <h3>Resources</h3>\n              </div>\n              <a href="#" \n                ng-click="vm.selectMeters(meters, resource)" \n                class="list-group-item" \n                ng-repeat="(resource, meters) in vm.selectedResources" \n                ng-class="{active: resource === vm.selectedResource}">\n                {{resource}} <i class="glyphicon glyphicon-chevron-right pull-right"></i>\n              </a>\n            </div>\n          </div>\n          <div class="col-sm-8 animate-slide-left" ng-hide="!vm.selectedMeters">\n            <div class="list-group">\n              <div class="list-group-item">\n                <h3>Meters</h3>\n              </div>\n              <div class="list-group-item">\n                <div class="row">\n                  <div class="col-xs-6">\n                    <label>Name:</label>\n                  </div>\n                  <div class="col-xs-3">\n                    <label>Unit:</label>\n                  </div>\n                  <div class="col-xs-3"></div>\n                </div>\n                <div class="row" ng-repeat="meter in vm.selectedMeters" style="margin-bottom: 10px;">\n                  <div class="col-xs-6">\n                    {{meter.name}}\n                  </div>\n                  <div class="col-xs-3">\n                    {{meter.unit}}\n                  </div>\n                  <div class="col-xs-3">\n                    <a ui-sref="samples({name: meter.name, tenant: meter.project_id})" class="btn btn-primary">\n                      <i class="glyphicon glyphicon-search"></i>\n                    </a>\n                  </div>\n                </div>\n              </div>\n            </div>\n          </div>\n        </article>\n      </div>\n    </section>\n  </div>\n</section>\n<section ng-if="!vm.loader && vm.error">\n  <div class="alert alert-danger">\n    {{vm.error}}\n  </div>\n</section>\n'),e.put("templates/ceilometer-samples.tpl.html",'<!-- <pre>{{ vm | json}}</pre> -->\n\n<div class="row">\n  <div class="col-xs-10">\n    <h1>{{vm.name | uppercase}}</h1>\n  </div>\n  <div class="col-xs-2">\n    <a ui-sref="ceilometerDashboard" class="btn btn-primary pull-right">\n      <i class="glyphicon glyphicon-arrow-left"></i> Back to list\n    </a>\n  </div>\n</div>\n<div class="row" ng-show="vm.loader">\n  <div class="col-xs-12">\n    <div class="loader">Loading</div>\n  </div>\n</div>\n<section ng-if="!vm.loader && !vm.error">\n  <div class="row">\n    <form class="form-inline col-xs-8" ng-submit="vm.addMeterToChart(vm.addMeterValue)">\n      <select ng-model="vm.addMeterValue" class="form-control" ng-options="resource.id as resource.name for resource in vm.sampleLabels"></select>\n      <button class="btn btn-success"> \n        <i class="glyphicon glyphicon-plus"></i> Add\n      </button>\n    </form>\n    <div class="col-xs-4 text-right">\n      <a ng-click="vm.chartType = \'line\'" class="btn" ng-class="{\'btn-default\': vm.chartType != \'bar\', \'btn-primary\': vm.chartType == \'line\'}">Lines</a>\n      <a ng-click="vm.chartType = \'bar\'" class="btn" ng-class="{\'btn-default\': vm.chartType != \'line\', \'btn-primary\': vm.chartType == \'bar\'}">Bars</a>\n    </div>\n  </div>\n  <div class="row" ng-if="!vm.loader">\n    <div class="col-xs-12">\n      <canvas ng-if="vm.chartType === \'line\'" id="line" class="chart chart-line" chart-data="vm.chart.data" chart-options="{datasetFill: false}"\n        chart-labels="vm.chart.labels" chart-legend="false" chart-series="vm.chart.series">\n      </canvas>\n      <canvas ng-if="vm.chartType === \'bar\'" id="bar" class="chart chart-bar" chart-data="vm.chart.data"\n        chart-labels="vm.chart.labels" chart-legend="false" chart-series="vm.chart.series">\n      </canvas>\n      <!-- <pre>{{vm.chartMeters | json}}</pre> -->\n    </div>\n  </div>\n  <div class="row" ng-if="!vm.loader">\n    <div class="col-xs-12">\n      <a ng-click="vm.removeFromChart(meter)" class="btn btn-chart" ng-style="{\'background-color\': vm.chartColors[$index]}" ng-repeat="meter in vm.chartMeters">\n        {{meter.resource_name || meter.resource_id}}\n      </a>\n    </div>\n  </div>\n</section>\n<section ng-if="!vm.loader && vm.error">\n  <div class="alert alert-danger">\n    {{vm.error}}\n  </div>\n</section>'),e.put("templates/ceilometer-stats.tpl.html",'<div ng-show="vm.loader" class="loader">Loading</div>\n\n<section ng-if="!vm.loader && !vm.error">\n\n  <div class="alert alert-danger" ng-if="vm.stats.length == 0">\n    No result\n  </div>  \n\n  <table class="table" ng-if="vm.stats.length > 0">\n    <tr>\n      <th>\n        <a ng-click="order = \'category\'">Type:</a>\n      </th>\n      <th>\n        <a ng-click="order = \'resource_name\'">Resource:</a>\n      </th>\n      <th>\n        <a ng-click="order = \'meter\'">Meter:</a>\n      </th>\n      <th>\n        Unit:\n      </th>\n      <th>\n        Value:\n      </th>\n    </tr>\n    <!-- <tr>\n      <td>\n        <input type="text" ng-model="query.category">\n      </td>\n      <td>\n        <input type="text" ng-model="query.resource_name">\n      </td>\n      <td>\n        <input type="text" ng-model="query.meter">\n      </td>\n      <td>\n        <input type="text" ng-model="query.unit">\n      </td>\n      <td>\n        <input type="text" ng-model="query.value">\n      </td>\n    </tr> -->\n    <tr ng-repeat="item in vm.stats | orderBy:order">\n      <td>{{item.category}}</td>\n      <td>{{item.resource_name}}</td>\n      <td>{{item.meter}}</td>\n      <td>{{item.unit}}</td>\n      <td>{{item.value}}</td>\n    </tr>\n  </table>\n</section>\n\n<section ng-if="!vm.loader && vm.error">\n  <div class="alert alert-danger">\n    {{vm.error}}\n  </div>\n</section>\n')}]),angular.module("xos.ceilometerDashboard").run(["$location",function(e){e.path("/")}]),angular.bootstrap(angular.element("#xosCeilometerDashboard"),["xos.ceilometerDashboard"]);
\ No newline at end of file
diff --git a/xos/model_autodeletion.py b/xos/model_autodeletion.py
index 2bfc48c..6eaf63c 100644
--- a/xos/model_autodeletion.py
+++ b/xos/model_autodeletion.py
@@ -1 +1 @@
-ephemeral_models = ['ReservedResource','Instance','Image','Network','Port','Tag','SitePrivilege','SliceMembership','SliceTag','Reservation','Slice']
+ephemeral_models = ['ReservedResource','Instance','Image','Network','Tag','SitePrivilege','SliceMembership','SliceTag','Reservation','Slice']
diff --git a/xos/services/ceilometer/models.py b/xos/services/ceilometer/models.py
index 42734de..2684097 100644
--- a/xos/services/ceilometer/models.py
+++ b/xos/services/ceilometer/models.py
@@ -35,6 +35,10 @@
         proxy = True
 
     KIND = CEILOMETER_KIND
+    LOOK_FOR_IMAGES=[ "trusty-server-multi-nic-docker", # CloudLab
+                      "trusty-server-multi-nic",
+                    ]
+
 
     sync_attributes = ("private_ip", "private_mac",
                        "ceilometer_ip", "ceilometer_mac",
diff --git a/xos/services/cord/admin.py b/xos/services/cord/admin.py
index 5f1a285..76b505c 100644
--- a/xos/services/cord/admin.py
+++ b/xos/services/cord/admin.py
@@ -98,21 +98,29 @@
 # vCPE
 #-----------------------------------------------------------------------------
 
-class VCPEServiceForm(forms.ModelForm):
+class VSGServiceForm(forms.ModelForm):
     bbs_api_hostname = forms.CharField(required=False)
     bbs_api_port = forms.IntegerField(required=False)
     bbs_server = forms.CharField(required=False)
     backend_network_label = forms.CharField(required=False)
     bbs_slice = forms.ModelChoiceField(queryset=Slice.objects.all(), required=False)
+    wan_container_gateway_ip = forms.CharField(required=False)
+    wan_container_gateway_mac = forms.CharField(required=False)
+    wan_container_netbits = forms.CharField(required=False)
+    dns_servers = forms.CharField(required=False)
 
     def __init__(self,*args,**kwargs):
-        super (VCPEServiceForm,self ).__init__(*args,**kwargs)
+        super (VSGServiceForm,self ).__init__(*args,**kwargs)
         if self.instance:
             self.fields['bbs_api_hostname'].initial = self.instance.bbs_api_hostname
             self.fields['bbs_api_port'].initial = self.instance.bbs_api_port
             self.fields['bbs_server'].initial = self.instance.bbs_server
             self.fields['backend_network_label'].initial = self.instance.backend_network_label
             self.fields['bbs_slice'].initial = self.instance.bbs_slice
+            self.fields['wan_container_gateway_ip'].initial = self.instance.wan_container_gateway_ip
+            self.fields['wan_container_gateway_mac'].initial = self.instance.wan_container_gateway_mac
+            self.fields['wan_container_netbits'].initial = self.instance.wan_container_netbits
+            self.fields['dns_servers'].initial = self.instance.dns_servers
 
     def save(self, commit=True):
         self.instance.bbs_api_hostname = self.cleaned_data.get("bbs_api_hostname")
@@ -120,24 +128,30 @@
         self.instance.bbs_server = self.cleaned_data.get("bbs_server")
         self.instance.backend_network_label = self.cleaned_data.get("backend_network_label")
         self.instance.bbs_slice = self.cleaned_data.get("bbs_slice")
-        return super(VCPEServiceForm, self).save(commit=commit)
+        self.instance.wan_container_gateway_ip = self.cleaned_data.get("wan_container_gateway_ip")
+        self.instance.wan_container_gateway_mac = self.cleaned_data.get("wan_container_gateway_mac")
+        self.instance.wan_container_netbits = self.cleaned_data.get("wan_container_netbits")
+        self.instance.dns_servers = self.cleaned_data.get("dns_servers")
+        return super(VSGServiceForm, self).save(commit=commit)
 
     class Meta:
-        model = VCPEService
+        model = VSGService
 
-class VCPEServiceAdmin(ReadOnlyAwareAdmin):
-    model = VCPEService
-    verbose_name = "vCPE Service"
-    verbose_name_plural = "vCPE Service"
+class VSGServiceAdmin(ReadOnlyAwareAdmin):
+    model = VSGService
+    verbose_name = "vSG Service"
+    verbose_name_plural = "vSG Service"
     list_display = ("backend_status_icon", "name", "enabled")
     list_display_links = ('backend_status_icon', 'name', )
     fieldsets = [(None,             {'fields': ['backend_status_text', 'name','enabled','versionNumber', 'description', "view_url", "icon_url", "service_specific_attribute",],
                                      'classes':['suit-tab suit-tab-general']}),
                  ("backend config", {'fields': [ "backend_network_label", "bbs_api_hostname", "bbs_api_port", "bbs_server", "bbs_slice"],
-                                     'classes':['suit-tab suit-tab-backend']}) ]
+                                     'classes':['suit-tab suit-tab-backend']}),
+                 ("vSG config", {'fields': [ "wan_container_gateway_ip", "wan_container_gateway_mac", "wan_container_netbits", "dns_servers"],
+                                     'classes':['suit-tab suit-tab-vsg']}) ]
     readonly_fields = ('backend_status_text', "service_specific_attribute")
     inlines = [SliceInline,ServiceAttrAsTabInline,ServicePrivilegeInline]
-    form = VCPEServiceForm
+    form = VSGServiceForm
 
     extracontext_registered_admins = True
 
@@ -145,6 +159,7 @@
 
     suit_form_tabs =(('general', 'Service Details'),
         ('backend', 'Backend Config'),
+        ('vsg', 'vSG Config'),
         ('administration', 'Administration'),
         #('tools', 'Tools'),
         ('slices','Slices'),
@@ -156,53 +171,57 @@
                            ) #('hpctools.html', 'top', 'tools') )
 
     def queryset(self, request):
-        return VCPEService.get_service_objects_by_user(request.user)
+        return VSGService.get_service_objects_by_user(request.user)
 
-class VCPETenantForm(forms.ModelForm):
+class VSGTenantForm(forms.ModelForm):
     bbs_account = forms.CharField(required=False)
     creator = forms.ModelChoiceField(queryset=User.objects.all())
     instance = forms.ModelChoiceField(queryset=Instance.objects.all(),required=False)
     last_ansible_hash = forms.CharField(required=False)
+    wan_container_ip = forms.CharField(required=False)
+    wan_container_mac = forms.CharField(required=False)
 
     def __init__(self,*args,**kwargs):
-        super (VCPETenantForm,self ).__init__(*args,**kwargs)
+        super (VSGTenantForm,self ).__init__(*args,**kwargs)
         self.fields['kind'].widget.attrs['readonly'] = True
-        self.fields['provider_service'].queryset = VCPEService.get_service_objects().all()
+        self.fields['provider_service'].queryset = VSGService.get_service_objects().all()
         if self.instance:
             # fields for the attributes
             self.fields['bbs_account'].initial = self.instance.bbs_account
             self.fields['creator'].initial = self.instance.creator
             self.fields['instance'].initial = self.instance.instance
             self.fields['last_ansible_hash'].initial = self.instance.last_ansible_hash
+            self.fields['wan_container_ip'].initial = self.instance.wan_container_ip
+            self.fields['wan_container_mac'].initial = self.instance.wan_container_mac
         if (not self.instance) or (not self.instance.pk):
             # default fields for an 'add' form
             self.fields['kind'].initial = VCPE_KIND
             self.fields['creator'].initial = get_request().user
-            if VCPEService.get_service_objects().exists():
-               self.fields["provider_service"].initial = VCPEService.get_service_objects().all()[0]
+            if VSGService.get_service_objects().exists():
+               self.fields["provider_service"].initial = VSGService.get_service_objects().all()[0]
 
     def save(self, commit=True):
         self.instance.creator = self.cleaned_data.get("creator")
         self.instance.instance = self.cleaned_data.get("instance")
         self.instance.last_ansible_hash = self.cleaned_data.get("last_ansible_hash")
-        return super(VCPETenantForm, self).save(commit=commit)
+        return super(VSGTenantForm, self).save(commit=commit)
 
     class Meta:
-        model = VCPETenant
+        model = VSGTenant
 
-class VCPETenantAdmin(ReadOnlyAwareAdmin):
+class VSGTenantAdmin(ReadOnlyAwareAdmin):
     list_display = ('backend_status_icon', 'id', 'subscriber_tenant' )
     list_display_links = ('backend_status_icon', 'id')
     fieldsets = [ (None, {'fields': ['backend_status_text', 'kind', 'provider_service', 'subscriber_tenant', 'service_specific_id', # 'service_specific_attribute',
-                                     'bbs_account', 'creator', 'instance', 'last_ansible_hash'],
+                                     'wan_container_ip', 'wan_container_mac', 'bbs_account', 'creator', 'instance', 'last_ansible_hash'],
                           'classes':['suit-tab suit-tab-general']})]
-    readonly_fields = ('backend_status_text', 'service_specific_attribute', 'bbs_account')
-    form = VCPETenantForm
+    readonly_fields = ('backend_status_text', 'service_specific_attribute', 'bbs_account', 'wan_container_ip', 'wan_container_mac')
+    form = VSGTenantForm
 
     suit_form_tabs = (('general','Details'),)
 
     def queryset(self, request):
-        return VCPETenant.get_tenant_objects_by_user(request.user)
+        return VSGTenant.get_tenant_objects_by_user(request.user)
 
 #-----------------------------------------------------------------------------
 # vBNG
@@ -362,8 +381,8 @@
 
 admin.site.register(VOLTService, VOLTServiceAdmin)
 admin.site.register(VOLTTenant, VOLTTenantAdmin)
-admin.site.register(VCPEService, VCPEServiceAdmin)
-admin.site.register(VCPETenant, VCPETenantAdmin)
+admin.site.register(VSGService, VSGServiceAdmin)
+admin.site.register(VSGTenant, VSGTenantAdmin)
 admin.site.register(VBNGService, VBNGServiceAdmin)
 admin.site.register(VBNGTenant, VBNGTenantAdmin)
 admin.site.register(CordSubscriberRoot, CordSubscriberRootAdmin)
diff --git a/xos/services/cord/models.py b/xos/services/cord/models.py
index bf20e86..37ee78e 100644
--- a/xos/services/cord/models.py
+++ b/xos/services/cord/models.py
@@ -1,5 +1,5 @@
 from django.db import models
-from core.models import Service, PlCoreBase, Slice, Instance, Tenant, TenantWithContainer, Node, Image, User, Flavor, Subscriber, NetworkParameter, NetworkParameterType, Port
+from core.models import Service, PlCoreBase, Slice, Instance, Tenant, TenantWithContainer, Node, Image, User, Flavor, Subscriber, NetworkParameter, NetworkParameterType, Port, AddressPool
 from core.models.plcorebase import StrippedCharField
 import os
 from django.db import models, transaction
@@ -10,44 +10,7 @@
 from core.models.service import LeastLoadedNodeScheduler
 import traceback
 from xos.exceptions import *
-
-"""
-import os
-import sys
-sys.path.append("/opt/xos")
-os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
-import django
-from core.models import *
-from services.hpc.models import *
-from services.cord.models import *
-django.setup()
-
-t = VOLTTenant()
-t.caller = User.objects.all()[0]
-t.save()
-
-for v in VOLTTenant.get_tenant_objects().all():
-    v.caller = User.objects.all()[0]
-    v.delete()
-
-for v in VCPETenant.get_tenant_objects().all():
-    v.caller = User.objects.all()[0]
-    v.delete()
-
-for v in VOLTTenant.get_tenant_objects().all():
-    v.caller = User.objects.all()[0]
-    v.delete()
-
-for v in VOLTTenant.get_tenant_objects().all():
-    if not v.creator:
-        v.creator= User.objects.all()[0]
-        v.save()
-
-for v in VCPETenant.get_tenant_objects().all():
-    if not v.creator:
-        v.creator= User.objects.all()[0]
-        v.save()
-"""
+from xos.config import Config
 
 class ConfigurationError(Exception):
     pass
@@ -57,6 +20,8 @@
 VBNG_KIND = "vBNG"
 CORD_SUBSCRIBER_KIND = "CordSubscriberRoot"
 
+CORD_USE_VTN = getattr(Config(), "networking_use_vtn", False)
+
 # -------------------------------------------
 # CordSubscriberRoot
 # -------------------------------------------
@@ -292,7 +257,7 @@
 
     @property
     def vcpe(self):
-        vcpe = self.get_newest_subscribed_tenant(VCPETenant)
+        vcpe = self.get_newest_subscribed_tenant(VSGTenant)
         if not vcpe:
             return None
 
@@ -346,11 +311,11 @@
             return
 
         if self.vcpe is None:
-            vcpeServices = VCPEService.get_service_objects().all()
-            if not vcpeServices:
-                raise XOSConfigurationError("No VCPE Services available")
+            vsgServices = VSGService.get_service_objects().all()
+            if not vsgServices:
+                raise XOSConfigurationError("No VSG Services available")
 
-            vcpe = VCPETenant(provider_service = vcpeServices[0],
+            vcpe = VSGTenant(provider_service = vsgServices[0],
                               subscriber_tenant = self)
             vcpe.caller = self.creator
             vcpe.save()
@@ -382,7 +347,7 @@
     def cleanup_orphans(self):
         # ensure vOLT only has one vCPE
         cur_vcpe = self.vcpe
-        for vcpe in list(self.get_subscribed_tenants(VCPETenant)):
+        for vcpe in list(self.get_subscribed_tenants(VSGTenant)):
             if (not cur_vcpe) or (vcpe.id != cur_vcpe.id):
                 # print "XXX clean up orphaned vcpe", vcpe
                 vcpe.delete()
@@ -428,24 +393,28 @@
 # VCPE
 # -------------------------------------------
 
-class VCPEService(Service):
+class VSGService(Service):
     KIND = VCPE_KIND
 
     simple_attributes = ( ("bbs_api_hostname", None),
                           ("bbs_api_port", None),
                           ("bbs_server", None),
-                          ("backend_network_label", "hpc_client"), )
+                          ("backend_network_label", "hpc_client"),
+                          ("wan_container_gateway_ip", ""),
+                          ("wan_container_gateway_mac", ""),
+                          ("wan_container_netbits", "24"),
+                          ("dns_servers", "8.8.8.8") )
 
     def __init__(self, *args, **kwargs):
-        super(VCPEService, self).__init__(*args, **kwargs)
+        super(VSGService, self).__init__(*args, **kwargs)
 
     class Meta:
         app_label = "cord"
-        verbose_name = "vCPE Service"
+        verbose_name = "vSG Service"
         proxy = True
 
     def allocate_bbs_account(self):
-        vcpes = VCPETenant.get_tenant_objects().all()
+        vcpes = VSGTenant.get_tenant_objects().all()
         bbs_accounts = [vcpe.bbs_account for vcpe in vcpes]
 
         # There's a bit of a race here; some other user could be trying to
@@ -474,7 +443,7 @@
             value = value.id
         self.set_attribute("bbs_slice_id", value)
 
-VCPEService.setup_simple_attributes()
+VSGService.setup_simple_attributes()
 
 #class STagBlock(PlCoreBase):
 #    instance = models.ForeignKey(Instance, related_name="s_tags")
@@ -483,7 +452,7 @@
 #
 #    def __unicode__(self): return u'%s' % (self.s_tag)
 
-class VCPETenant(TenantWithContainer):
+class VSGTenant(TenantWithContainer):
     class Meta:
         proxy = True
 
@@ -491,7 +460,8 @@
 
     sync_attributes = ("nat_ip", "nat_mac",
                        "lan_ip", "lan_mac",
-                       "wan_ip", "wan_mac", "wan_container_mac",
+                       "wan_ip", "wan_mac",
+                       "wan_container_ip", "wan_container_mac",
                        "private_ip", "private_mac",
                        "hpc_client_ip", "hpc_client_mac")
 
@@ -499,10 +469,11 @@
                           "container_id": None,
                           "users": [],
                           "bbs_account": None,
-                          "last_ansible_hash": None}
+                          "last_ansible_hash": None,
+                          "wan_container_ip": None}
 
     def __init__(self, *args, **kwargs):
-        super(VCPETenant, self).__init__(*args, **kwargs)
+        super(VSGTenant, self).__init__(*args, **kwargs)
         self.cached_vbng=None
 
     @property
@@ -582,6 +553,10 @@
                 addresses["hpc_client"] = (ns.ip, ns.mac)
         return addresses
 
+    # ------------------------------------------------------------------------
+    # The following IP addresses all come from the VM
+    # Note: They might not be useful for the VTN-vSG
+
     @property
     def nat_ip(self):
         return self.addresses.get("nat", (None,None) )[0]
@@ -606,11 +581,37 @@
     def wan_mac(self):
         return self.addresses.get("wan", (None, None) )[1]
 
+    # end of VM IP address stubs
+    # ------------------------------------------------------------------------
+
+    @property
+    def wan_container_ip(self):
+        if CORD_USE_VTN:
+            # When using VTN, wan_container_ip is stored and maintained inside
+            # of the vSG object.
+            return self.get_attribute("wan_container_ip", self.default_attributes["wan_container_ip"])
+        else:
+            # When not using VTN, wan_container_ip is the same as wan_ip.
+            # XXX Is this broken for multiple-containers-per-VM?
+            return self.wan_ip
+
+    @wan_container_ip.setter
+    def wan_container_ip(self, value):
+        if CORD_USE_VTN:
+            self.set_attribute("wan_container_ip", value)
+        else:
+            raise Exception("wan_container_ip.setter called on non-VTN CORD")
+
+    def ip_to_mac(self, ip):
+        (a, b, c, d) = ip.split('.')
+        return "02:42:%02x:%02x:%02x:%02x" % (int(a), int(b), int(c), int(d))
+
     # Generate the MAC for the container interface connected to WAN
     @property
     def wan_container_mac(self):
-        (a, b, c, d) = self.wan_ip.split('.')
-        return "02:42:%02x:%02x:%02x:%02x" % (int(a), int(b), int(c), int(d))
+        if not self.wan_container_ip:
+            return None
+        return self.ip_to_mac(self.wan_container_ip)
 
     @property
     def private_ip(self):
@@ -712,6 +713,7 @@
                         flavor = flavors[0],
                         isolation = slice.default_isolation,
                         parent = parent)
+
         self.save_instance(instance)
 
         return instance
@@ -726,19 +728,23 @@
         # provides us
         slice = self.get_slice()
         if slice.default_isolation in ["container_vm", "container"]:
-            super(VCPETenant,self).manage_container()
+            super(VSGTenant,self).manage_container()
             return
 
         if not self.volt:
             raise XOSConfigurationError("This vCPE container has no volt")
 
+        if self.instance:
+            # We're good.
+            return
+
         instance = self.find_or_make_instance_for_s_tag(self.volt.s_tag)
         self.instance = instance
         super(TenantWithContainer, self).save()
 
     def cleanup_container(self):
         if self.get_slice().default_isolation in ["container_vm", "container"]:
-            super(VCPETenant,self).cleanup_container()
+            super(VSGTenant,self).cleanup_container()
 
         # To-do: cleanup unused instances
         pass
@@ -749,14 +755,41 @@
 
         if self.volt and self.volt.subscriber and self.volt.subscriber.url_filter_enable:
             if not self.bbs_account:
-                # make sure we use the proxied VCPEService object, not the generic Service object
-                vcpe_service = VCPEService.objects.get(id=self.provider_service.id)
+                # make sure we use the proxied VSGService object, not the generic Service object
+                vcpe_service = VSGService.objects.get(id=self.provider_service.id)
                 self.bbs_account = vcpe_service.allocate_bbs_account()
-                super(VCPETenant, self).save()
+                super(VSGTenant, self).save()
         else:
             if self.bbs_account:
                 self.bbs_account = None
-                super(VCPETenant, self).save()
+                super(VSGTenant, self).save()
+
+    def get_wan_address_from_pool(self):
+        ap = AddressPool.objects.filter(name="public_addresses")
+        if not ap:
+            raise Exception("AddressPool 'public_addresses' does not exist. Please configure it.")
+        ap = ap[0]
+
+        addr = ap.get_address()
+        if not addr:
+            raise Exception("AddressPool 'public_addresses' has run out of addresses.")
+        return addr
+
+    def put_wan_address_to_pool(self, addr):
+        AddressPool.objects.filter(name="public_addresses")[0].put_address(addr)
+
+    def manage_wan_container_ip(self):
+        if CORD_USE_VTN:
+            if not self.wan_container_ip:
+                addr = self.get_wan_address_from_pool()
+
+                self.wan_container_ip = addr
+                super(TenantWithContainer, self).save()
+
+    def cleanup_wan_container_ip(self):
+        if CORD_USE_VTN and self.wan_container_ip:
+            self.put_wan_address_to_pool(self.wan_container_ip)
+            self.wan_container_ip = None
 
     def find_or_make_port(self, instance, network, **kwargs):
         port = Port.objects.filter(instance=instance, network=network)
@@ -767,16 +800,27 @@
             port.save()
         return port
 
+    def get_lan_network(self, instance):
+        slice = self.provider_service.slices.all()[0]
+        if CORD_USE_VTN:
+            # there should only be one network private network, and its template should not be the management template
+            lan_networks = [x for x in slice.networks.all() if x.template.visibility=="private" and (not "management" in x.template.name)]
+            if len(lan_networks)>1:
+                raise XOSProgrammingError("The vSG slice should only have one non-management private network")
+        else:
+            lan_networks = [x for x in slice.networks.all() if "lan" in x.name]
+        if not lan_networks:
+            raise XOSProgrammingError("No lan_network")
+        return lan_networks[0]
+
     def save_instance(self, instance):
         with transaction.atomic():
             instance.volumes = "/etc/dnsmasq.d,/etc/ufw"
-            super(VCPETenant, self).save_instance(instance)
+            super(VSGTenant, self).save_instance(instance)
 
             if instance.isolation in ["container", "container_vm"]:
-                lan_networks = [x for x in instance.slice.networks.all() if "lan" in x.name]
-                if not lan_networks:
-                    raise XOSProgrammingError("No lan_network")
-                port = self.find_or_make_port(instance, lan_networks[0], ip="192.168.0.1", port_id="unmanaged")
+                lan_network = self.get_lan_network(instance)
+                port = self.find_or_make_port(instance, lan_network, ip="192.168.0.1", port_id="unmanaged")
                 port.set_parameter("c_tag", self.volt.c_tag)
                 port.set_parameter("s_tag", self.volt.s_tag)
                 port.set_parameter("device", "eth1")
@@ -789,6 +833,14 @@
                 port.set_parameter("next_hop", value="10.0.1.253")   # FIX ME
                 port.set_parameter("device", "eth0")
 
+            if instance.isolation in ["vm"]:
+                lan_network = self.get_lan_network(instance)
+                port = self.find_or_make_port(instance, lan_network)
+                port.set_parameter("c_tag", self.volt.c_tag)
+                port.set_parameter("s_tag", self.volt.s_tag)
+                port.set_parameter("neutron_port_name", "stag-%s" % self.volt.s_tag)
+                port.save()
+
             # tag the instance with the s-tag, so we can easily find the
             # instance later
             if self.volt and self.volt.s_tag:
@@ -797,34 +849,41 @@
                     tag = Tag(service=self.provider_service, content_object=instance, name="s_tag", value=self.volt.s_tag)
                     tag.save()
 
+            # VTN-CORD needs a WAN address for the VM, so that the VM can
+            # be configured.
+            if CORD_USE_VTN:
+                tags = Tag.select_by_content_object(instance).filter(name="vm_wan_addr")
+                if not tags:
+                    address = self.get_wan_address_from_pool()
+                    tag = Tag(service=self.provider_service, content_object=instance, name="vm_wan_addr", value="%s,%s,%s" % ("public_addresses", address, self.ip_to_mac(address)))
+                    tag.save()
+
     def save(self, *args, **kwargs):
         if not self.creator:
             if not getattr(self, "caller", None):
                 # caller must be set when creating a vCPE since it creates a slice
-                raise XOSProgrammingError("VCPETenant's self.caller was not set")
+                raise XOSProgrammingError("VSGTenant's self.caller was not set")
             self.creator = self.caller
             if not self.creator:
-                raise XOSProgrammingError("VCPETenant's self.creator was not set")
+                raise XOSProgrammingError("VSGTenant's self.creator was not set")
 
-        super(VCPETenant, self).save(*args, **kwargs)
+        super(VSGTenant, self).save(*args, **kwargs)
         model_policy_vcpe(self.pk)
-        #self.manage_instance()
-        #self.manage_vbng()
-        #self.manage_bbs_account()
-        #self.cleanup_orphans()
 
     def delete(self, *args, **kwargs):
         self.cleanup_vbng()
         self.cleanup_container()
-        super(VCPETenant, self).delete(*args, **kwargs)
+        self.cleanup_wan_container_ip()
+        super(VSGTenant, self).delete(*args, **kwargs)
 
 def model_policy_vcpe(pk):
     # TODO: this should be made in to a real model_policy
     with transaction.atomic():
-        vcpe = VCPETenant.objects.select_for_update().filter(pk=pk)
+        vcpe = VSGTenant.objects.select_for_update().filter(pk=pk)
         if not vcpe:
             return
         vcpe = vcpe[0]
+        vcpe.manage_wan_container_ip()
         vcpe.manage_container()
         vcpe.manage_vbng()
         vcpe.manage_bbs_account()
diff --git a/xos/services/cord/templates/vcpeadmin.html b/xos/services/cord/templates/vcpeadmin.html
index a21dabe..c93f032 100644
--- a/xos/services/cord/templates/vcpeadmin.html
+++ b/xos/services/cord/templates/vcpeadmin.html
@@ -1,6 +1,6 @@
 <div class = "row text-center">
     <div class="col-xs-6">
-        <a class="btn btn-primary" href="/admin/cord/vcpetenant/">vCPE Tenants</a>
+        <a class="btn btn-primary" href="/admin/cord/vsgtenant/">vSG Tenants</a>
     </div>
     <div class="col-xs-6">
         <a class="btn btn-primary" href="/admin/dashboard/cord/">Subscriber View</a>
diff --git a/xos/services/onos/admin.py b/xos/services/onos/admin.py
index 3f9f96c..fb0f1d7 100644
--- a/xos/services/onos/admin.py
+++ b/xos/services/onos/admin.py
@@ -19,16 +19,28 @@
 from django.contrib.admin.utils import quote
 
 class ONOSServiceForm(forms.ModelForm):
-    use_external_host = forms.CharField(required=False)
+    rest_hostname = forms.CharField(required=False)
+    rest_port = forms.CharField(required=False)
+    no_container = forms.BooleanField(required=False)
+#    external_hostname = forms.CharField(required=False)
+#    external_container = forms.CharField(required=False)
 
     def __init__(self,*args,**kwargs):
         super (ONOSServiceForm,self ).__init__(*args,**kwargs)
         if self.instance:
             # fields for the attributes
-            self.fields['use_external_host'].initial = self.instance.use_external_host
+            self.fields['rest_hostname'].initial = self.instance.rest_hostname
+            self.fields['rest_port'].initial = self.instance.rest_port
+            self.fields['no_container'].initial = self.instance.no_container
+#            self.fields['external_hostname'].initial = self.instance.external_hostname
+#            self.fields['external_container'].initial = self.instance.external_hostname
 
     def save(self, commit=True):
-        self.instance.use_external_host = self.cleaned_data.get("use_external_host")
+        self.instance.rest_hostname = self.cleaned_data.get("rest_hostname")
+        self.instance.rest_port = self.cleaned_data.get("rest_port")
+        self.instance.no_container = self.cleaned_data.get("no_container")
+#        self.instance.external_hostname = self.cleaned_data.get("external_hostname")
+#        self.instance.external_container = self.cleaned_data.get("external_container")
         return super(ONOSServiceForm, self).save(commit=commit)
 
     class Meta:
@@ -40,7 +52,7 @@
     verbose_name_plural = "ONOS Services"
     list_display = ("backend_status_icon", "name", "enabled")
     list_display_links = ('backend_status_icon', 'name', )
-    fieldsets = [(None, {'fields': ['backend_status_text', 'name','enabled','versionNumber', 'description',"view_url","icon_url", "use_external_host" ], 'classes':['suit-tab suit-tab-general']})]
+    fieldsets = [(None, {'fields': ['backend_status_text', 'name','enabled','versionNumber', 'description',"view_url","icon_url", "rest_hostname", "rest_port", "no_container" ], 'classes':['suit-tab suit-tab-general']})]
     readonly_fields = ('backend_status_text', )
     inlines = [SliceInline,ServiceAttrAsTabInline,ServicePrivilegeInline]
     form = ONOSServiceForm
diff --git a/xos/services/onos/models.py b/xos/services/onos/models.py
index 1e869d1..20fa73f 100644
--- a/xos/services/onos/models.py
+++ b/xos/services/onos/models.py
@@ -21,15 +21,43 @@
         verbose_name = "ONOS Service"
         proxy = True
 
-    default_attributes = {"use_external_host": ""}
+    default_attributes = {"rest_hostname": "",
+                          "rest_port": "8181",
+                          "no_container": False,
+                          "node_key": ""}
 
     @property
-    def use_external_host(self):
-        return self.get_attribute("use_external_host", self.default_attributes["use_external_host"])
+    def rest_hostname(self):
+        return self.get_attribute("rest_hostname", self.default_attributes["rest_hostname"])
 
-    @use_external_host.setter
-    def use_external_host(self, value):
-        self.set_attribute("use_external_host", value)
+    @rest_hostname.setter
+    def rest_hostname(self, value):
+        self.set_attribute("rest_hostname", value)
+
+    @property
+    def rest_port(self):
+        return self.get_attribute("rest_port", self.default_attributes["rest_port"])
+
+    @rest_port.setter
+    def rest_port(self, value):
+        self.set_attribute("rest_port", value)
+
+    @property
+    def no_container(self):
+        return self.get_attribute("no_container", self.default_attributes["no_container"])
+
+    @no_container.setter
+    def no_container(self, value):
+        self.set_attribute("no_container", value)
+
+    @property
+    def node_key(self):
+        return self.get_attribute("node_key", self.default_attributes["node_key"])
+
+    @node_key.setter
+    def node_key(self, value):
+        self.set_attribute("node_key", value)
+
 
 class ONOSApp(Tenant):   # aka 'ONOSTenant'
     class Meta:
@@ -93,19 +121,6 @@
     def install_dependencies(self, value):
         self.set_attribute("install_dependencies", value)
 
-    #@property
-    #def instance(self):
-    #    instance_id = self.get_attribute("instance_id", self.default_attributes["instance_id"])
-    #    if instance_id:
-    #        instances = Instance.objects.filter(id=instance_id)
-    #        if instances:
-    #            return instances[0]
-    #    return None
-
-    #@instance.setter
-    #def instance(self, value):
-    #    self.set_attribute("instance_id", value.id)
-
     def save(self, *args, **kwargs):
         if not self.creator:
             if not getattr(self, "caller", None):
diff --git a/xos/synchronizers/base/SyncInstanceUsingAnsible.py b/xos/synchronizers/base/SyncInstanceUsingAnsible.py
index 335932f..04b98df 100644
--- a/xos/synchronizers/base/SyncInstanceUsingAnsible.py
+++ b/xos/synchronizers/base/SyncInstanceUsingAnsible.py
@@ -15,10 +15,10 @@
 
 class SyncInstanceUsingAnsible(SyncStep):
     # All of the following should be defined for classes derived from this
-    # base class. Examples below use VCPETenant.
+    # base class. Examples below use VSGTenant.
 
-    # provides=[VCPETenant]
-    # observes=VCPETenant
+    # provides=[VSGTenant]
+    # observes=VSGTenant
     # requested_interval=0
     # template_name = "sync_vcpetenant.yaml"
     # service_key_name = "/opt/xos/observers/vcpe/vcpe_private_key"
@@ -26,6 +26,12 @@
     def __init__(self, **args):
         SyncStep.__init__(self, **args)
 
+    def skip_ansible_fields(self, o):
+        # Return True if the instance processing and get_ansible_fields stuff
+        # should be skipped. This hook is primarily for the OnosApp
+        # sync step, so it can do its external REST API sync thing.
+        return False
+
     def defer_sync(self, o, reason):
         logger.info("defer object %s due to %s" % (str(o), reason))
         raise Exception("defer object %s due to %s" % (str(o), reason))
@@ -44,6 +50,14 @@
 
         return o.instance
 
+    def get_external_sync(self, o):
+        hostname = getattr(o, "external_hostname", None)
+        container = getattr(o, "external_container", None)
+        if hostname and container:
+            return (hostname, container)
+        else:
+            return None
+
     def run_playbook(self, o, fields, template_name=None):
         if not template_name:
             template_name = self.template_name
@@ -80,6 +94,7 @@
                        "hostname": instance.node.name,
                        "instance_id": instance.instance_id,
                        "username": "ubuntu",
+                       "ssh_ip": instance.get_ssh_ip(),
                      }
             key_name = self.service_key_name
         elif (instance.isolation == "container"):
@@ -91,6 +106,7 @@
                        "instance_name": "rootcontext",
                        "username": "root",
                        "container_name": "%s-%s" % (instance.slice.name, str(instance.id))
+                       # ssh_ip is not used for container-on-metal
                      }
             key_name = self.get_node_key(node)
         else:
@@ -107,7 +123,7 @@
                        "instance_name": instance.parent.name,
                        "instance_id": instance.parent.instance_id,
                        "username": "ubuntu",
-                       "nat_ip": instance.parent.get_ssh_ip(),
+                       "ssh_ip": instance.parent.get_ssh_ip(),
                        "container_name": "%s-%s" % (instance.slice.name, str(instance.id))
                          }
             key_name = instance.parent.slice.service.private_key_fn
@@ -131,9 +147,9 @@
 
         fields.update({"keystone_tenant_id": cslice.tenant_id,
                        "keystone_user_id": cuser.kuser_id,
-                       "rabbit_user": instance.controller.rabbit_user,
-                       "rabbit_password": instance.controller.rabbit_password,
-                       "rabbit_host": instance.controller.rabbit_host})
+                       "rabbit_user": getattr(instance.controller,"rabbit_user", None),
+                       "rabbit_password": getattr(instance.controller, "rabbit_password", None),
+                       "rabbit_host": getattr(instance.controller, "rabbit_host", None)})
 
         return fields
 
@@ -142,30 +158,43 @@
 
         self.prepare_record(o)
 
-        instance = self.get_instance(o)
-
-        if isinstance(instance, basestring):
-            # sync to some external host
-
-            # XXX - this probably needs more work...
-
-            fields = { "hostname": instance,
-                       "instance_id": "ubuntu",     # this is the username to log into
-                       "private_key": service.key,
-                     }
+        if self.skip_ansible_fields(o):
+            fields = {}
         else:
-            # sync to an XOS instance
-            if not instance:
-                self.defer_sync(o, "waiting on instance")
-                return
+            if self.get_external_sync(o):
+                # sync to some external host
 
-            if not instance.instance_name:
-                self.defer_sync(o, "waiting on instance.instance_name")
-                return
+                # UNTESTED
 
-            fields = self.get_ansible_fields(instance)
+                (hostname, container_name) = self.get_external_sync(o)
+                fields = { "hostname": hostname,
+                           "baremetal_ssh": True,
+                           "instance_name": "rootcontext",
+                           "username": "root",
+                           "container_name": container_name
+                         }
+                key_name = self.get_node_key(node)
+                if not os.path.exists(key_name):
+                    raise Exception("Node key %s does not exist" % key_name)
 
-            fields["ansible_tag"] =  o.__class__.__name__ + "_" + str(o.id)
+                key = file(key_name).read()
+
+                fields["private_key"] = key
+                # TO DO: Ceilometer stuff
+            else:
+                instance = self.get_instance(o)
+                # sync to an XOS instance
+                if not instance:
+                    self.defer_sync(o, "waiting on instance")
+                    return
+
+                if not instance.instance_name:
+                    self.defer_sync(o, "waiting on instance.instance_name")
+                    return
+
+                fields = self.get_ansible_fields(instance)
+
+        fields["ansible_tag"] =  o.__class__.__name__ + "_" + str(o.id)
 
         # If 'o' defines a 'sync_attributes' list, then we'll copy those
         # attributes into the Ansible recipe's field list automatically.
diff --git a/xos/synchronizers/base/SyncSliverUsingAnsible.py b/xos/synchronizers/base/SyncSliverUsingAnsible.py
deleted file mode 100644
index c64e5ea..0000000
--- a/xos/synchronizers/base/SyncSliverUsingAnsible.py
+++ /dev/null
@@ -1,95 +0,0 @@
-import hashlib
-import os
-import socket
-import sys
-import base64
-import time
-from django.db.models import F, Q
-from xos.config import Config
-from synchronizers.base.syncstep import SyncStep
-from synchronizers.base.ansible import run_template_ssh
-from core.models import Service, Slice
-from xos.logger import Logger, logging
-
-logger = Logger(level=logging.INFO)
-
-class SyncInstanceUsingAnsible(SyncStep):
-    # All of the following should be defined for classes derived from this
-    # base class. Examples below use VCPETenant.
-
-    # provides=[VCPETenant]
-    # observes=VCPETenant
-    # requested_interval=0
-    # template_name = "sync_vcpetenant.yaml"
-    # service_key_name = "/opt/xos/observers/vcpe/vcpe_private_key"
-
-    def __init__(self, **args):
-        SyncStep.__init__(self, **args)
-
-    def defer_sync(self, o, reason):
-        logger.info("defer object %s due to %s" % (str(o), reason))
-        raise Exception("defer object %s due to %s" % (str(o), reason))
-
-    def get_extra_attributes(self, o):
-        # This is a place to include extra attributes that aren't part of the
-        # object itself.
-
-        return {}
-
-    def get_instance(self, o):
-        # We need to know what instance is associated with the object. Let's
-        # assume 'o' has a field called 'instance'. If the field is called
-        # something else, or if custom logic is needed, then override this
-        # method.
-
-        return o.instance
-
-    def run_playbook(self, o, fields):
-        tStart = time.time()
-        run_template_ssh(self.template_name, fields)
-        logger.info("playbook execution time %d" % int(time.time()-tStart))
-
-    def pre_sync_hook(self, o, fields):
-        pass
-
-    def post_sync_hook(self, o, fields):
-        pass
-
-    def sync_fields(self, o, fields):
-        self.run_playbook(o, fields)
-
-    def sync_record(self, o):
-        logger.info("sync'ing object %s" % str(o))
-
-        instance = self.get_instance(o)
-        if not instance:
-            self.defer_sync(o, "waiting on instance")
-            return
-
-        if not os.path.exists(self.service_key_name):
-            raise Exception("Service key %s does not exist" % self.service_key_name)
-
-        service_key = file(self.service_key_name).read()
-
-        fields = { "instance_name": instance.name,
-                   "hostname": instance.node.name,
-                   "instance_id": instance.instance_id,
-                   "private_key": service_key,
-                   "ansible_tag": "vcpe_tenant_" + str(o.id)
-                 }
-
-        # If 'o' defines a 'sync_attributes' list, then we'll copy those
-        # attributes into the Ansible recipe's field list automatically.
-        if hasattr(o, "sync_attributes"):
-            for attribute_name in o.sync_attributes:
-                fields[attribute_name] = getattr(o, attribute_name)
-
-        fields.update(self.get_extra_attributes(o))
-
-        self.sync_fields(o, fields)
-
-        o.save()
-
-    def delete_record(self, m):
-        pass
-
diff --git a/xos/synchronizers/base/ansible.py b/xos/synchronizers/base/ansible.py
index d2dca3b..d92835a 100644
--- a/xos/synchronizers/base/ansible.py
+++ b/xos/synchronizers/base/ansible.py
@@ -34,11 +34,20 @@
         if (l.startswith(magic_str)):
             w = len(magic_str)
             str = l[w:]
+
+            # handle ok: [127.0.0.1] => (item=org.onosproject.driver) => {...
+            if str.startswith("(") and (" => {" in str):
+                str = str.split("=> ",1)[1]
+
             d = json.loads(str)
             results.append(d)
         elif (l.startswith(magic_str2)):
             w = len(magic_str2)
             str = l[w:]
+
+            if str.startswith("(") and (" => {" in str):
+                str = str.split("=> ",1)[1]
+
             d = json.loads(str)
             results.append(d)
 
@@ -149,12 +158,12 @@
     private_key = opts["private_key"]
     baremetal_ssh = opts.get("baremetal_ssh",False)
     if baremetal_ssh:
-        # no instance_id or nat_ip for baremetal
+        # no instance_id or ssh_ip for baremetal
         # we never proxy to baremetal
         proxy_ssh = False
     else:
         instance_id = opts["instance_id"]
-        nat_ip = opts["nat_ip"]
+        ssh_ip = opts["ssh_ip"]
         try:
             proxy_ssh = Config().observer_proxy_ssh
         except:
@@ -172,7 +181,15 @@
     f = open(config_pathname, "w")
     f.write("[ssh_connection]\n")
     if proxy_ssh:
-        proxy_command = "ProxyCommand ssh -q -i %s -o StrictHostKeyChecking=no %s@%s" % (private_key_pathname, instance_id, hostname)
+        proxy_ssh_key = getattr(Config(), "observer_proxy_ssh_key", None)
+        proxy_ssh_user = getattr(Config(), "observer_proxy_ssh_user", "root")
+        if proxy_ssh_key:
+            # If proxy_ssh_key is known, then we can proxy into the compute
+            # node without needing to have the OpenCloud sshd machinery in
+            # place.
+            proxy_command = "ProxyCommand ssh -q -i %s -o StrictHostKeyChecking=no %s@%s nc %s 22" % (proxy_ssh_key, proxy_ssh_user, hostname, ssh_ip)
+        else:
+            proxy_command = "ProxyCommand ssh -q -i %s -o StrictHostKeyChecking=no %s@%s" % (private_key_pathname, instance_id, hostname)
         f.write('ssh_args = -o "%s"\n' % proxy_command)
     f.write('scp_if_ssh = True\n')
     f.write('pipelining = True\n')
@@ -186,7 +203,7 @@
         f.write("%s ansible_ssh_private_key_file=%s\n" % (hostname, private_key_pathname))
     else:
         # acb: Login user is hardcoded, this is not great
-        f.write("%s ansible_ssh_private_key_file=%s ansible_ssh_user=ubuntu\n" % (nat_ip, private_key_pathname))
+        f.write("%s ansible_ssh_private_key_file=%s ansible_ssh_user=ubuntu\n" % (ssh_ip, private_key_pathname))
     f.close()
 
     # SSH will complain if private key is world or group readable
diff --git a/xos/synchronizers/base/event_loop.py b/xos/synchronizers/base/event_loop.py
index 6cfc9f6..c1b9cda 100644
--- a/xos/synchronizers/base/event_loop.py
+++ b/xos/synchronizers/base/event_loop.py
@@ -421,7 +421,7 @@
 				except Exception,e:
                         		self.consolePrint(bcolors.FAIL + "Model step %r failed" % (sync_step.__name__) + bcolors.ENDC)
 					logger.error('Model step %r failed. This seems like a misconfiguration or bug: %r. This error will not be relayed to the user!' % (sync_step.__name__, e))
-					logger.log_exc(e)
+					logger.log_exc("Exception in sync step")
 					self.failed_steps.append(S)
 					my_status = STEP_STATUS_KO
 			else:
diff --git a/xos/synchronizers/base/syncstep.py b/xos/synchronizers/base/syncstep.py
index bdab8f3..54c4b89 100644
--- a/xos/synchronizers/base/syncstep.py
+++ b/xos/synchronizers/base/syncstep.py
@@ -142,10 +142,10 @@
     def sync_record(self, o):
         try:
             controller = o.get_controller()
-            controller_register = json.loads(o.node.site_deployment.controller.backend_register)
+            controller_register = json.loads(controller.backend_register)
 
             if (controller_register.get('disabled',False)):
-                raise InnocuousException('Controller %s is disabled'%sliver.node.site_deployment.controller.name)
+                raise InnocuousException('Controller %s is disabled'%controller.name)
         except AttributeError:
             pass
 
@@ -249,7 +249,7 @@
                     except:
                         error = '%s'%str_e
 
-                    if isinstance(e, InnocuousException) and not force_error:
+                    if isinstance(e, InnocuousException):
                         o.backend_status = '1 - %s'%error
                     else:
                         o.backend_status = '2 - %s'%error
diff --git a/xos/synchronizers/hpc/run.sh b/xos/synchronizers/hpc/run.sh
index f77d751..9d22047 100755
--- a/xos/synchronizers/hpc/run.sh
+++ b/xos/synchronizers/hpc/run.sh
@@ -1,6 +1,2 @@
-#if [[ ! -e ./hpc-backend.py ]]; then
-#    ln -s ../xos-observer.py hpc-backend.py
-#fi
-
 export XOS_DIR=/opt/xos
-python hpc-observer.py  -C $XOS_DIR/observers/hpc/hpc_observer_config
+python hpc-synchronizer.py  -C $XOS_DIR/synchronizers/hpc/hpc_synchronizer_config
diff --git a/xos/synchronizers/hpc/start.sh b/xos/synchronizers/hpc/start.sh
index 305c07f..3153a7d 100755
--- a/xos/synchronizers/hpc/start.sh
+++ b/xos/synchronizers/hpc/start.sh
@@ -1,6 +1,2 @@
-#if [[ ! -e ./hpc-backend.py ]]; then
-#    ln -s ../xos-observer.py hpc-backend.py
-#fi
-
 export XOS_DIR=/opt/xos
-nohup python hpc-observer.py  -C $XOS_DIR/observers/hpc/hpc_observer_config > /dev/null 2>&1 &
+nohup python hpc-synchronizer.py  -C $XOS_DIR/synchronizers/hpc/hpc_synchronizer_config > /dev/null 2>&1 &
diff --git a/xos/synchronizers/hpc/stop.sh b/xos/synchronizers/hpc/stop.sh
index a0b4a8e..780e25c 100755
--- a/xos/synchronizers/hpc/stop.sh
+++ b/xos/synchronizers/hpc/stop.sh
@@ -1 +1 @@
-pkill -9 -f hpc-observer.py
+pkill -9 -f hpc-synchronizer.py
diff --git a/xos/synchronizers/monitoring_channel/steps/sync_monitoringchannel.yaml b/xos/synchronizers/monitoring_channel/steps/sync_monitoringchannel.yaml
index 6cda511..06403a6 100644
--- a/xos/synchronizers/monitoring_channel/steps/sync_monitoringchannel.yaml
+++ b/xos/synchronizers/monitoring_channel/steps/sync_monitoringchannel.yaml
@@ -85,6 +85,32 @@
      - remove container
      - start monitoring-channel
 
+#  - name: Start monitoring-channel container
+#    docker:
+#      docker_api_version: "1.18"
+#      name: monitoring-channel-{{ unique_id }}
+#      # was: reloaded
+#      state: running
+#      image: srikanthvavila/monitoring-channel
+#      expose:
+#      - 8000
+#      ports:
+#      - "{{ ceilometer_port }}:8000"
+#      volumes:
+#      - /usr/local/share/monitoring-channel-{{ unique_id }}_ceilometer_proxy_config:/usr/local/share/ceilometer_proxy_config
+#
+#  - name: Get Docker IP
+#    #TODO: copy dockerip.sh to monitoring service synchronizer
+#    script: /opt/xos/synchronizers/onos/scripts/dockerip.sh monitoring-channel-{{ unique_id }}
+#    register: dockerip
+#
+#  - name: Wait for Monitoring channel to come up
+#    wait_for:
+#      host={{ '{{' }} dockerip.stdout {{ '}}' }}
+#      port={{ '{{' }} item {{ '}}' }}
+#      state=present
+#    with_items:
+#    - {{ ceilometer_port }}
 # These are samples, not necessary for correct function of demo
 
   - name: Make sure Monitoring channel service is running
diff --git a/xos/synchronizers/monitoring_channel/steps/sync_sflowservice.py b/xos/synchronizers/monitoring_channel/steps/sync_sflowservice.py
index 5e5cd83..154c5ab 100644
--- a/xos/synchronizers/monitoring_channel/steps/sync_sflowservice.py
+++ b/xos/synchronizers/monitoring_channel/steps/sync_sflowservice.py
@@ -55,7 +55,6 @@
         fields["instance_hostname"] = self.get_instance(o).instance_name.replace("_","-")
         fields["sflow_port"] = o.sflow_port
         fields["sflow_api_port"] = o.sflow_api_port
-        fields["nat_ip"] = self.get_instance(o).get_ssh_ip()
         fields["sflow_container"] = "sflowpubsub"
         return fields
 
diff --git a/xos/synchronizers/monitoring_channel/steps/sync_sflowtenant.py b/xos/synchronizers/monitoring_channel/steps/sync_sflowtenant.py
index 6de0374..a15fa54 100644
--- a/xos/synchronizers/monitoring_channel/steps/sync_sflowtenant.py
+++ b/xos/synchronizers/monitoring_channel/steps/sync_sflowtenant.py
@@ -64,7 +64,6 @@
         instance = self.get_instance(o)
 
         fields={}
-        fields["nat_ip"] = instance.get_ssh_ip()
         fields["sflow_api_base_url"] = self.get_sflow_service(o).sflow_api_url
         fields["sflow_api_port"] = self.get_sflow_service(o).sflow_api_port
         fields["listening_endpoint"] = o.listening_endpoint
diff --git a/xos/synchronizers/monitoring_channel/templates/start-monitoring-channel.sh.j2 b/xos/synchronizers/monitoring_channel/templates/start-monitoring-channel.sh.j2
index f56c247..ea5b639 100755
--- a/xos/synchronizers/monitoring_channel/templates/start-monitoring-channel.sh.j2
+++ b/xos/synchronizers/monitoring_channel/templates/start-monitoring-channel.sh.j2
@@ -22,7 +22,12 @@
 then
     #sudo docker build -t monitoring-channel -f Dockerfile.monitoring_channel .
     sudo docker pull srikanthvavila/monitoring-channel
+if [ -z "$HEADNODEFLATLANIP" ] || [ "$HEADNODEFLATLANIP" == "None" ]
+then
+    docker run -d --name=$MONITORING_CHANNEL --privileged=true -p $HOST_FORWARDING_PORT_FOR_CEILOMETER:8000 srikanthvavila/monitoring-channel
+else
     docker run -d --name=$MONITORING_CHANNEL --add-host="ctl:$HEADNODEFLATLANIP" --privileged=true -p $HOST_FORWARDING_PORT_FOR_CEILOMETER:8000 srikanthvavila/monitoring-channel
+fi
 else
     docker start $MONITORING_CHANNEL
 fi
diff --git a/xos/synchronizers/onos/onos-ext-notifier-1.0-SNAPSHOT.oar b/xos/synchronizers/onos/onos-ext-notifier-1.0-SNAPSHOT.oar
index 893c01a..23c6fcd 100644
--- a/xos/synchronizers/onos/onos-ext-notifier-1.0-SNAPSHOT.oar
+++ b/xos/synchronizers/onos/onos-ext-notifier-1.0-SNAPSHOT.oar
Binary files differ
diff --git a/xos/synchronizers/onos/onos-ext-volt-event-publisher-1.0-SNAPSHOT.oar b/xos/synchronizers/onos/onos-ext-volt-event-publisher-1.0-SNAPSHOT.oar
index 7a32268..244f589 100644
--- a/xos/synchronizers/onos/onos-ext-volt-event-publisher-1.0-SNAPSHOT.oar
+++ b/xos/synchronizers/onos/onos-ext-volt-event-publisher-1.0-SNAPSHOT.oar
Binary files differ
diff --git a/xos/synchronizers/onos/steps/sync_onosapp.py b/xos/synchronizers/onos/steps/sync_onosapp.py
index 8942e59..2dfdfbd 100644
--- a/xos/synchronizers/onos/steps/sync_onosapp.py
+++ b/xos/synchronizers/onos/steps/sync_onosapp.py
@@ -7,8 +7,10 @@
 import time
 import re
 import json
+from collections import OrderedDict
 from django.db.models import F, Q
 from xos.config import Config
+from synchronizers.base.ansible import run_template
 from synchronizers.base.syncstep import SyncStep
 from synchronizers.base.ansible import run_template_ssh
 from synchronizers.base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible
@@ -46,8 +48,8 @@
 
         serv = self.get_onos_service(o)
 
-        if serv.use_external_host:
-            return serv.use_external_host
+        if serv.no_container:
+            raise Exception("get_instance() was called on a service that was marked no_container")
 
         if serv.slices.exists():
             slice = serv.slices.all()[0]
@@ -66,6 +68,12 @@
 
         return onoses[0]
 
+    def is_no_container(self, o):
+        return self.get_onos_service(o).no_container
+
+    def skip_ansible_fields(self, o):
+        return self.is_no_container(o)
+
     def get_files_dir(self, o):
         if not hasattr(Config(), "observer_steps_dir"):
             # make steps_dir mandatory; there's no valid reason for it to not
@@ -125,8 +133,15 @@
 
         ordered_attrs = attrs.keys()
 
+        onos = self.get_onos_service(o)
+        if onos.node_key:
+            file(os.path.join(o.files_dir, "node_key"),"w").write(onos.node_key)
+            o.node_key_fn="node_key"
+        else:
+            o.node_key_fn=None
+
         o.early_rest_configs=[]
-        if ("cordvtn" in o.dependencies):
+        if ("cordvtn" in o.dependencies) and (not self.is_no_container(o)):
             # For VTN, since it's running in a docker host container, we need
             # to make sure it configures the cluster using the right ip addresses.
             # NOTE: rest_onos/v1/cluster/configuration/ will reboot the cluster and
@@ -155,7 +170,7 @@
                 file(os.path.join(o.files_dir, fn),"w").write(" " +value)
                 o.rest_configs.append( {"endpoint": endpoint, "fn": fn} )
             if name.startswith("component_config"):
-                components = json.loads(value)
+                components = json.loads(value,object_pairs_hook=OrderedDict)
                 for component in components.keys():
                     config = components[component]
                     for key in config.keys():
@@ -172,22 +187,37 @@
     def prepare_record(self, o):
         self.write_configs(o)
 
-    def get_extra_attributes(self, o):
-        instance = self.get_instance(o)
+    def get_extra_attributes_common(self, o):
+        fields = {}
 
-        fields={}
+        # These are attributes that are not dependent on Instance. For example,
+        # REST API stuff.
+
+        onos = self.get_onos_service(o)
+
         fields["files_dir"] = o.files_dir
         fields["appname"] = o.name
-        fields["nat_ip"] = instance.get_ssh_ip()
-        fields["config_fns"] = o.config_fns
         fields["rest_configs"] = o.rest_configs
-        fields["early_rest_configs"] = o.early_rest_configs
-        fields["component_configs"] = o.component_configs
+        fields["rest_hostname"] = onos.rest_hostname
+        fields["rest_port"] = onos.rest_port
+
         if o.dependencies:
             fields["dependencies"] = [x.strip() for x in o.dependencies.split(",")]
         else:
             fields["dependencies"] = []
 
+        return fields
+
+    def get_extra_attributes_full(self, o):
+        instance = self.get_instance(o)
+
+        fields = self.get_extra_attributes_common(o)
+
+        fields["config_fns"] = o.config_fns
+        fields["early_rest_configs"] = o.early_rest_configs
+        fields["component_configs"] = o.component_configs
+        fields["node_key_fn"] = o.node_key_fn
+
         if o.install_dependencies:
             fields["install_dependencies"] = [x.strip() for x in o.install_dependencies.split(",")]
         else:
@@ -199,12 +229,23 @@
             fields["ONOS_container"] = "ONOS"
         return fields
 
+    def get_extra_attributes(self, o):
+        if self.is_no_container(o):
+            return self.get_extra_attributes_common(o)
+        else:
+            return self.get_extra_attributes_full(o)
+
     def sync_fields(self, o, fields):
         # the super causes the playbook to be run
         super(SyncONOSApp, self).sync_fields(o, fields)
 
     def run_playbook(self, o, fields):
-        super(SyncONOSApp, self).run_playbook(o, fields)
+        if self.is_no_container(o):
+            # There is no machine to SSH to, so use the synchronizer's
+            # run_template method directly.
+            run_template("sync_onosapp_nocontainer.yaml", fields)
+        else:
+            super(SyncONOSApp, self).run_playbook(o, fields)
 
     def delete_record(self, m):
         pass
diff --git a/xos/synchronizers/onos/steps/sync_onosapp.yaml b/xos/synchronizers/onos/steps/sync_onosapp.yaml
index f0af0d6..8235286 100644
--- a/xos/synchronizers/onos/steps/sync_onosapp.yaml
+++ b/xos/synchronizers/onos/steps/sync_onosapp.yaml
@@ -50,6 +50,16 @@
       path=/home/ubuntu/{{ appname }}/
       state=directory
 
+{% if node_key_fn %}
+  - name: Copy over key
+    copy:
+      src={{ files_dir }}/{{ node_key_fn }}
+      dest=/home/ubuntu/node_key
+
+  - name: Copy node key into container
+    shell: docker cp /home/ubuntu/node_key {{ ONOS_container }}:/root/node_key
+{% endif %}
+
 {% if config_fns %}
   - name: Copy over configuration files
     copy:
diff --git a/xos/synchronizers/onos/steps/sync_onosapp_nocontainer.yaml b/xos/synchronizers/onos/steps/sync_onosapp_nocontainer.yaml
new file mode 100644
index 0000000..5aad569
--- /dev/null
+++ b/xos/synchronizers/onos/steps/sync_onosapp_nocontainer.yaml
@@ -0,0 +1,57 @@
+---
+- hosts: 127.0.0.1
+  connection: local
+  vars:
+    appname: {{ appname }}
+    dependencies: {{ dependencies }}
+{% if component_configs %}
+    component_configs:
+{% for component_config in component_configs %}
+       - component: {{ component_config.component }}
+         config_params: {{  component_config.config_params }}
+{% endfor %}
+{% endif %}
+{% if rest_configs %}
+    rest_configs:
+{% for rest_config in rest_configs %}
+       - endpoint: {{ rest_config.endpoint }}
+         body: "{{ '{{' }} lookup('file', '{{ files_dir }}/{{ rest_config.fn }}') {{ '}}' }}"
+{% endfor %}
+{% endif %}
+{% if early_rest_configs %}
+    early_rest_configs:
+{% for early_rest_config in early_rest_configs %}
+       - endpoint: {{ early_rest_config.endpoint }}
+         body: "{{ '{{' }} lookup('file', '{{ files_dir }}/{{ early_rest_config.fn }}') {{ '}}' }}"
+{% endfor %}
+{% endif %}
+    rest_hostname: {{ rest_hostname }}
+    rest_port: {{ rest_port }}
+
+  tasks:
+{% if dependencies %}
+  - name: Add dependencies to ONOS
+    uri:
+      url: http://{{ '{{' }} rest_hostname {{ '}}' }}:{{ '{{' }} rest_port {{ '}}' }}/onos/v1/applications/{{ '{{' }} item {{ '}}' }}/active
+      method: POST
+      user: karaf
+      password: karaf
+    with_items:
+        {% for dependency in dependencies %}
+        - {{ dependency }}
+        {% endfor %}
+{% endif %}
+
+{% if rest_configs %}
+# Do this after services have been activated, or it will cause an exception.
+# vOLT will re-read its net config; vbng may not.
+  - name: Add ONOS configuration values
+    uri:
+      url: http://{{ '{{' }} rest_hostname {{ '}}' }}:{{ '{{' }} rest_port {{ '}}' }}/{{ '{{' }} item.endpoint {{ '}}' }} #http://localhost:8181/onos/v1/network/configuration/
+      body: "{{ '{{' }} item.body {{ '}}' }}"
+      body_format: raw
+      method: POST
+      user: karaf
+      password: karaf
+    with_items: "rest_configs"
+{% endif %}
diff --git a/xos/synchronizers/onos/steps/sync_onosservice.py b/xos/synchronizers/onos/steps/sync_onosservice.py
index e70be0c..944a05c 100644
--- a/xos/synchronizers/onos/steps/sync_onosservice.py
+++ b/xos/synchronizers/onos/steps/sync_onosservice.py
@@ -43,9 +43,6 @@
 
         serv = o
 
-        if serv.use_external_host:
-            return serv.use_external_host
-
         if serv.slices.exists():
             slice = serv.slices.all()[0]
             if slice.instances.exists():
@@ -57,10 +54,16 @@
         fields={}
         fields["instance_hostname"] = self.get_instance(o).instance_name.replace("_","-")
         fields["appname"] = o.name
-        fields["nat_ip"] = self.get_instance(o).get_ssh_ip()
         fields["ONOS_container"] = "ONOS"
         return fields
 
+    def sync_record(self, o):
+        if o.no_container:
+            logger.info("no work to do for onos service, because o.no_container is set")
+            o.save()
+        else:
+            super(SyncONOSService, self).sync_record(o)
+
     def sync_fields(self, o, fields):
         # the super causes the playbook to be run
         super(SyncONOSService, self).sync_fields(o, fields)
diff --git a/xos/synchronizers/openstack/event_loop.py b/xos/synchronizers/openstack/event_loop.py
index 6cfc9f6..db78f07 100644
--- a/xos/synchronizers/openstack/event_loop.py
+++ b/xos/synchronizers/openstack/event_loop.py
@@ -23,8 +23,8 @@
 #from timeout import timeout
 from xos.config import Config, XOS_DIR
 from synchronizers.base.steps import *
-from syncstep import SyncStep
-from toposort import toposort
+from synchronizers.base.syncstep import SyncStep
+from synchronizers.base.toposort import toposort
 from synchronizers.base.error_mapper import *
 from synchronizers.openstack.openstacksyncstep import OpenStackSyncStep
 from synchronizers.base.steps.sync_object import SyncObject
@@ -421,7 +421,7 @@
 				except Exception,e:
                         		self.consolePrint(bcolors.FAIL + "Model step %r failed" % (sync_step.__name__) + bcolors.ENDC)
 					logger.error('Model step %r failed. This seems like a misconfiguration or bug: %r. This error will not be relayed to the user!' % (sync_step.__name__, e))
-					logger.log_exc(e)
+					logger.log_exc("Exception in sync step")
 					self.failed_steps.append(S)
 					my_status = STEP_STATUS_KO
 			else:
diff --git a/xos/synchronizers/openstack/model_policies/model_policy_Controller.py b/xos/synchronizers/openstack/model_policies/model_policy_Controller.py
index 2db7a63..c62b612 100644
--- a/xos/synchronizers/openstack/model_policies/model_policy_Controller.py
+++ b/xos/synchronizers/openstack/model_policies/model_policy_Controller.py
@@ -46,6 +46,8 @@
         if network not in ctrls_by_network or \
             controller not in ctrls_by_network[network]:
             controller_network = ControllerNetwork(controller=controller, network=network)
+            if network.subnet and network.subnet.strip():
+                controller_network.subnet = network.subnet.strip()
             controller_network.save()
     # relations for all images
     ctrls_by_image = defaultdict(list)
diff --git a/xos/synchronizers/openstack/model_policies/model_policy_Network.py b/xos/synchronizers/openstack/model_policies/model_policy_Network.py
index 38d0377..9f9e5fd 100644
--- a/xos/synchronizers/openstack/model_policies/model_policy_Network.py
+++ b/xos/synchronizers/openstack/model_policies/model_policy_Network.py
@@ -22,4 +22,9 @@
 		if network not in network_deploy_lookup or \
 		  expected_controller not in network_deploy_lookup[network]:
 			nd = ControllerNetwork(network=network, controller=expected_controller, lazy_blocked=True)
+                        if network.subnet:
+                            # XXX: Possibly unpredictable behavior if there is
+                            # more than one ControllerNetwork and the subnet
+                            # is specified.
+                            nd.subnet = network.subnet
 			nd.save()
diff --git a/xos/synchronizers/openstack/openstacksyncstep.py b/xos/synchronizers/openstack/openstacksyncstep.py
index cc568f8..46056cf 100644
--- a/xos/synchronizers/openstack/openstacksyncstep.py
+++ b/xos/synchronizers/openstack/openstacksyncstep.py
@@ -1,6 +1,6 @@
 import os
 import base64
-from syncstep import SyncStep
+from synchronizers.base.syncstep import SyncStep
 
 class OpenStackSyncStep(SyncStep):
     """ XOS Sync step for copying data to OpenStack 
diff --git a/xos/synchronizers/openstack/steps/sync_container.yaml b/xos/synchronizers/openstack/steps/sync_container.yaml
index 82588dc..4ae4eb2 100644
--- a/xos/synchronizers/openstack/steps/sync_container.yaml
+++ b/xos/synchronizers/openstack/steps/sync_container.yaml
@@ -52,10 +52,18 @@
       state=latest
       update_cache=yes
     with_items:
-    - docker-engine
+# XXX docker 1.10 is not working on cloudlab
+#    - docker-engine
     - python-pip
     - python-httplib2
 
+  - name: Install Docker 1.9.1
+    apt:
+      name={{ '{{' }} item {{ '}}' }}
+      update_cache=yes
+    with_items:
+    - docker-engine=1.9.1-0~trusty
+
   # Something is installing a requests library that is incompative with pip, and
   # will cause this recipe to fail next time it tries to run pip. Only the one
   # in /usr/local/lib is bad. There's still a good one in /usr/lib
diff --git a/xos/synchronizers/openstack/steps/sync_controller_networks.py b/xos/synchronizers/openstack/steps/sync_controller_networks.py
index 0b876fa..f8b2292 100644
--- a/xos/synchronizers/openstack/steps/sync_controller_networks.py
+++ b/xos/synchronizers/openstack/steps/sync_controller_networks.py
@@ -34,22 +34,21 @@
         cidr = '%d.%d.%d.%d/24'%(a,b,c,d)
         return cidr
 
-    def alloc_gateway(self, uuid):
-        # 16 bits only
-        uuid_masked = uuid & 0xffff
-        a = 10
-        b = uuid_masked >> 8
-        c = uuid_masked & 0xff
-        d = 1
-
-        gateway = '%d.%d.%d.%d'%(a,b,c,d)
-        return gateway
-
+    def alloc_gateway(self, subnet):
+        parts = subnet.split(".")
+        if len(parts)!=4:
+            raise Exception("Invalid subnet %s" % subnet)
+        return ".".join(parts[:3]) + ".1"
 
     def save_controller_network(self, controller_network):
         network_name = controller_network.network.name
         subnet_name = '%s-%d'%(network_name,controller_network.pk)
-        cidr = self.alloc_subnet(controller_network.pk)
+        if controller_network.subnet and controller_network.subnet.strip():
+            # If a subnet is already specified (pass in by the creator), then
+            # use that rather than auto-generating one.
+            cidr = controller_network.subnet.strip()
+        else:
+            cidr = self.alloc_subnet(controller_network.pk)
         self.cidr=cidr
         slice = controller_network.network.owner
 
@@ -63,9 +62,9 @@
                     'subnet_name':subnet_name,
                     'ansible_tag':'%s-%s@%s'%(network_name,slice.slicename,controller_network.controller.name),
                     'cidr':cidr,
-                    'gateway':self.alloc_gateway(controller_network.pk),
+                    'gateway':self.alloc_gateway(cidr),
                     'use_vtn':getattr(Config(), "networking_use_vtn", False),
-                    'delete':False	
+                    'delete':False
                     }
         return network_fields
 
diff --git a/xos/synchronizers/openstack/steps/sync_instances.py b/xos/synchronizers/openstack/steps/sync_instances.py
index 22aa45c..884bcf5 100644
--- a/xos/synchronizers/openstack/steps/sync_instances.py
+++ b/xos/synchronizers/openstack/steps/sync_instances.py
@@ -34,8 +34,7 @@
             userdata += '  - %s\n' % key
         return userdata
 
-    def sort_controller_networks(self, nets):
-        nets = list(nets)
+    def sort_nics(self, nics):
         result = []
 
         # Enforce VTN's network order requirement. The access network must be
@@ -43,23 +42,27 @@
         # into the second slot.
 
         # move the private and/or access network to the first spot
-        for net in nets[:]:
-            tem = net.network.template
-            if (tem.visibility == "private") and (tem.translation=="none") and ("management" not in tem.name):
-                result.append(net)
-                nets.remove(net)
+        for nic in nics[:]:
+            network=nic.get("network", None)
+            if network:
+                tem = network.template
+                if (tem.visibility == "private") and (tem.translation=="none") and ("management" not in tem.name):
+                    result.append(nic)
+                    nics.remove(nic)
 
         # move the management network to the second spot
-        for net in nets[:]:
-            tem = net.network.template
-            if (tem.visibility == "private") and (tem.translation=="none") and ("management" in tem.name):
-                if len(result)!=1:
-                    raise Exception("Management network needs to be inserted in slot 1, but there are %d private nets" % len(result))
-                result.append(net)
-                nets.remove(net)
+        for net in nics[:]:
+            network=nic.get("network", None)
+            if network:
+                tem = network.template
+                if (tem.visibility == "private") and (tem.translation=="none") and ("management" in tem.name):
+                    if len(result)!=1:
+                        raise Exception("Management network needs to be inserted in slot 1, but there are %d private nics" % len(result))
+                    result.append(nic)
+                    nics.remove(nic)
 
         # add everything else. For VTN there probably shouldn't be any more.
-        result.extend(nets)
+        result.extend(nics)
 
         return result
 
@@ -84,19 +87,30 @@
         if instance.slice.service and instance.slice.service.public_key:
             pubkeys.add(instance.slice.service.public_key)
 
-        nics = []
-        networks = [ns.network for ns in NetworkSlice.objects.filter(slice=instance.slice)]
+        nics=[]
+
+        # handle ports the were created by the user
+        port_ids=[]
+        for port in Port.objects.filter(instance=instance):
+            if not port.port_id:
+                raise DeferredException("Instance %s waiting on port %s" % (instance, port))
+            nics.append({"kind": "port", "value": port.port_id, "network": port.network})
+
+        # we want to exclude from 'nics' any network that already has a Port
+        existing_port_networks = [port.network for network in Port.objects.filter(instance=instance)]
+
+        networks = [ns.network for ns in NetworkSlice.objects.filter(slice=instance.slice) if ns.network not in existing_port_networks]
         controller_networks = ControllerNetwork.objects.filter(network__in=networks,
                                                                 controller=instance.node.site_deployment.controller)
 
-        controller_networks = self.sort_controller_networks(controller_networks)
+        #controller_networks = self.sort_controller_networks(controller_networks)
         for controller_network in controller_networks:
             # Lenient exception - causes slow backoff
             if controller_network.network.template.visibility == 'private' and \
                controller_network.network.template.translation == 'none':
                    if not controller_network.net_id:
                         raise DeferredException("Instance %s Private Network %s has no id; Try again later" % (instance, controller_network.network.name))
-                   nics.append(controller_network.net_id)
+                   nics.append({"kind": "net", "value": controller_network.net_id, "network": controller_network.network})
 
         # now include network template
         network_templates = [network.template.shared_network_name for network in networks \
@@ -107,12 +121,14 @@
         nets = driver.shell.quantum.list_networks()['networks']
         for net in nets:
             if net['name'] in network_templates:
-                nics.append(net['id'])
+                nics.append({"kind": "net", "value": net['id'], "network": None})
 
         if (not nics):
             for net in nets:
                 if net['name']=='public':
-                    nics.append(net['id'])
+                    nics.append({"kind": "net", "value": net['id'], "network": None})
+
+        nics = self.sort_nics(nics)
 
         image_name = None
         controller_images = instance.image.controllerimages.filter(controller=instance.node.site_deployment.controller)
diff --git a/xos/synchronizers/openstack/steps/sync_instances.yaml b/xos/synchronizers/openstack/steps/sync_instances.yaml
index a61e5cf..3e7182a 100644
--- a/xos/synchronizers/openstack/steps/sync_instances.yaml
+++ b/xos/synchronizers/openstack/steps/sync_instances.yaml
@@ -19,11 +19,8 @@
       user_data: "{{ user_data }}"
       config_drive: yes
       nics:
-      {% for net in nics %}
-          - net-id: {{ net }}
-      {% endfor %}
-      {% for port in ports %}
-          - port-id: {{ port }}
+      {% for nic in nics %}
+          - {{ nic.kind }}-id: {{ nic.value }}
       {% endfor %}
 
       {% if meta %}
diff --git a/xos/synchronizers/openstack/steps/sync_ports.py b/xos/synchronizers/openstack/steps/sync_ports.py
index 21376e5..4f6ce14 100644
--- a/xos/synchronizers/openstack/steps/sync_ports.py
+++ b/xos/synchronizers/openstack/steps/sync_ports.py
@@ -16,8 +16,35 @@
     #     has, and then work backward from each port's network-id to determine
     #     which Network is associated from the port.
 
-    def call(self, **args):
-        logger.info("sync'ing network instances")
+    def call(self, failed=[], deletion=False):
+        if deletion:
+            self.delete_ports()
+        else:
+            self.sync_ports()
+
+    def get_driver(self, port):
+        # We need to use a client driver that specifies the tenant
+        # of the destination instance. Nova-compute will not connect
+        # ports to instances if the port's tenant does not match
+        # the instance's tenant.
+
+        # A bunch of stuff to compensate for OpenStackDriver.client_driveR()
+        # not being in working condition.
+        from openstack.client import OpenStackClient
+        from openstack.driver import OpenStackDriver
+        controller = port.instance.node.site_deployment.controller
+        slice = port.instance.slice
+        caller = port.network.owner.creator
+        auth = {'username': caller.email,
+                'password': caller.remote_password,
+                'tenant': slice.name}
+        client = OpenStackClient(controller=controller, **auth) # cacert=self.config.nova_ca_ssl_cert,
+        driver = OpenStackDriver(client=client)
+
+        return driver
+
+    def sync_ports(self):
+        logger.info("sync'ing Ports [delete=False]")
 
         ports = Port.objects.all()
         ports_by_id = {}
@@ -164,33 +191,40 @@
                     logger.info("deferring port %s because controllerNetwork does not have a port-id yet" % port)
                     continue
                 try:
-                    # We need to use a client driver that specifies the tenant
-                    # of the destination instance. Nova-compute will not connect
-                    # ports to instances if the port's tenant does not match
-                    # the instance's tenant.
+                    driver = self.get_driver(port)
 
-                    # A bunch of stuff to compensate for OpenStackDriver.client_driveR()
-                    # not being in working condition.
-                    from openstack.client import OpenStackClient
-                    from openstack.driver import OpenStackDriver
-                    caller = port.network.owner.creator
-                    auth = {'username': caller.email,
-                            'password': caller.remote_password,
-                            'tenant': slice.name}
-                    client = OpenStackClient(controller=controller, **auth) # cacert=self.config.nova_ca_ssl_cert,
-                    driver = OpenStackDriver(client=client)
+                    args = {"network_id": cn.net_id}
+                    neutron_port_name = port.get_parameters().get("neutron_port_name", None)
+                    if neutron_port_name:
+                        args["name"] = neutron_port_name
 
-                    neutron_port = driver.shell.quantum.create_port({"port": {"network_id": cn.net_id}})["port"]
+                    neutron_port = driver.shell.quantum.create_port({"port": args})["port"]
                     port.port_id = neutron_port["id"]
                     if neutron_port["fixed_ips"]:
                         port.ip = neutron_port["fixed_ips"][0]["ip_address"]
                     port.mac = neutron_port["mac_address"]
+                    port.xos_created = True
+                    logger.info("created neutron port %s for %s" % (port.port_id, port))
                 except:
                     logger.log_exc("failed to create neutron port for %s" % port)
                     continue
                 port.save()
 
-    def delete_record(self, network_instance):
-        # Nothing to do, this is an OpenCloud object
-        pass
+    def delete_ports(self):
+        logger.info("sync'ing Ports [delete=True]")
+        for port in Port.deleted_objects.all():
+            self.delete_record(port)
+
+    def delete_record(self, port):
+        if port.xos_created and port.port_id:
+            logger.info("calling openstack to destroy port %s" % port.port_id)
+            try:
+                driver = self.get_driver(port)
+                driver.shell.quantum.delete_port(port.port_id)
+            except:
+                logger.log_exc("failed to delete port %s from neutron" % port.port_id)
+                return
+
+        logger.info("Purging port %s" % port)
+        port.delete(purge=True)
 
diff --git a/xos/synchronizers/openstack/syncstep.py b/xos/synchronizers/openstack/syncstep.py
index bdab8f3..d1639b4 100644
--- a/xos/synchronizers/openstack/syncstep.py
+++ b/xos/synchronizers/openstack/syncstep.py
@@ -142,10 +142,10 @@
     def sync_record(self, o):
         try:
             controller = o.get_controller()
-            controller_register = json.loads(o.node.site_deployment.controller.backend_register)
+            controller_register = json.loads(controller.backend_register)
 
             if (controller_register.get('disabled',False)):
-                raise InnocuousException('Controller %s is disabled'%sliver.node.site_deployment.controller.name)
+                raise InnocuousException('Controller %s is disabled'%controller.name)
         except AttributeError:
             pass
 
diff --git a/xos/synchronizers/vbng/steps/sync_vbngtenant.py b/xos/synchronizers/vbng/steps/sync_vbngtenant.py
index 94875f4..4fa351e 100644
--- a/xos/synchronizers/vbng/steps/sync_vbngtenant.py
+++ b/xos/synchronizers/vbng/steps/sync_vbngtenant.py
@@ -8,7 +8,7 @@
 from synchronizers.base.syncstep import SyncStep
 from synchronizers.base.ansible import run_template_ssh
 from core.models import Service
-from services.cord.models import VCPEService, VCPETenant, VBNGTenant, VBNGService
+from services.cord.models import VSGService, VSGTenant, VBNGTenant, VBNGService
 from services.hpc.models import HpcService, CDNPrefix
 from xos.logger import Logger, logging
 
@@ -21,8 +21,8 @@
 logger = Logger(level=logging.INFO)
 
 class SyncVBNGTenant(SyncStep):
-    provides=[VCPETenant]
-    observes=VCPETenant
+    provides=[VSGTenant]
+    observes=VSGTenant
     requested_interval=0
 
     def __init__(self, **args):
@@ -84,7 +84,7 @@
         raise Exception("vBNG service does not have vbng_url set, and is not linked to an ONOSApp")
 
     def get_private_interface(self, o):
-        vcpes = VCPETenant.get_tenant_objects().all()
+        vcpes = VSGTenant.get_tenant_objects().all()
         vcpes = [x for x in vcpes if (x.vbng is not None) and (x.vbng.id == o.id)]
         if not vcpes:
             raise Exception("No vCPE tenant is associated with vBNG %s" % str(o.id))
diff --git a/xos/synchronizers/vcpe/run-vtn.sh b/xos/synchronizers/vcpe/run-vtn.sh
new file mode 100755
index 0000000..c4c3b00
--- /dev/null
+++ b/xos/synchronizers/vcpe/run-vtn.sh
@@ -0,0 +1,8 @@
+#if [[ ! -e ./vcpe-observer.py ]]; then
+#    ln -s ../../xos-observer.py vcpe-observer.py
+#fi
+
+export XOS_DIR=/opt/xos
+cp /root/setup/node_key $XOS_DIR/synchronizers/vcpe/node_key
+chmod 0600 $XOS_DIR/synchronizers/vcpe/node_key
+python vcpe-synchronizer.py  -C $XOS_DIR/synchronizers/vcpe/vtn_vcpe_synchronizer_config
diff --git a/xos/synchronizers/vcpe/steps/sync_vcpetenant.py b/xos/synchronizers/vcpe/steps/sync_vcpetenant.py
index f0e9301..5e48837 100644
--- a/xos/synchronizers/vcpe/steps/sync_vcpetenant.py
+++ b/xos/synchronizers/vcpe/steps/sync_vcpetenant.py
@@ -9,8 +9,8 @@
 from synchronizers.base.syncstep import SyncStep
 from synchronizers.base.ansible import run_template_ssh
 from synchronizers.base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible
-from core.models import Service, Slice
-from services.cord.models import VCPEService, VCPETenant, VOLTTenant
+from core.models import Service, Slice, Tag
+from services.cord.models import VSGService, VSGTenant, VOLTTenant
 from services.hpc.models import HpcService, CDNPrefix
 from xos.logger import Logger, logging
 
@@ -25,21 +25,23 @@
 PARENTAL_MECHANISM="dnsmasq"
 ENABLE_QUICK_UPDATE=False
 
-class SyncVCPETenant(SyncInstanceUsingAnsible):
-    provides=[VCPETenant]
-    observes=VCPETenant
+CORD_USE_VTN = getattr(Config(), "networking_use_vtn", False)
+
+class SyncVSGTenant(SyncInstanceUsingAnsible):
+    provides=[VSGTenant]
+    observes=VSGTenant
     requested_interval=0
     template_name = "sync_vcpetenant.yaml"
     service_key_name = "/opt/xos/synchronizers/vcpe/vcpe_private_key"
 
     def __init__(self, *args, **kwargs):
-        super(SyncVCPETenant, self).__init__(*args, **kwargs)
+        super(SyncVSGTenant, self).__init__(*args, **kwargs)
 
     def fetch_pending(self, deleted):
         if (not deleted):
-            objs = VCPETenant.get_tenant_objects().filter(Q(enacted__lt=F('updated')) | Q(enacted=None),Q(lazy_blocked=False))
+            objs = VSGTenant.get_tenant_objects().filter(Q(enacted__lt=F('updated')) | Q(enacted=None),Q(lazy_blocked=False))
         else:
-            objs = VCPETenant.get_deleted_tenant_objects()
+            objs = VSGTenant.get_deleted_tenant_objects()
 
         return objs
 
@@ -47,7 +49,7 @@
         if not o.provider_service:
             return None
 
-        vcpes = VCPEService.get_service_objects().filter(id=o.provider_service.id)
+        vcpes = VSGService.get_service_objects().filter(id=o.provider_service.id)
         if not vcpes:
             return None
 
@@ -137,6 +139,19 @@
                     if mac:
                         safe_macs.append(mac)
 
+        wan_vm_ip=""
+        wan_vm_mac=""
+        tags = Tag.select_by_content_object(o.instance).filter(name="vm_wan_addr")
+        if tags:
+            parts=tags[0].value.split(",")
+            if len(parts)!=3:
+                raise Exception("vm_wan_addr tag is malformed: %s" % value)
+            wan_vm_ip = parts[1]
+            wan_vm_mac = parts[2]
+        else:
+            if CORD_USE_VTN:
+                raise Exception("no vm_wan_addr tag for instance %s" % o.instance)
+
         fields = {"vlan_ids": vlan_ids,   # XXX remove this
                 "s_tags": s_tags,
                 "c_tags": c_tags,
@@ -145,7 +160,13 @@
                 "bbs_addrs": bbs_addrs,
                 "full_setup": full_setup,
                 "isolation": o.instance.isolation,
-                "safe_browsing_macs": safe_macs}
+                "wan_container_gateway_mac": vcpe_service.wan_container_gateway_mac,
+                "wan_container_gateway_ip": vcpe_service.wan_container_gateway_ip,
+                "wan_container_netbits": vcpe_service.wan_container_netbits,
+                "wan_vm_mac": wan_vm_mac,
+                "wan_vm_ip": wan_vm_ip,
+                "safe_browsing_macs": safe_macs,
+                "dns_servers": [x.strip() for x in vcpe_service.dns_servers.split(",")] }
 
         # add in the sync_attributes that come from the SubscriberRoot object
 
@@ -158,7 +179,7 @@
     def sync_fields(self, o, fields):
         # the super causes the playbook to be run
 
-        super(SyncVCPETenant, self).sync_fields(o, fields)
+        super(SyncVSGTenant, self).sync_fields(o, fields)
 
         # now do all of our broadbandshield stuff...
 
@@ -225,9 +246,12 @@
             logger.info("quick_update triggered; skipping ansible recipe")
         else:
             if o.instance.isolation in ["container", "container_vm"]:
-                super(SyncVCPETenant, self).run_playbook(o, fields, "sync_vcpetenant_new.yaml")
+                super(SyncVSGTenant, self).run_playbook(o, fields, "sync_vcpetenant_new.yaml")
             else:
-                super(SyncVCPETenant, self).run_playbook(o, fields)
+                if CORD_USE_VTN:
+                    super(SyncVSGTenant, self).run_playbook(o, fields, template_name="sync_vcpetenant_vtn.yaml")
+                else:
+                    super(SyncVSGTenant, self).run_playbook(o, fields)
 
         o.last_ansible_hash = ansible_hash
 
diff --git a/xos/synchronizers/vcpe/steps/sync_vcpetenant.yaml b/xos/synchronizers/vcpe/steps/sync_vcpetenant.yaml
index d887547..585f68a 100644
--- a/xos/synchronizers/vcpe/steps/sync_vcpetenant.yaml
+++ b/xos/synchronizers/vcpe/steps/sync_vcpetenant.yaml
@@ -33,6 +33,10 @@
         {% for bbs_addr in bbs_addrs %}
         - {{ bbs_addr }}
         {% endfor %}
+      dns_servers:
+        {% for dns_server in dns_servers %}
+        - {{ dns_server }}
+        {% endfor %}
       nat_ip: {{ nat_ip }}
       nat_mac: {{ nat_mac }}
       lan_ip: {{ lan_ip }}
diff --git a/xos/synchronizers/vcpe/steps/sync_vcpetenant_new.yaml b/xos/synchronizers/vcpe/steps/sync_vcpetenant_new.yaml
index 59047c1..071c30a 100644
--- a/xos/synchronizers/vcpe/steps/sync_vcpetenant_new.yaml
+++ b/xos/synchronizers/vcpe/steps/sync_vcpetenant_new.yaml
@@ -34,6 +34,10 @@
         {% for bbs_addr in bbs_addrs %}
         - {{ bbs_addr }}
         {% endfor %}
+      dns_servers:
+        {% for dns_server in dns_servers %}
+        - {{ dns_server }}
+        {% endfor %}
       nat_ip: {{ nat_ip }}
       nat_mac: {{ nat_mac }}
       lan_ip: {{ lan_ip }}
diff --git a/xos/synchronizers/vcpe/steps/sync_vcpetenant_vtn.yaml b/xos/synchronizers/vcpe/steps/sync_vcpetenant_vtn.yaml
new file mode 100644
index 0000000..819dcc5
--- /dev/null
+++ b/xos/synchronizers/vcpe/steps/sync_vcpetenant_vtn.yaml
@@ -0,0 +1,217 @@
+---
+- hosts: {{ instance_name }}
+  gather_facts: False
+  connection: ssh
+  user: ubuntu
+  sudo: yes
+  vars:
+      cdn_enable: {{ cdn_enable }}
+      dnsdemux_ip: {{ dnsdemux_ip }}
+      firewall_enable: {{ firewall_enable }}
+      url_filter_enable: {{ url_filter_enable }}
+      vlan_ids:
+        {% for vlan_id in vlan_ids %}
+        - {{ vlan_id }}
+        {% endfor %}
+      c_tags:
+        {% for c_tag in c_tags %}
+        - {{ c_tag }}
+        {% endfor %}
+      s_tags:
+        {% for s_tag in s_tags %}
+        - {{ s_tag }}
+        {% endfor %}
+      firewall_rules:
+        {% for firewall_rule in firewall_rules.split("\n") %}
+        - {{ firewall_rule }}
+        {% endfor %}
+      cdn_prefixes:
+        {% for prefix in cdn_prefixes %}
+        - {{ prefix }}
+        {% endfor %}
+      bbs_addrs:
+        {% for bbs_addr in bbs_addrs %}
+        - {{ bbs_addr }}
+        {% endfor %}
+      dns_servers:
+        {% for dns_server in dns_servers %}
+        - {{ dns_server }}
+        {% endfor %}
+      nat_ip: {{ nat_ip }}
+      nat_mac: {{ nat_mac }}
+      lan_ip: {{ lan_ip }}
+      lan_mac: {{ lan_mac }}
+      wan_ip: {{ wan_ip }}
+      wan_mac: {{ wan_mac }}
+      wan_container_ip: {{ wan_container_ip }}
+      wan_container_netbits: {{ wan_container_netbits }}
+      wan_container_mac: {{ wan_container_mac }}
+      wan_container_gateway_ip: {{ wan_container_gateway_ip }}
+      wan_vm_ip: {{ wan_vm_ip }}
+      wan_vm_mac: {{ wan_vm_mac }}
+      wan_next_hop: 10.0.1.253   # FIX ME
+      private_ip: {{ private_ip }}
+      private_mac: {{ private_mac }}
+      hpc_client_ip: {{ hpc_client_ip }}
+      hpc_client_mac: {{ hpc_client_mac }}
+      keystone_tenant_id: {{ keystone_tenant_id }}
+      keystone_user_id: {{ keystone_user_id }}
+      rabbit_user: {{ rabbit_user }}
+      rabbit_password: {{ rabbit_password }}
+      rabbit_host: {{ rabbit_host }}
+      safe_browsing:
+        {% for mac in safe_browsing_macs %}
+        - {{ mac }}
+        {% endfor %}
+
+  tasks:
+  - name: Check to see if network is setup
+    stat: path=/root/network_is_setup
+    register: network_is_setup
+
+  - name: Add eth0.500
+    shell: "{{ '{{' }} item {{ '}}' }}"
+    with_items:
+      - ip link del link eth0 eth0.500 || true
+      - brctl delbr br-wan || true
+      - ip link add link eth0 eth0.500 type vlan id 500
+      - ifconfig eth0.500 up
+      - ifconfig eth0.500 0.0.0.0
+      - ifconfig eth0.500 hw ether {{ wan_vm_mac }}
+      - ip addr add {{ wan_vm_ip }}/{{ wan_container_netbits }} dev eth0.500
+      - ip link set eth0.500 up
+      - ip route del default || true
+      - ip route add default via {{ wan_container_gateway_ip }}
+    when: network_is_setup.stat.exists == False
+
+  - name: install bridge-utils
+    apt: name=bridge-utils state=present
+
+  - name: now redo everything using a bridge
+    shell: "{{ '{{' }} item {{ '}}' }}"
+    with_items:
+       - ip link del link eth0 eth0.500
+       - ip link add link eth0 eth0.500 type vlan id 500
+       - ip link set eth0.500 up
+       - brctl delbr br-wan || true
+       - brctl addbr br-wan
+       - brctl addif br-wan eth0.500
+       - ifconfig br-wan hw ether {{ wan_vm_mac }}
+       - ip addr add {{ wan_vm_ip }}/{{ wan_container_netbits }} dev br-wan
+       - ip link set br-wan up
+       - ip route del default || true
+       - ip route add default via {{ wan_container_gateway_ip }}
+       - ip link set dev br-wan promisc on
+    when: network_is_setup.stat.exists == False
+
+  - name: Remember that the network is setup, so we never do the above again
+    shell: touch /root/network_is_setup
+
+{% if full_setup %}
+  - name: Docker repository
+    copy: src=/opt/xos/synchronizers/vcpe/files/docker.list
+      dest=/etc/apt/sources.list.d/docker.list
+
+  - name: Import the repository key
+    apt_key: keyserver=keyserver.ubuntu.com id=36A1D7869245C8950F966E92D8576A8BA88D21E9
+
+  - name: install Docker
+    apt: name=lxc-docker state=present update_cache=yes
+
+  - name: install python-setuptools
+    apt: name=python-setuptools state=present
+
+  - name: install pip
+    easy_install: name=pip
+
+  - name: install docker-py
+    pip: name=docker-py version=0.5.3
+
+  - name: install Pipework
+    get_url: url=https://raw.githubusercontent.com/jpetazzo/pipework/master/pipework
+       dest=/usr/local/bin/pipework
+       mode=0755
+
+  - name: make sure /etc/dnsmasq.d exists
+    file: path=/etc/dnsmasq.d state=directory owner=root group=root
+
+  - name: Disable resolvconf service
+    shell: service resolvconf stop
+    shell: echo manual > /etc/init/resolvconf.override
+    shell: rm -f /etc/resolv.conf
+
+  - name: Install resolv.conf
+    copy: src=/opt/xos/synchronizers/vcpe/files/vm-resolv.conf
+      dest=/etc/resolv.conf
+
+  - name: Verify if vcpe_stats_notifier ([] is to avoid capturing the shell process) cron job is already running
+    shell: pgrep -f [v]cpe_stats_notifier | wc -l
+    register: cron_job_pids_count
+
+#  - name: DEBUG
+#    debug: var=cron_job_pids_count.stdout
+
+#  - name: make sure ~/bin exists
+#    file: path=~/bin state=directory owner=root group=root
+#    when: cron_job_pids_count.stdout == "0"
+
+#  - name: Copy cron job to destination
+#    copy: src=/opt/xos/synchronizers/vcpe/vcpe_stats_notifier.py
+#      dest=/usr/local/sbin/vcpe_stats_notifier.py
+#    when: cron_job_pids_count.stdout == "0"
+
+#  - name: install python-kombu
+#    apt: name=python-kombu state=present
+#    when: cron_job_pids_count.stdout == "0"
+
+#  - name: Initiate vcpe_stats_notifier cron job
+#    command: sudo python /usr/local/sbin/vcpe_stats_notifier.py --keystone_tenant_id={{ keystone_tenant_id }} --keystone_user_id={{ keystone_user_id }} --rabbit_user={{ rabbit_user }} --rabbit_password={{ rabbit_password }} --rabbit_host={{ rabbit_host }} --vcpeservice_rabbit_exchange='vcpeservice'
+#    async: 9999999999999999
+#    poll: 0
+#    when: cron_job_pids_count.stdout == "0"
+{% endif %}
+
+  - name: vCPE upstart
+    template: src=/opt/xos/synchronizers/vcpe/templates/vcpe.conf.j2 dest=/etc/init/vcpe-{{ s_tags[0] }}-{{ c_tags[0] }}.conf
+
+  - name: vCPE startup script
+    template: src=/opt/xos/synchronizers/vcpe/templates/start-vcpe-vtn.sh.j2 dest=/usr/local/sbin/start-vcpe-{{ s_tags[0] }}-{{ c_tags[0] }}.sh mode=0755
+    notify:
+#    - restart vcpe
+     - stop vcpe
+     - remove container
+     - start vcpe
+
+  - name: create /etc/vcpe-{{ s_tags[0] }}-{{ c_tags[0] }}/dnsmasq.d
+    file: path=/etc/vcpe-{{ s_tags[0] }}-{{ c_tags[0] }}/dnsmasq.d state=directory owner=root group=root
+
+  - name: vCPE basic dnsmasq config
+    copy: src=/opt/xos/synchronizers/vcpe/files/vcpe.dnsmasq dest=/etc/vcpe-{{ s_tags[0] }}-{{ c_tags[0] }}/dnsmasq.d/vcpe.conf owner=root group=root
+    notify:
+    - restart dnsmasq
+
+  - name: dnsmasq config
+    template: src=/opt/xos/synchronizers/vcpe/templates/dnsmasq_servers.j2 dest=/etc/vcpe-{{ s_tags[0] }}-{{ c_tags[0] }}/dnsmasq.d/servers.conf owner=root group=root
+    notify:
+    - restart dnsmasq
+
+  - name: Make sure vCPE service is running
+    service: name=vcpe-{{ s_tags[0] }}-{{ c_tags[0] }} state=started
+
+  handlers:
+  # Dnsmasq is automatically restarted in the container
+  - name: restart dnsmasq
+    shell: docker exec vcpe-{{ s_tags[0] }}-{{ c_tags[0] }} killall dnsmasq
+
+  - name: restart vcpe
+    shell: service vcpe-{{ s_tags[0] }}-{{ c_tags[0] }} stop; sleep 1; service vcpe-{{ s_tags[0] }}-{{ c_tags[0] }} start
+
+  - name: stop vcpe
+    service: name=vcpe-{{ s_tags[0] }}-{{ c_tags[0] }} state=stopped
+
+  - name: remove container
+    docker: name=vcpe-{{ s_tags[0] }}-{{ c_tags[0] }} state=absent image=docker-vcpe
+
+  - name: start vcpe
+    service: name=vcpe-{{ s_tags[0] }}-{{ c_tags[0] }} state=started
+
diff --git a/xos/synchronizers/vcpe/templates/dnsmasq_servers.j2 b/xos/synchronizers/vcpe/templates/dnsmasq_servers.j2
index c89c762..3682cdf 100644
--- a/xos/synchronizers/vcpe/templates/dnsmasq_servers.j2
+++ b/xos/synchronizers/vcpe/templates/dnsmasq_servers.j2
@@ -10,5 +10,7 @@
 {% endif %}
 
 # use google's DNS service
-server=8.8.8.8
-server=8.8.4.4
+{% for dns_server in dns_servers %}
+server={{ dns_server }}
+{% endfor %}
+
diff --git a/xos/synchronizers/vcpe/templates/start-vcpe-vtn.sh.j2 b/xos/synchronizers/vcpe/templates/start-vcpe-vtn.sh.j2
new file mode 100644
index 0000000..bf46515
--- /dev/null
+++ b/xos/synchronizers/vcpe/templates/start-vcpe-vtn.sh.j2
@@ -0,0 +1,47 @@
+#!/bin/bash
+
+function mac_to_iface {
+    MAC=$1
+    ifconfig|grep $MAC| awk '{print $1}'|grep -v '\.'
+}
+
+iptables -L > /dev/null
+ip6tables -L > /dev/null
+
+STAG={{ s_tags[0] }}
+CTAG={{ c_tags[0] }}
+VCPE=vcpe-$STAG-$CTAG
+
+docker inspect $VCPE > /dev/null 2>&1
+if [ "$?" == 1 ]
+then
+    docker pull andybavier/docker-vcpe
+    docker run -d --name=$VCPE --privileged=true --net=none -v /etc/$VCPE/dnsmasq.d:/etc/dnsmasq.d andybavier/docker-vcpe
+else
+    docker start $VCPE
+fi
+
+# Set up networking via pipework
+WAN_IFACE=br-wan
+docker exec $VCPE ifconfig eth0 >> /dev/null || pipework $WAN_IFACE -i eth0 $VCPE {{ wan_container_ip }}/{{ wan_container_netbits }}@{{ wan_container_gateway_ip }} {{ wan_container_mac }}
+
+LAN_IFACE=eth0
+ifconfig $LAN_IFACE >> /dev/null
+if [ "$?" == 0 ]
+then
+    ifconfig $LAN_IFACE.$STAG >> /dev/null || ip link add link $LAN_IFACE name $LAN_IFACE.$STAG type vlan id $STAG
+    ifconfig $LAN_IFACE.$STAG up
+    docker exec $VCPE ifconfig eth1 >> /dev/null || pipework $LAN_IFACE.$STAG -i eth1 $VCPE 192.168.0.1/24 @$CTAG
+fi
+
+#HPC_IFACE=$( mac_to_iface {{ hpc_client_mac }} )
+#docker exec $VCPE ifconfig eth2 >> /dev/null || pipework $HPC_IFACE -i eth2 $VCPE {{ hpc_client_ip }}/24
+
+# Make sure VM's eth0 (hpc_client) has no IP address
+#ifconfig $HPC_IFACE 0.0.0.0
+
+# Now can start up dnsmasq
+docker exec $VCPE service dnsmasq start
+
+# Attach to container
+docker start -a $VCPE
diff --git a/xos/synchronizers/vcpe/vtn_vcpe_synchronizer_config b/xos/synchronizers/vcpe/vtn_vcpe_synchronizer_config
new file mode 100644
index 0000000..e92786b
--- /dev/null
+++ b/xos/synchronizers/vcpe/vtn_vcpe_synchronizer_config
@@ -0,0 +1,47 @@
+
+[plc]
+name=plc
+deployment=VICCI
+
+[db]
+name=xos
+user=postgres
+password=password
+host=localhost
+port=5432
+
+[api]
+host=128.112.171.237
+port=8000
+ssl_key=None
+ssl_cert=None
+ca_ssl_cert=None
+ratelimit_enabled=0
+omf_enabled=0
+mail_support_address=support@localhost
+nova_enabled=True
+
+[observer]
+name=vcpe
+dependency_graph=/opt/xos/synchronizers/vcpe/model-deps
+steps_dir=/opt/xos/synchronizers/vcpe/steps
+sys_dir=/opt/xos/synchronizers/vcpe/sys
+deleters_dir=/opt/xos/synchronizers/vcpe/deleters
+log_file=console
+#/var/log/hpc.log
+driver=None
+pretend=False
+backoff_disabled=True
+save_ansible_output=True
+# set proxy_ssh to false on cloudlab
+full_setup=True
+proxy_ssh=True
+proxy_ssh_key=/opt/xos/synchronizers/vcpe/node_key
+proxy_ssh_user=root
+
+[networking]
+use_vtn=True
+
+[feefie]
+client_id='vicci_dev_central'
+user_id='pl'
diff --git a/xos/synchronizers/vtn/steps/sync_port_addresses.py b/xos/synchronizers/vtn/steps/sync_port_addresses.py
new file mode 100644
index 0000000..6b48911
--- /dev/null
+++ b/xos/synchronizers/vtn/steps/sync_port_addresses.py
@@ -0,0 +1,137 @@
+import os
+import requests
+import socket
+import sys
+import base64
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.syncstep import SyncStep
+from core.models import Service, Port, Controller, Tag
+from core.models.service import COARSE_KIND
+from services.cord.models import VSGTenant
+from services.cord.models import Tenant
+from xos.logger import Logger, logging
+from requests.auth import HTTPBasicAuth
+
+# hpclibrary will be in steps/..
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+logger = Logger(level=logging.INFO)
+
+# XXX should save and load this
+glo_saved_vtn_maps = []
+
+class SyncPortAddresses(SyncStep):
+    requested_interval = 0 # 3600
+    provides=[Port]
+    observes=Port
+
+    def __init__(self, **args):
+        SyncStep.__init__(self, **args)
+
+    def call(self, **args):
+        global glo_saved_vtn_maps
+
+        logger.info("sync'ing vsg tenant to port addresses")
+
+        # build up a dictionary of port-->[wan_addrs] mappings
+        port_addrs = {}
+        for vsg in VSGTenant.get_tenant_objects().all():
+            if not vsg.instance:
+                logger.info("skipping vsg %s because it has no instance" % vsg)
+
+            wan_ip = vsg.wan_container_ip
+            if not wan_ip:
+                logger.info("skipping vsg %s because it has no wan_container_ip" % vsg)
+
+            wan_mac = vsg.wan_container_mac
+            if not wan_mac:
+                logger.info("skipping vsg %s because it has no wan_container_mac" % vsg)
+
+            lan_network = vsg.get_lan_network(vsg.instance)
+            if not lan_network:
+                logger.info("skipping vsg %s because it has no lan_network" % vsg)
+
+            lan_port = Port.objects.filter(instance = vsg.instance, network=lan_network)
+            if not lan_port:
+                logger.info("skipping vsg %s because it has no lan_port" % vsg)
+            lan_port = lan_port[0]
+
+            if not lan_port.port_id:
+                logger.info("skipping vsg %s because its lan_port has no port_id" % vsg)
+
+            if not (lan_port.pk in port_addrs):
+                port_addrs[lan_port.pk] = []
+            entry = {"mac_address": wan_mac, "ip_address": wan_ip}
+            addr_pairs = port_addrs[lan_port.pk]
+            if not entry in addr_pairs:
+                 addr_pairs.append(entry)
+
+            # now do the VM_WAN_IP from the instance
+            if vsg.instance:
+                tags=Tag.select_by_content_object(vsg.instance).filter(name="vm_wan_addr")
+                if tags:
+                    parts=tags[0].value.split(",")
+                    if len(parts)!=3:
+                        raise Exception("vm_wan_addr tag is malformed: %s" % value)
+                    entry = {"mac_address": parts[2], "ip_address": parts[1]}
+                    if not entry in addr_pairs:
+                        addr_pairs.append(entry)
+
+        # Get all ports in all controllers
+        ports_by_id = {}
+        for controller in Controller.objects.all():
+            if not controller.admin_tenant:
+                logger.info("controller %s has no admin_tenant" % controller)
+                continue
+            try:
+                driver = self.driver.admin_driver(controller = controller)
+                ports = driver.shell.quantum.list_ports()["ports"]
+            except:
+                logger.log_exc("failed to get ports from controller %s" % controller)
+                continue
+
+            for port in ports:
+                ports_by_id[port["id"]] = port
+
+        for port_pk in port_addrs.keys():
+            port = Port.objects.get(pk=port_pk)
+            addr_pairs = port_addrs[port_pk]
+            neutron_port = ports_by_id.get(port.port_id,None)
+            if not neutron_port:
+                logger.info("failed to get neutron port for port %s" % port)
+                continue
+
+            ips = [x["ip_address"] for x in addr_pairs]
+
+            changed = False
+
+            # delete addresses in neutron that don't exist in XOS
+            aaps = neutron_port.get("allowed_address_pairs", [])
+            for aap in aaps[:]:
+                if not aap["ip_address"] in ips:
+                    logger.info("removing address %s from port %s" % (aap["ip_address"], port))
+                    aaps.remove(aap)
+                    changed = True
+
+            aaps_ips = [x["ip_address"] for x in aaps]
+
+            # add addresses in XOS that don't exist in neutron
+            for addr in addr_pairs:
+                if not addr["ip_address"] in aaps_ips:
+                    logger.info("adding address %s to port %s" % (addr, port))
+                    aaps.append( addr )
+                    aaps_ips.append(addr["ip_address"])
+                    changed = True
+
+            if changed:
+                logger.info("updating port %s" % port)
+                driver.shell.quantum.update_port(port.port_id, {"port": {"allowed_address_pairs": aaps}})
+
+
+
+
+
+
+
diff --git a/xos/synchronizers/vtn/vtn_synchronizer_config b/xos/synchronizers/vtn/vtn_synchronizer_config
index 302a096..d931839 100644
--- a/xos/synchronizers/vtn/vtn_synchronizer_config
+++ b/xos/synchronizers/vtn/vtn_synchronizer_config
@@ -29,10 +29,16 @@
 deleters_dir=/opt/xos/synchronizers/vtn/deleters
 log_file=console
 #/var/log/hpc.log
-driver=None
+driver=openstack
 pretend=False
 backoff_disabled=True
 
+[nova]
+ca_ssl_cert=/etc/ssl/certs/ca-certificates.crt
+
 [feefie]
 client_id='vicci_dev_central'
 user_id='pl'
+
+[networking]
+use_vtn=True
diff --git a/xos/templates/admin/base.html b/xos/templates/admin/base.html
index 5a99e0e..8d8dcd1 100644
--- a/xos/templates/admin/base.html
+++ b/xos/templates/admin/base.html
@@ -23,6 +23,11 @@
   <script type="text/javascript" src="{% static 'uploadTextarea.js' %}"></script>
   <script type="text/javascript" src="{% static 'observer_status.js' %}"></script>
 
+  <script
+    src="//d2wy8f7a9ursnm.cloudfront.net/bugsnag-2.min.js"
+    data-apikey="748d877b8b4e211dcd3249c1aa46d263">
+  </script>
+
   <!-- ngXosLib -->
   <script src="{% static 'js/vendor/ngXosVendor.js' %}"></script>
   <script src="{% static 'js/vendor/ngXosHelpers.js' %}"></script>
diff --git a/xos/tests/README.md b/xos/tests/README.md
new file mode 100644
index 0000000..f3ddad5
--- /dev/null
+++ b/xos/tests/README.md
@@ -0,0 +1,5 @@
+# CORD Tests
+
+The files in this directory are obsolete. The plan is for this
+directory to hold tests in the furture. There are also tests in
+the form of TOSCA specifications in `../configurations/tests`.
diff --git a/xos/tools/apigen/modelgen b/xos/tools/apigen/modelgen
index 72cce08..414540d 100644
--- a/xos/tools/apigen/modelgen
+++ b/xos/tools/apigen/modelgen
@@ -17,6 +17,7 @@
 
 options = None
 
+
 def singular(foo, keys):
 	for k in keys:
 		if (foo==k+'es'):
@@ -28,8 +29,11 @@
 g = globals()
 
 def enum_classes(apps):
+    global app_map
+    app_map = {}
     model_classes = []
     for app in apps:
+            orig_app=app
             app = app + ".models"
             models_module = __import__(app)
             for part in app.split(".")[1:]:
@@ -37,12 +41,15 @@
                     break
                 models_module = getattr(models_module,part)
 
+            global PlCoreBase
             PlCoreBase = getattr(models_module,"PlCoreBase")
 
             for classname in dir(models_module):
                     c = getattr(models_module, classname, None)
                     if type(c)==type(PlCoreBase) and c.__name__ not in options.blacklist:
                             model_classes.append(c)
+                            app_map[c.__name__]=orig_app
+
 
     return model_classes
 
@@ -53,6 +60,8 @@
 	def __init__(self, m):
 		self.model = m
 		self.props = []
+		self.fields = []
+		self.field_dict = []
 		self.refs = []
 		self.plural_name = None
 
@@ -101,11 +110,19 @@
 		return filtered
 
 	def add_object(self, o):
+                global app_map
 		obj = GenObj(o)
 		fields = o._meta.fields
+                try:
+                    obj.app = app_map[o.__name__]
+                except KeyError:
+                    print "KeyError: %r"%o.__name__
+                    pdb.set_trace()
 		self[str(obj).lower()]=obj
 
 	def compute_links(self):
+                base_props = [f.name for f in PlCoreBase._meta.fields]
+
 		for obj in self.values():
 			#if (str(obj)=='network'):
 			#	pdb.set_trace()
@@ -132,7 +149,11 @@
                                         # cause swagger and REST to break
                                         pass
 				else:
-					obj.props.append(f.name)
+                                        f.type = f.__class__.__name__
+
+                                        if (f.name not in base_props):
+                                            obj.fields.append(f) 
+                                        obj.props.append(f.name)
 
 			m2m = obj.model._meta.many_to_many
 			for f in m2m:
diff --git a/xos/tosca/custom_types/cdn.m4 b/xos/tosca/custom_types/cdn.m4
index 59d4ee6..0d33715 100644
--- a/xos/tosca/custom_types/cdn.m4
+++ b/xos/tosca/custom_types/cdn.m4
@@ -33,6 +33,26 @@
             user:
                 type: tosca.capabilities.xos.CDNPrefix
 
+    tosca.nodes.HpcHealthCheck:
+        derived_from: tosca.nodes.Root
+
+        properties:
+            kind:
+                type: string
+                required: true
+                description: dns | http | nameserver
+            resource_name:
+                type: string
+                required: true
+                description: name of resource to query
+            result_contains:
+                type: string
+                required: false
+                description: soemthing to look for inside the result
+        capabilities:
+            healthcheck:
+                type: tosca.capabilities.xos.HpcHealthCheck
+
     tosca.relationships.MemberOfServiceProvider:
         derived_from: tosca.relationships.Root
         valid_target_types: [ tosca.capabilities.xos.ServiceProvider ]
@@ -57,4 +77,7 @@
     tosca.capabilities.xos.OriginServer:
         derived_from: tosca.capabilities.Root
 
+    tosca.capabilities.xos.HpcHealthCheck:
+        derived_from: tosca.capabilities.Root
+
 
diff --git a/xos/tosca/custom_types/cdn.yaml b/xos/tosca/custom_types/cdn.yaml
index 59d4ee6..0d33715 100644
--- a/xos/tosca/custom_types/cdn.yaml
+++ b/xos/tosca/custom_types/cdn.yaml
@@ -33,6 +33,26 @@
             user:
                 type: tosca.capabilities.xos.CDNPrefix
 
+    tosca.nodes.HpcHealthCheck:
+        derived_from: tosca.nodes.Root
+
+        properties:
+            kind:
+                type: string
+                required: true
+                description: dns | http | nameserver
+            resource_name:
+                type: string
+                required: true
+                description: name of resource to query
+            result_contains:
+                type: string
+                required: false
+                description: soemthing to look for inside the result
+        capabilities:
+            healthcheck:
+                type: tosca.capabilities.xos.HpcHealthCheck
+
     tosca.relationships.MemberOfServiceProvider:
         derived_from: tosca.relationships.Root
         valid_target_types: [ tosca.capabilities.xos.ServiceProvider ]
@@ -57,4 +77,7 @@
     tosca.capabilities.xos.OriginServer:
         derived_from: tosca.capabilities.Root
 
+    tosca.capabilities.xos.HpcHealthCheck:
+        derived_from: tosca.capabilities.Root
+
 
diff --git a/xos/tosca/custom_types/xos.m4 b/xos/tosca/custom_types/xos.m4
index 20a537a..15e9710 100644
--- a/xos/tosca/custom_types/xos.m4
+++ b/xos/tosca/custom_types/xos.m4
@@ -121,6 +121,18 @@
             rest_onos/v1/network/configuration/:
                 type: string
                 required: false
+            rest_hostname:
+                type: string
+                required: false
+            rest_port:
+                type: string
+                required: false
+            no_container:
+                type: boolean
+                default: false
+            node_key:
+                type: string
+                required: false
 
 
     tosca.nodes.ONOSApp:
@@ -193,9 +205,9 @@
                 type: string
                 required: false
 
-    tosca.nodes.VCPEService:
+    tosca.nodes.VSGService:
         description: >
-            CORD: The vCPE Service.
+            CORD: The vSG Service.
         derived_from: tosca.nodes.Root
         capabilities:
             xos_base_service_caps
@@ -206,6 +218,18 @@
                 type: string
                 required: false
                 description: Label that matches network used to connect HPC and BBS services.
+            wan_container_gateway_ip:
+                type: string
+                required: false
+            wan_container_gateway_mac:
+                type: string
+                required: false
+            wan_container_netbits:
+                type: string
+                required: false
+            dns_servers:
+                type: string
+                required: false
 
     tosca.nodes.VBNGService:
         derived_from: tosca.nodes.Root
@@ -409,6 +433,7 @@
             This is a variant of the TOSCA Network object that includes additional

             XOS-specific properties.

           properties:

+            xos_base_props

             ip_version:

               type: integer

               required: no

@@ -510,6 +535,17 @@
                 required: false
                 description: Comma-separated list of flavors that this deployment supports.
 
+    tosca.nodes.AddressPool:
+        derived_from: tosca.nodes.Root
+        description: >
+            A pool of addresses
+        properties:
+            xos_base_props
+            addresses:
+                type: string
+                required: false
+                description: space-separated list of addresses
+
     tosca.nodes.Image:
         derived_from: tosca.nodes.Root
         description: >
diff --git a/xos/tosca/custom_types/xos.yaml b/xos/tosca/custom_types/xos.yaml
index 1b5db39..88b3388 100644
--- a/xos/tosca/custom_types/xos.yaml
+++ b/xos/tosca/custom_types/xos.yaml
@@ -151,6 +151,18 @@
             rest_onos/v1/network/configuration/:
                 type: string
                 required: false
+            rest_hostname:
+                type: string
+                required: false
+            rest_port:
+                type: string
+                required: false
+            no_container:
+                type: boolean
+                default: false
+            node_key:
+                type: string
+                required: false
 
 
     tosca.nodes.ONOSApp:
@@ -251,9 +263,9 @@
                 type: string
                 required: false
 
-    tosca.nodes.VCPEService:
+    tosca.nodes.VSGService:
         description: >
-            CORD: The vCPE Service.
+            CORD: The vSG Service.
         derived_from: tosca.nodes.Root
         capabilities:
             scalable:
@@ -308,6 +320,18 @@
                 type: string
                 required: false
                 description: Label that matches network used to connect HPC and BBS services.
+            wan_container_gateway_ip:
+                type: string
+                required: false
+            wan_container_gateway_mac:
+                type: string
+                required: false
+            wan_container_netbits:
+                type: string
+                required: false
+            dns_servers:
+                type: string
+                required: false
 
     tosca.nodes.VBNGService:
         derived_from: tosca.nodes.Root
@@ -622,6 +646,18 @@
             This is a variant of the TOSCA Network object that includes additional

             XOS-specific properties.

           properties:

+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object

             ip_version:

               type: integer

               required: no

@@ -734,6 +770,28 @@
                 required: false
                 description: Comma-separated list of flavors that this deployment supports.
 
+    tosca.nodes.AddressPool:
+        derived_from: tosca.nodes.Root
+        description: >
+            A pool of addresses
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            addresses:
+                type: string
+                required: false
+                description: space-separated list of addresses
+
     tosca.nodes.Image:
         derived_from: tosca.nodes.Root
         description: >
diff --git a/xos/tosca/resources/addresspool.py b/xos/tosca/resources/addresspool.py
new file mode 100644
index 0000000..e8577a2
--- /dev/null
+++ b/xos/tosca/resources/addresspool.py
@@ -0,0 +1,53 @@
+import os
+import pdb
+import socket
+import sys
+import struct
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from core.models import AddressPool
+
+from xosresource import XOSResource
+
+class XOSAddressPool(XOSResource):
+    provides = "tosca.nodes.AddressPool"
+    xos_model = AddressPool
+    copyin_props = ["addresses"]
+
+    def expand_cidr(self, cidr):
+        (network, bits) = cidr.split("/")
+        network=network.strip()
+        bits=int(bits.strip())
+
+        dest = []
+
+        netmask = (~(pow(2,32-bits)-1) & 0xFFFFFFFF)
+
+        count = pow(2, 32-bits)
+        for i in range(2, count-1):
+            ip = struct.unpack("!L", socket.inet_aton(network))[0]
+            ip = ip & netmask | i
+            dest.append( socket.inet_ntoa(struct.pack("!L", ip)) )
+
+        return dest
+
+    def get_xos_args(self):
+        args = super(XOSAddressPool, self).get_xos_args()
+
+        if "addresses" in args:
+            dest = []
+            for addr in args["addresses"].split():
+                addr=addr.strip()
+                if "/" in addr:
+                    dest.extend(self.expand_cidr(addr))
+                else:
+                    dest.append(addr)
+            args["addresses"] = " ".join(dest)
+
+        return args
+
+
+
+
diff --git a/xos/tosca/resources/hpchealthcheck.py b/xos/tosca/resources/hpchealthcheck.py
new file mode 100644
index 0000000..93a0912
--- /dev/null
+++ b/xos/tosca/resources/hpchealthcheck.py
@@ -0,0 +1,39 @@
+import importlib
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+import pdb
+
+from services.hpc.models import HpcHealthCheck, HpcService
+
+from xosresource import XOSResource
+
+class XOSHpcHealthCheck(XOSResource):
+    provides = "tosca.nodes.HpcHealthCheck"
+    xos_model = HpcHealthCheck
+    name_field = None
+    copyin_props = ("kind", "resource_name", "result_contains")
+
+    def get_xos_args(self, throw_exception=True):
+        args = super(XOSHpcHealthCheck, self).get_xos_args()
+
+        service_name = self.get_requirement("tosca.relationships.MemberOfService", throw_exception=throw_exception)
+        if service_name:
+            args["hpcService"] = self.get_xos_object(HpcService, throw_exception=throw_exception, name=service_name)
+
+        return args
+
+    def get_existing_objs(self):
+        args = self.get_xos_args(throw_exception=True)
+
+        return list( HpcHealthCheck.objects.filter(hpcService=args["hpcService"], kind=args["kind"], resource_name=args["resource_name"]) )
+
+    def postprocess(self, obj):
+        pass
+
+    def can_delete(self, obj):
+        return super(XOSTenant, self).can_delete(obj)
+
diff --git a/xos/tosca/resources/network.py b/xos/tosca/resources/network.py
index f483b6c..7b513c3 100644
--- a/xos/tosca/resources/network.py
+++ b/xos/tosca/resources/network.py
@@ -39,6 +39,10 @@
             # we have to manually fill in some defaults.
             args["permit_all_slices"] = True
 
+        cidr = self.get_property_default("cidr", None)
+        if cidr:
+            args["subnet"] = cidr
+
         return args
 
     def postprocess(self, obj):
diff --git a/xos/tosca/resources/onosapp.py b/xos/tosca/resources/onosapp.py
index 5947400..321600d 100644
--- a/xos/tosca/resources/onosapp.py
+++ b/xos/tosca/resources/onosapp.py
@@ -57,7 +57,7 @@
             v = d.value
             if k.startswith("config_"):
                 self.set_tenant_attr(obj, k, v)
-            elif k.startswith("rest_"):
+            elif k.startswith("rest_") and (k!="rest_hostname") and (k!="rest_port"):
                 self.set_tenant_attr(obj, k, v)
             elif k.startswith("component_config"):
                 self.set_tenant_attr(obj, k, v)
diff --git a/xos/tosca/resources/onosservice.py b/xos/tosca/resources/onosservice.py
index b742ebb..3540dd0 100644
--- a/xos/tosca/resources/onosservice.py
+++ b/xos/tosca/resources/onosservice.py
@@ -13,7 +13,7 @@
 class XOSONOSService(XOSService):
     provides = "tosca.nodes.ONOSService"
     xos_model = ONOSService
-    copyin_props = ["view_url", "icon_url", "enabled", "published", "public_key", "versionNumber"]
+    copyin_props = ["view_url", "icon_url", "enabled", "published", "public_key", "versionNumber", "rest_hostname", "rest_port", "no_container", "node_key"]
 
     def set_service_attr(self, obj, prop_name, value):
         value = self.try_intrinsic_function(value)
@@ -36,6 +36,6 @@
             v = d.value
             if k.startswith("config_"):
                 self.set_service_attr(obj, k, v)
-            elif k.startswith("rest_"):
+            elif k.startswith("rest_")  and (k!="rest_hostname") and (k!="rest_port"):
                 self.set_service_attr(obj, k, v)
 
diff --git a/xos/tosca/resources/slice.py b/xos/tosca/resources/slice.py
index 7dcbd59..48e5eb0 100644
--- a/xos/tosca/resources/slice.py
+++ b/xos/tosca/resources/slice.py
@@ -12,7 +12,7 @@
 class XOSSlice(XOSResource):
     provides = "tosca.nodes.Slice"
     xos_model = Slice
-    copyin_props = ["enabled", "description", "slice_url", "max_instances", "default_isolation", "network", "exposed_ports"]
+    copyin_props = ["enabled", "description", "slice_url", "max_instances", "default_isolation", "default_flavor", "network", "exposed_ports"]
 
     def get_xos_args(self):
         args = super(XOSSlice, self).get_xos_args()
diff --git a/xos/tosca/resources/vcpeservice.py b/xos/tosca/resources/vcpeservice.py
index abcdea9..5c7b2a7 100644
--- a/xos/tosca/resources/vcpeservice.py
+++ b/xos/tosca/resources/vcpeservice.py
@@ -5,12 +5,15 @@
 sys.path.append("/opt/tosca")
 from translator.toscalib.tosca_template import ToscaTemplate
 
-from services.cord.models import VCPEService
+from services.cord.models import VSGService
 
 from service import XOSService
 
-class XOSVcpeService(XOSService):
-    provides = "tosca.nodes.VCPEService"
-    xos_model = VCPEService
-    copyin_props = ["view_url", "icon_url", "enabled", "published", "public_key", "private_key_fn", "versionNumber", "backend_network_label"]
+class XOSVsgService(XOSService):
+    provides = "tosca.nodes.VSGService"
+    xos_model = VSGService
+    copyin_props = ["view_url", "icon_url", "enabled", "published", "public_key",
+                    "private_key_fn", "versionNumber", "backend_network_label",
+                    "wan_container_gateway_ip", "wan_container_gateway_mac",
+                    "wan_container_netbits", "dns_servers"]
 
diff --git a/xos/tosca/samples/two_slices_two_networks.yaml b/xos/tosca/samples/two_slices_two_networks.yaml
new file mode 100644
index 0000000..080a6f0
--- /dev/null
+++ b/xos/tosca/samples/two_slices_two_networks.yaml
@@ -0,0 +1,69 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Template for deploying a single server with predefined properties.
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    mysite:
+      type: tosca.nodes.Site
+
+    Private:
+      type: tosca.nodes.NetworkTemplate
+
+    # this one lets XOS auto-allocate a subnet
+    producer_private_network:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
+      requirements:
+          - network_template:
+              node: Private
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - slice:
+              node: mysite_producer
+              relationship: tosca.relationships.MemberOfSlice
+          - slice:
+              node: mysite_producer
+              relationship: tosca.relationships.ConnectsToSlice
+
+    # this one specifies the subnet to use
+    producer_private_network2:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
+          cidr: 123.123.0.0/16
+      requirements:
+          - network_template:
+              node: Private
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - slice:
+              node: mysite_producer
+              relationship: tosca.relationships.MemberOfSlice
+          - slice:
+              node: mysite_producer
+              relationship: tosca.relationships.ConnectsToSlice
+
+    mysite_producer:
+      type: tosca.nodes.Slice
+      requirements:
+          - slice:
+                node: mysite
+                relationship: tosca.relationships.MemberOfSite
+
+    mysite_consumer:
+      type: tosca.nodes.Slice
+      requirements:
+          - slice:
+                node: mysite
+                relationship: tosca.relationships.MemberOfSite
+          - network:
+                node: producer_private_network
+                relationship: tosca.relationships.ConnectsToNetwork
+          - network2:
+                node: producer_private_network2
+                relationship: tosca.relationships.ConnectsToNetwork
+
+
diff --git a/xos/tosca/samples/vtn-external.yaml b/xos/tosca/samples/vtn-external.yaml
new file mode 100644
index 0000000..ee41ac8
--- /dev/null
+++ b/xos/tosca/samples/vtn-external.yaml
@@ -0,0 +1,31 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Setup CORD-related services -- vOLT, vCPE, vBNG.
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    service_ONOS_VTN:
+      type: tosca.nodes.ONOSService
+      requirements:
+      properties:
+          kind: onos
+          view_url: /admin/onos/onosservice/$id$/
+          no_container: true
+          rest_hostname: ctl.smbaker-xos-neu.xos-pg0.clemson.cloudlab.us
+
+    VTN_ONOS_app:
+      type: tosca.nodes.ONOSVTNApp
+      requirements:
+          - onos_tenant:
+              node: service_ONOS_VTN
+              relationship: tosca.relationships.TenantOfService
+      properties:
+          dependencies: org.onosproject.drivers, org.onosproject.drivers.ovsdb, org.onosproject.lldpprovider, org.onosproject.openflow-base, org.onosproject.ovsdb-base, org.onosproject.dhcp, org.onosproject.openstackswitching, org.onosproject.cordvtn
+          rest_onos/v1/network/configuration/: { get_artifact: [ SELF, vtn_network_cfg_json, LOCAL_FILE ] }
+      artifacts:
+          vtn_network_cfg_json: /root/setup/vtn-network-cfg.json
+
+
diff --git a/xos/xos/exceptions.py b/xos/xos/exceptions.py
index 52badf8..9ab2605 100644
--- a/xos/xos/exceptions.py
+++ b/xos/xos/exceptions.py
@@ -62,3 +62,9 @@
                             "specific_error": why,
                             "fields": fields})
 
+class XOSServiceUnavailable(APIException):
+    status_code=503
+    def __init__(self, why="Service temporarily unavailable, try again later", fields={}):
+        APIException.__init__(self, {"error": "XOSServiceUnavailable",
+                            "specific_error": why,
+                            "fields": fields})
diff --git a/xos/xos/settings.py b/xos/xos/settings.py
index a6313cf..c8b0b07 100644
--- a/xos/xos/settings.py
+++ b/xos/xos/settings.py
@@ -224,8 +224,8 @@
     }
 }
 
-RESTAPI_HOSTNAME = getattr(config, "server_restapihostname", getattr(config, "server_hostname", socket.gethostname()))
-RESTAPI_PORT = int(getattr(config, "server_port", "8000"))
+RESTAPI_HOSTNAME = getattr(config, "server_restapi_hostname", getattr(config, "server_hostname", socket.gethostname()))
+RESTAPI_PORT = int(getattr(config, "server_restapi_port", getattr(config, "server_port", "8000")))
 
 BIGQUERY_TABLE = getattr(config, "bigquery_table", "demoevents")