Merge branch 'master' into feature/fabric-synchronizer
diff --git a/applications/auto-scale/xos_auto_scaling_app.py b/applications/auto-scale/xos_auto_scaling_app.py
index 848ccc0..68ba4cf 100644
--- a/applications/auto-scale/xos_auto_scaling_app.py
+++ b/applications/auto-scale/xos_auto_scaling_app.py
@@ -17,6 +17,12 @@
 
 use_kafka = True
 
+XOS_ENDPOINT = '130.127.133.58:9999'
+KAFKA_SERVER_IP = '130.127.133.58'
+KAFKA_SERVER_PORT = '9092'
+KAFKA_TOPIC = 'auto-scale'
+LOCAL_KAFKA_TARGET_URL = 'kafka://'+KAFKA_SERVER_IP+':'+KAFKA_SERVER_PORT+'?topic='+KAFKA_TOPIC
+
 if use_kafka:
    import kafka
    from kafka import TopicPartition
@@ -31,7 +37,7 @@
     return response
 
 def acquire_xos_monitoring_channel():
-    url = "http://ctl:9999/xoslib/monitoringchannel/"
+    url = "http://"+XOS_ENDPOINT+"/api/tenant/ceilometer/monitoringchannel/"
     admin_auth=("padmin@vicci.org", "letmein")   # use your XOS username and password
     monitoring_channels = requests.get(url, auth=admin_auth).json()
     ceilometer_url = None
@@ -85,7 +91,7 @@
 
 def loadAllXosTenantInfo():
     print "SRIKANTH: Loading all XOS tenant info"
-    url = "http://ctl:9999/xos/controllerslices/"
+    url = "http://"+XOS_ENDPOINT+"/xos/controllerslices/"
     admin_auth=("padmin@vicci.org", "letmein")   # use your XOS username and password
     controller_slices = requests.get(url, auth=admin_auth).json()
     for cslice in controller_slices:
@@ -101,7 +107,7 @@
 
 def loadAllXosInstanceInfo():
     print "SRIKANTH: Loading all XOS instance info"
-    url = "http://ctl:9999/xos/instances/"
+    url = "http://"+XOS_ENDPOINT+"/xos/instances/"
     admin_auth=("padmin@vicci.org", "letmein")   # use your XOS username and password
     xos_instances = requests.get(url, auth=admin_auth).json()
     for instance in xos_instances:
@@ -148,7 +154,7 @@
         return
     print "SRIKANTH: SCALE %s for Project %s, Slice=%s, Service=%s from current=%d to new=%d" % (adjust, project, xos_slice, xos_service, current_instances, current_instances+1 if (adjust=='up') else current_instances-1)
     query_params = {'service':xos_service, 'slice_hint':xos_slice, 'scale':current_instances+1 if (adjust=='up') else current_instances-1}
-    url = "http://ctl:9999/xoslib/serviceadjustscale/"
+    url = "http://"+XOS_ENDPOINT+"/xoslib/serviceadjustscale/"
     admin_auth=("padmin@vicci.org", "letmein")   # use your XOS username and password
     response = requests.get(url, params=query_params, auth=admin_auth).json()
     print "SRIKANTH: XOS adjust_scale response: %s" % response
@@ -233,7 +239,7 @@
 
 def process_notification_from_ceilometer(sample):
          if sample['counter_name'] == 'instance':
-             if 'delete' in sample['resource_metadata']['event_type']:
+             if ('event_type' in sample['resource_metadata'].keys()) and ('delete' in sample['resource_metadata']['event_type']):
 	          xosTenantInfo = getXosTenantInfo(sample['project_id'])
                   xosResourceInfo = getXosInstanceInfo(sample['resource_id'])
                   print "SRIKANTH: Project %s Instance %s is getting deleted" % (xosTenantInfo['slice'] if xosTenantInfo['slice'] else sample['project_id'],xosResourceInfo) 
@@ -305,8 +311,8 @@
    loadAllXosInstanceInfo()
    ceilometer_url = monitoring_channel['ceilometer_url']
    if use_kafka:
-       thread.start_new(read_notification_from_ceilometer_over_kafka, ("10.11.10.1","9092","auto-scale",))
-       subscribe_data = {"sub_info":"cpu_util","app_id":"xos_auto_scale","target":"kafka://10.11.10.1:9092?topic=auto-scale"}
+       thread.start_new(read_notification_from_ceilometer_over_kafka, (KAFKA_SERVER_IP,KAFKA_SERVER_PORT,KAFKA_TOPIC,))
+       subscribe_data = {"sub_info":"cpu_util","app_id":"xos_auto_scale","target":LOCAL_KAFKA_TARGET_URL}
    else:
        thread.start_new(read_notification_from_ceilometer,(UDP_IP,UDP_PORT,))
        subscribe_data = {"sub_info":"cpu_util","app_id":"xos_auto_scale","target":"udp://10.11.10.1:12346"}
@@ -317,7 +323,10 @@
    if (not 'sucess' in response.text) and (not 'already exists' in response.text):
        print 'SRIKANTH: Ceilometer meter "cpu_util" Subscription unsuccessful...Exiting'
        return
-   subscribe_data = {"sub_info":"instance","app_id":"xos_auto_scale2","target":"udp://10.11.10.1:12346"}
+   if use_kafka:
+        subscribe_data = {"sub_info":"instance","app_id":"xos_auto_scale2","target":LOCAL_KAFKA_TARGET_URL}
+   else:
+        subscribe_data = {"sub_info":"instance","app_id":"xos_auto_scale2","target":"udp://10.11.10.1:12346"}
    subscribe_url = ceilometer_url + 'v2/subscribe'
    response = requests.post(subscribe_url, data=json.dumps(subscribe_data))
    print 'SRIKANTH: Ceilometer meter "instance" Subscription status:%s' % response.text
diff --git a/containers/onboarding_synchronizer/Dockerfile b/containers/onboarding_synchronizer/Dockerfile
new file mode 100644
index 0000000..967e234
--- /dev/null
+++ b/containers/onboarding_synchronizer/Dockerfile
@@ -0,0 +1,40 @@
+FROM       xosproject/xos-synchronizer-openstack
+
+# Install docker-in-docker (dind). See https://hub.docker.com/_/docker/. The docker git repo
+# currently only has 1.10 and 1.11, but it's possible to get the dockerfiles for earlier
+# versions by using:
+#        docker pull centurylink/dockerfile-from-image
+#        alias dfimage="docker run -v /var/run/docker.sock:/var/run/docker.sock --rm centurylink/dockerfile-from-image"
+#        dgimage <name of image>
+
+# This container must be started in privileged mode. 
+
+RUN apt-get install -y curl
+# iptables 
+ENV DOCKER_BUCKET=get.docker.com
+ENV DOCKER_VERSION=1.8.3
+ENV DOCKER_SHA256=f024bc65c45a3778cf07213d26016075e8172de8f6e4b5702bedde06c241650f
+RUN curl -fSL "https://${DOCKER_BUCKET}/builds/Linux/x86_64/docker-$DOCKER_VERSION" -o /usr/local/bin/docker && echo "${DOCKER_SHA256} /usr/local/bin/docker" | sha256sum -c - && chmod +x /usr/local/bin/docker
+
+# XXX uncomment the following 6 lines to run docker-in-docker
+#     comment them out if using the docker socket in a volume instead
+#ENV DIND_COMMIT=3b5fac462d21ca164b3778647420016315289034
+#RUN wget "https://raw.githubusercontent.com/docker/docker/${DIND_COMMIT}/hack/dind" -O /usr/local/bin/dind && chmod +x /usr/local/bin/dind
+#COPY start-dockerd.sh /usr/local/bin/
+#VOLUME /var/lib/docker
+#EXPOSE 2375
+#ENTRYPOINT ["start-dockerd.sh"]
+
+# Instead of using docker-in-docker, we can just attach ourselves
+# to the docker socket via a volume in the docker-compose:
+#     - /var/run/docker.sock:/var/run/docker.sock
+# This is more convenient, allowing us to build directly into our
+# parent's docker build system, making the images available for
+# instantiation on the parent. 
+
+# Now install docker-compose
+
+RUN bash -c "curl -L https://github.com/docker/compose/releases/download/1.5.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose"
+RUN chmod +x /usr/local/bin/docker-compose
+
+CMD update-ca-certificates && /usr/bin/supervisord -c /etc/supervisor/conf.d/synchronizer.conf
diff --git a/containers/onboarding_synchronizer/Makefile b/containers/onboarding_synchronizer/Makefile
new file mode 100644
index 0000000..6532196
--- /dev/null
+++ b/containers/onboarding_synchronizer/Makefile
@@ -0,0 +1,15 @@
+IMAGE_NAME:=xosproject/xos-synchronizer-onboarding
+CONTAINER_NAME:=xos-synchronizer
+NO_DOCKER_CACHE?=false
+
+.PHONY: build
+build: ; sudo docker build --no-cache=${NO_DOCKER_CACHE} --rm -t ${IMAGE_NAME} .
+
+.PHONY: run
+run: ; sudo docker run -d --name ${CONTAINER_NAME} -v /usr/local/share/ca-certificates:/usr/local/share/ca-certificates:ro ${IMAGE_NAME}
+
+.PHONY: stop
+stop: ; sudo docker stop ${CONTAINER_NAME}
+
+.PHONY: rm
+rm: ; sudo docker rm ${CONTAINER_NAME}
diff --git a/containers/onboarding_synchronizer/start-dockerd.sh b/containers/onboarding_synchronizer/start-dockerd.sh
new file mode 100755
index 0000000..bb97341
--- /dev/null
+++ b/containers/onboarding_synchronizer/start-dockerd.sh
@@ -0,0 +1,3 @@
+#! /bin/bash
+
+docker daemon --host=unix:///var/run/docker.sock --host=tcp://0.0.0.0:2375 --storage-driver=aufs
diff --git a/containers/onos/Dockerfile b/containers/onos/Dockerfile
new file mode 100644
index 0000000..d00b8e2
--- /dev/null
+++ b/containers/onos/Dockerfile
@@ -0,0 +1,57 @@
+FROM debian:jessie
+MAINTAINER Zack Williams <zdw@cs.arizona.edu>
+
+# Add Java 8 repository
+ENV DEBIAN_FRONTEND noninteractive
+RUN echo debconf shared/accepted-oracle-license-v1-1 select true | debconf-set-selections && \
+    echo "deb http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main" | tee /etc/apt/sources.list.d/webupd8team-java.list && \
+    echo "deb-src http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main" | tee -a /etc/apt/sources.list.d/webupd8team-java.list && \
+    apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys EEA14886
+
+# Set the environment variables
+ENV HOME /root
+ENV JAVA_HOME /usr/lib/jvm/java-8-oracle
+ENV ONOS_ROOT /src/onos
+ENV KARAF_VERSION 3.0.5
+ENV KARAF_ROOT /root/onos/apache-karaf-3.0.5
+ENV KARAF_LOG /root/onos/apache-karaf-3.0.5/data/log/karaf.log
+ENV BUILD_NUMBER docker
+ENV PATH $PATH:$KARAF_ROOT/bin
+
+#Download and Build ONOS
+WORKDIR /src
+RUN     apt-get update && apt-get install -y python maven git curl oracle-java8-installer oracle-java8-set-default && \
+        git clone https://github.com/opennetworkinglab/onos.git && cd onos && \
+        git checkout f503a62372ffa55150936628689d1435109ffccb && \
+        mkdir -p /root/Downloads && \
+        mvn clean install && \
+        tools/build/onos-package && \
+        rm -rf /root/.m2 && cd .. && \
+        rm -rf onos && \
+        apt-get remove --purge -y `apt-mark showauto` && \
+        apt-get install oracle-java8-set-default -y && \
+        apt-get clean && apt-get purge -y && apt-get autoremove -y && \
+        rm -rf /var/lib/apt/lists/* && \
+        rm -rf /var/cache/oracle-jdk8-installer && \
+        rm -rf /root/Downloads
+
+# Change to /root directory
+WORKDIR /root
+
+#Install ONOS
+RUN mkdir onos && \
+   mv /tmp/onos-*.docker.tar.gz . && \
+   tar -xf onos-*.docker.tar.gz -C onos --strip-components=1 && \
+   rm -rf onos-*.docker.tar.gz
+
+# Ports
+# 6653 - OpenFlow
+# 8181 - GUI
+# 8101 - ONOS CLI
+# 9876 - ONOS CLUSTER COMMUNICATION
+EXPOSE 6653 8181 8101 9876
+
+# Get ready to run command
+WORKDIR /root/onos
+ENTRYPOINT ["./bin/onos-service"]
+
diff --git a/containers/onos/Makefile b/containers/onos/Makefile
new file mode 100644
index 0000000..4db1a9b
--- /dev/null
+++ b/containers/onos/Makefile
@@ -0,0 +1,15 @@
+IMAGE_NAME:=xosproject/onos-fork
+CONTAINER_NAME:=onos-fork
+NO_DOCKER_CACHE?=false
+
+.PHONY: build
+build: ; sudo docker build --no-cache=${NO_DOCKER_CACHE} --rm -t ${IMAGE_NAME} .
+
+.PHONY: run
+run: ; sudo docker run -d --name ${CONTAINER_NAME} ${IMAGE_NAME}
+
+.PHONY: stop
+stop: ; sudo docker stop ${CONTAINER_NAME}
+
+.PHONY: rm
+rm: ; sudo docker rm ${CONTAINER_NAME}
diff --git a/views/ngXosLib/package.json b/views/ngXosLib/package.json
index da9d27b..ba25551 100644
--- a/views/ngXosLib/package.json
+++ b/views/ngXosLib/package.json
@@ -12,7 +12,8 @@
     "doc": "gulp docs; cd ./docs",
     "doc:ci": "gulp makeDocs;",
     "build": "gulp vendor && gulp helpers",
-    "dev": "gulp dev"
+    "dev": "gulp dev",
+    "lint": "eslint xosHelpers/"
   },
   "author": "Matteo Scandolo",
   "license": "ISC",
diff --git a/views/ngXosLib/xosHelpers/spec/services/helpers/form.helpers.test.js b/views/ngXosLib/xosHelpers/spec/services/helpers/form.helpers.test.js
index f6bfbb2..a126db5 100644
--- a/views/ngXosLib/xosHelpers/spec/services/helpers/form.helpers.test.js
+++ b/views/ngXosLib/xosHelpers/spec/services/helpers/form.helpers.test.js
@@ -17,8 +17,7 @@
         'name',
         'mail',
         'active',
-        'created',
-        'custom'
+        'created'
       ];
 
       let modelField = {
@@ -26,8 +25,7 @@
         name: {},
         mail: {},
         active: {},
-        created: {},
-        custom: {}
+        created: {}
       };
 
       let model = {
@@ -40,6 +38,14 @@
       };
 
       let customField = {
+        id: {
+          label: 'Id',
+          type: 'number',
+          validators: {
+            required: true
+          },
+          hint: ''
+        },
         custom: {
           label: 'Custom Label',
           type: 'number',
@@ -52,7 +58,9 @@
         id: {
           label: 'Id:',
           type: 'number',
-          validators: {},
+          validators: {
+            required: true
+          },
           hint: ''
         },
         name: {
@@ -152,7 +160,35 @@
 
       describe('when modelField are provided', () => {
         it('should combine modelField and customField in a form object', () => {
-          expect(service.buildFormStructure(modelField, customField, model)).toEqual(formObject);
+          const form = service.buildFormStructure(modelField, customField, model);
+          expect(form).toEqual(formObject);
+        });
+
+        it('should override modelField properties whith customField properties', () => {
+          const customFieldOverride = {
+            id: {
+              hint: 'something',
+              type: 'select',
+              options: [
+                {id: 1, label: 'one'},
+                {id: 2, label: 'two'}
+              ],
+              validators: {
+                required: true
+              }
+            }
+          };
+          const form = service.buildFormStructure({id: {}}, customFieldOverride, model);
+          
+          expect(form).toEqual({
+            id: {
+              label: 'Id:',
+              validators: {required: true},
+              hint: customFieldOverride.id.hint,
+              type: customFieldOverride.id.type,
+              options: customFieldOverride.id.options
+            }
+          });
         });
       });
 
@@ -185,6 +221,31 @@
             label: 'Custom Label',
             type: 'number',
             hint: 'Test Hint'
+          },
+          select: {
+            label: 'Select Label',
+            type: 'select',
+            hint: 'Select Hint',
+            options: [
+              {id: 1, label: 'something'}
+            ]
+          },
+          object: {
+            label: 'Object Label',
+            type: 'object',
+            hint: 'Object Hint',
+            properties: {
+              foo: {
+                type: 'string',
+                label: 'FooLabel',
+                validators: {
+                  required: true
+                }
+              },
+              bar: {
+                type: 'number'
+              }
+            }
           }
         };
 
@@ -224,19 +285,48 @@
             type: 'number',
             validators: {},
             hint: 'Test Hint'
+          },
+          select: {
+            label: 'Select Label:',
+            type: 'select',
+            hint: 'Select Hint',
+            validators: {},
+            options: [
+              {id: 1, label: 'something'}
+            ]
+          },
+          object: {
+            label: 'Object Label:',
+            type: 'object',
+            hint: 'Object Hint',
+            validators: {},
+            properties: {
+              foo: {
+                type: 'string',
+                label: 'FooLabel',
+                validators: {
+                  required: true
+                }
+              },
+              bar: {
+                type: 'number'
+              }
+            }
           }
         };
 
         let empty_model = {5: 'Nan'}
 
         it('should create a form object', () => {
-          let res = service.buildFormStructure(empty_modelField, empty_customFields, empty_model)
+          let res = service.buildFormStructure(empty_modelField, empty_customFields, empty_model);
           expect(res.id).toEqual(empty_formObject.id);
           expect(res.name).toEqual(empty_formObject.name);
           expect(res.mail).toEqual(empty_formObject.mail);
           expect(res.active).toEqual(empty_formObject.active);
           expect(res.created).toEqual(empty_formObject.created);
           expect(res.custom).toEqual(empty_formObject.custom);
+          expect(res.select).toEqual(empty_formObject.select);
+          expect(res.object).toEqual(empty_formObject.object);
           expect(res).toEqual(empty_formObject);
         });
       });
diff --git a/views/ngXosLib/xosHelpers/spec/ui/field.test.js b/views/ngXosLib/xosHelpers/spec/ui/field.test.js
index f933a01..62a41a7 100644
--- a/views/ngXosLib/xosHelpers/spec/ui/field.test.js
+++ b/views/ngXosLib/xosHelpers/spec/ui/field.test.js
@@ -59,6 +59,18 @@
         expect(errorFunctionWrapper).toThrow(new Error('[xosField] Please provide a field definition'));
       }));
 
+      it('should throw an error if no field type is passed', inject(($compile, $rootScope) => {
+        function errorFunctionWrapper(){
+          // setup the parent scope
+          scope = $rootScope.$new();
+          scope.name = 'label';
+          scope.ngModel = 1;
+          scope.field = {label: 'Label:'}
+          compileElement();
+        }
+        expect(errorFunctionWrapper).toThrow(new Error('[xosField] Please provide a type in the field definition'));
+      }));
+
       it('should throw an error if no field model is passed', inject(($compile, $rootScope) => {
         function errorFunctionWrapper(){
           // setup the parent scope
@@ -92,6 +104,42 @@
         });
       });
 
+
+
+
+      describe('when a option is selected in dropdown', () => {
+        beforeEach(() => {
+          scope = rootScope.$new();
+          scope.name = 'label';
+          scope.field = {
+            label: 'Label',
+            type: 'select',
+            validators: {},
+            options: [
+              {
+                id: 0,
+                label: '---Site---'
+              },
+              {
+                id: 1,
+                label: '---Site1---'
+              }
+            ]
+          };
+          scope.ngModel = 'label';
+          compileElement();
+        });
+
+        it('No of select elements', () => {
+          expect($(element).find('select').children('option').length).toEqual(3);
+        });
+
+        it('should show a selected value', () => {
+          var elem =  angular.element($(element).find('select').children('option')[1]);
+          expect(elem.text()).toEqual('---Site---');
+        });
+      });
+
       describe('when a number input is passed', () => {
         beforeEach(() => {
           scope = rootScope.$new();
@@ -187,9 +235,36 @@
           });
 
           it('should not print the panel', () => {
-            // console.log($(element).find('.panel.object-field'));
             expect($(element).find('.panel.object-field')).not.toExist()
           });
+
+          describe('but field is configured', () => {
+            beforeEach(() => {
+              scope.field.properties = {
+                foo: {
+                  label: 'FooLabel:',
+                  type: 'string',
+                  validators: {
+                    required: true
+                  }
+                },
+                bar: {
+                  type: 'number'
+                }
+              };
+              compileElement();
+            });
+            it('should render panel and configured fields', () => {
+              expect($(element).find('.panel.object-field')).toExist();
+              expect($(element).find('input[name="foo"]').parent().find('label').text()).toBe('FooLabel:');
+              expect($(element).find('input[name="foo"]')).toHaveAttr('type', 'string');
+              expect($(element).find('input[name="foo"]')).toHaveAttr('required');
+
+              expect($(element).find('input[name="bar"]').parent().find('label').text()).toBe('Bar:');
+              expect($(element).find('input[name="bar"]')).toHaveAttr('type', 'number');
+
+            });
+          });
         });
       });
     });
diff --git a/views/ngXosLib/xosHelpers/spec/ui/form.test.js b/views/ngXosLib/xosHelpers/spec/ui/form.test.js
index cb9f9e8..eac10f5 100644
--- a/views/ngXosLib/xosHelpers/spec/ui/form.test.js
+++ b/views/ngXosLib/xosHelpers/spec/ui/form.test.js
@@ -33,21 +33,21 @@
         compile = $compile;
       }));
 
-      it('should throw an error if no config is specified', inject(($compile, $rootScope) => {
+      it('should throw an error if no config is specified', () => {
         function errorFunctionWrapper(){
           compileElement();
         }
         expect(errorFunctionWrapper).toThrow(new Error('[xosForm] Please provide a configuration via the "config" attribute'));
-      }));
+      });
 
-      it('should throw an error if no actions is specified', inject(($compile, $rootScope) => {
+      it('should throw an error if no actions is specified', () => {
         function errorFunctionWrapper(){
-          scope = $rootScope.$new();
+          scope = rootScope.$new();
           scope.config = 'green';
           compileElement();
         }
         expect(errorFunctionWrapper).toThrow(new Error('[xosForm] Please provide an action list in the configuration'));
-      }));
+      });
 
       describe('when correctly configured', () => {
         
diff --git a/views/ngXosLib/xosHelpers/spec/ui/table.test.js b/views/ngXosLib/xosHelpers/spec/ui/table.test.js
index e94eb36..1535c6e 100644
--- a/views/ngXosLib/xosHelpers/spec/ui/table.test.js
+++ b/views/ngXosLib/xosHelpers/spec/ui/table.test.js
@@ -31,22 +31,22 @@
         rootScope = $rootScope;
       }));
 
-      it('should throw an error if no config is specified', inject(($compile, $rootScope) => {
+      it('should throw an error if no config is specified', () => {
         function errorFunctionWrapper(){
           compileElement();
         }
         expect(errorFunctionWrapper).toThrow(new Error('[xosTable] Please provide a configuration via the "config" attribute'));
-      }));
+      });
 
-      it('should throw an error if no config columns are specified', inject(($compile, $rootScope) => {
+      it('should throw an error if no config columns are specified', () => {
         function errorFunctionWrapper(){
           // setup the parent scope
-          scope = $rootScope.$new();
+          scope = rootScope.$new();
           scope.config = 'green';
           compileElement();
         }
         expect(errorFunctionWrapper).toThrow(new Error('[xosTable] Please provide a columns list in the configuration'));
-      }));
+      });
 
       describe('when basicly configured', function() {
 
diff --git a/views/ngXosLib/xosHelpers/spec/ui/validation.test.js b/views/ngXosLib/xosHelpers/spec/ui/validation.test.js
index bb663fa..f8350ed 100644
--- a/views/ngXosLib/xosHelpers/spec/ui/validation.test.js
+++ b/views/ngXosLib/xosHelpers/spec/ui/validation.test.js
@@ -7,7 +7,7 @@
 (function () {
   'use strict';
 
-  let compile, element, scope, isolatedScope;
+  let compile, element, scope;
 
   const compileElement = (el) => {
     element = el;
@@ -20,7 +20,6 @@
     }
     compile(element)(scope);
     scope.$digest();
-    isolatedScope = element.isolateScope().vm;
   }
 
   describe('The xos.helper module', function(){
diff --git a/views/ngXosLib/xosHelpers/src/services/helpers/ui/form.helpers.js b/views/ngXosLib/xosHelpers/src/services/helpers/ui/form.helpers.js
index 04a383a..bc6a503 100644
--- a/views/ngXosLib/xosHelpers/src/services/helpers/ui/form.helpers.js
+++ b/views/ngXosLib/xosHelpers/src/services/helpers/ui/form.helpers.js
@@ -91,7 +91,7 @@
 
     this.buildFormStructure = (modelField, customField, model) => {
 
-      modelField = Object.keys(modelField).length > 0 ? modelField : customField; //if no model field are provided, check custom
+      modelField = angular.extend(modelField, customField);
       customField = customField || {};
 
       return _.reduce(Object.keys(modelField), (form, f) => {
@@ -100,9 +100,15 @@
           label: (customField[f] && customField[f].label) ? `${customField[f].label}:` : LabelFormatter.format(f),
           type: (customField[f] && customField[f].type) ? customField[f].type : this._getFieldFormat(model[f]),
           validators: (customField[f] && customField[f].validators) ? customField[f].validators : {},
-          hint: (customField[f] && customField[f].hint)? customField[f].hint : ''
+          hint: (customField[f] && customField[f].hint)? customField[f].hint : '',
         };
 
+        if(customField[f] && customField[f].options){
+          form[f].options = customField[f].options;
+        }
+        if(customField[f] && customField[f].properties){
+          form[f].properties = customField[f].properties;
+        }
         if(form[f].type === 'date'){
           model[f] = new Date(model[f]);
         }
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/field/field.component.js b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/field/field.component.js
index 20b7707..686dd38 100644
--- a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/field/field.component.js
+++ b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/field/field.component.js
@@ -103,19 +103,41 @@
             return $window._;
           })
           .controller('SampleCtrl', function(){
-            this.name = 'input-name';
-            this.field = {label: 'My Object Value:', type: 'object'};
-            this.model = {
+            this.name1 = 'input-name';
+            this.field1 = {label: 'My Object Field:', type: 'object'};
+            this.model1 = {
               name: 'Jhon',
               age: '25',
               email: 'jhon@thewall.ru',
               active: true
             };
+
+            this.name2 = 'another-name';
+            this.field2 = {
+              label: 'Empty Object Field',
+              type: 'object',
+              properties: {
+                foo: {
+                  label: 'FooLabel:',
+                  type: 'string',
+                  validators: {
+                    required: true
+                  }
+                },
+                bar: {
+                  type: 'number'
+                }
+              }
+            }
           });
         </file>
         <file name="index.html">
           <div ng-controller="SampleCtrl as vm">
-            <xos-field ng-model="vm.model" name="vm.name" field="vm.field"></xos-field>
+            <h4>Autogenerated object field</h4>
+            <xos-field ng-model="vm.model1" name="vm.name1" field="vm.field1"></xos-field>
+
+            <h4>Configured object field</h4>
+            <xos-field ng-model="vm.model2" name="vm.name2" field="vm.field2"></xos-field>
           </div>
         </file>
       </example>
@@ -131,7 +153,7 @@
       template: `
         <label ng-if="vm.field.type !== 'object'">{{vm.field.label}}</label>
             <input
-              ng-if="vm.field.type !== 'boolean' && vm.field.type !== 'object'"
+              ng-if="vm.field.type !== 'boolean' && vm.field.type !== 'object' && vm.field.type !== 'select'"
               type="{{vm.field.type}}"
               name="{{vm.name}}"
               class="form-control"
@@ -139,6 +161,12 @@
               ng-minlength="vm.field.validators.minlength || 0"
               ng-maxlength="vm.field.validators.maxlength || 2000"
               ng-required="vm.field.validators.required || false" />
+              <select class="form-control" ng-if ="vm.field.type === 'select'"
+                name = "{{vm.name}}"
+                ng-options="item.id as item.label for item in vm.field.options track by item.id"
+                ng-model="vm.ngModel"
+                ng-required="vm.field.validators.required || false">
+                </select>
             <span class="boolean-field" ng-if="vm.field.type === 'boolean'">
               <button
                 class="btn btn-success"
@@ -155,17 +183,28 @@
             </span>
             <div
               class="panel panel-default object-field"
-              ng-if="vm.field.type == 'object' && !vm.isEmptyObject(vm.ngModel)"
+              ng-if="vm.field.type == 'object' && (!vm.isEmptyObject(vm.ngModel) || !vm.isEmptyObject(vm.field.properties))"
               >
               <div class="panel-heading">{{vm.field.label}}</div>
               <div class="panel-body">
-                <div ng-repeat="(k, v) in vm.ngModel">
+                <div ng-if="!vm.field.properties" ng-repeat="(k, v) in vm.ngModel">
                   <xos-field
                     name="k"
                     field="{label: vm.formatLabel(k), type: vm.getType(v)}"
                     ng-model="v">
                   </xos-field>
                 </div>
+                <div ng-if="vm.field.properties" ng-repeat="(k, v) in vm.field.properties">
+                  <xos-field
+                    name="k"
+                    field="{
+                      label: v.label || vm.formatLabel(k),
+                      type: v.type,
+                      validators: v.validators
+                    }"
+                    ng-model="vm.ngModel[k]">
+                  </xos-field>
+                </div>
               </div>
             </div>
       `,
@@ -176,13 +215,16 @@
         return RecursionHelper.compile(element);
       },
       controller: function($attrs, XosFormHelpers, LabelFormatter){
-        // console.log('Field: ', this.name, this.field, this.ngModel);
+
         if(!this.name){
           throw new Error('[xosField] Please provide a field name');
         }
         if(!this.field){
           throw new Error('[xosField] Please provide a field definition');
         }
+        if(!this.field.type){
+          throw new Error('[xosField] Please provide a type in the field definition');
+        }
         if(!$attrs.ngModel){
           throw new Error('[xosField] Please provide an ng-model');
         }
@@ -190,7 +232,7 @@
         this.getType = XosFormHelpers._getFieldFormat;
         this.formatLabel = LabelFormatter.format;
 
-        this.isEmptyObject = o => Object.keys(o).length === 0;
+        this.isEmptyObject = o => o ? Object.keys(o).length === 0 : true;
       }
     }
   });
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/form/form.component.js b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/form/form.component.js
index 92843c2..2a9f00c 100644
--- a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/form/form.component.js
+++ b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/form/form.component.js
@@ -164,7 +164,7 @@
         <ng-form name="vm.{{vm.config.formName || 'form'}}">
           <div class="form-group" ng-repeat="(name, field) in vm.formField">
             <xos-field name="name" field="field" ng-model="vm.ngModel[name]"></xos-field>
-            <xos-validation errors="vm[vm.config.formName || 'form'][name].$error"></xos-validation>
+            <xos-validation field="vm[vm.config.formName || 'form'][name]" form="vm[vm.config.formName || 'form']"></xos-validation>
           </div>
           <div class="form-group" ng-if="vm.config.actions">
             <button role="button" href=""
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/validation/validation.component.js b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/validation/validation.component.js
index dbe4fbb..91610e1 100644
--- a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/validation/validation.component.js
+++ b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/validation/validation.component.js
@@ -29,41 +29,44 @@
           </div>
           <div class="col-xs-2">
             <a class="btn"
-              ng-click="vm.errors.required = !vm.errors.required"
-              ng-class="{'btn-default': !vm.errors.required, 'btn-success': vm.errors.required}">
+              ng-click="vm.field.$error.required = !vm.field.$error.required"
+              ng-class="{'btn-default': !vm.field.$error.required, 'btn-success': vm.field.$error.required}">
               Required
             </a>
           </div>
           <div class="col-xs-2">
             <a class="btn"
-              ng-click="vm.errors.email = !vm.errors.email"
-              ng-class="{'btn-default': !vm.errors.email, 'btn-success': vm.errors.email}">
+              ng-click="vm.field.$error.email = !vm.field.$error.email"
+              ng-class="{'btn-default': !vm.field.$error.email, 'btn-success': vm.field.$error.email}">
               Email
             </a>
           </div>
           <div class="col-xs-2">
             <a class="btn"
-              ng-click="vm.errors.minlength = !vm.errors.minlength"
-              ng-class="{'btn-default': !vm.errors.minlength, 'btn-success': vm.errors.minlength}">
+              ng-click="vm.field.$error.minlength = !vm.field.$error.minlength"
+              ng-class="{'btn-default': !vm.field.$error.minlength, 'btn-success': vm.field.$error.minlength}">
               Min Length
             </a>
           </div>
           <div class="col-xs-2">
             <a class="btn"
-              ng-click="vm.errors.maxlength = !vm.errors.maxlength"
-              ng-class="{'btn-default': !vm.errors.maxlength, 'btn-success': vm.errors.maxlength}">
+              ng-click="vm.field.$error.maxlength = !vm.field.$error.maxlength"
+              ng-class="{'btn-default': !vm.field.$error.maxlength, 'btn-success': vm.field.$error.maxlength}">
               Max Length
             </a>
           </div>
         </div>
-        <xos-validation errors="vm.errors"></xos-validation>
+        <xos-validation field ="vm.field" form = "vm.form"></xos-validation>
       </div>
     </file>
     <file name="script.js">
       angular.module('sampleValidation', ['xos.uiComponents'])
       .controller('SampleCtrl', function(){
-        this.errors = {
-          email: false
+        this.field = {
+          $error: {}
+        };
+        this.form= {
+        $submitted:true
         }
       });
     </file>
@@ -82,16 +85,16 @@
           <xos-alert config="vm.config" show="vm.field.$error.required !== undefined && vm.field.$error.required !== false  && (vm.field.$touched || vm.form.$submitted)">
             Field required
           </xos-alert>
-          <xos-alert config="vm.config" show="vm.field.$error.email !== undefined && vm.field.$error.email !== false  && (vm.field.$touched || vm.form.$submitted)">
+          <xos-alert config="vm.config" show="vm.field.$error.email !== undefined && vm.field.$error.email !== false && (vm.field.$touched || vm.form.$submitted)">
             This is not a valid email
           </xos-alert>
-          <xos-alert config="vm.config" show="vm.field.$error.minlength !== undefined && vm.field.$error.minlength !== false  && (vm.field.$touched || vm.form.$submitted)">
+          <xos-alert config="vm.config" show="vm.field.$error.minlength !== undefined && vm.field.$error.minlength !== false && (vm.field.$touched || vm.form.$submitted)">
             Too short
           </xos-alert>
-          <xos-alert config="vm.config" show="vm.field.$error.maxlength !== undefined && vm.field.$error.maxlength !== false  && (vm.field.$touched || vm.form.$submitted)">
+          <xos-alert config="vm.config" show="vm.field.$error.maxlength !== undefined && vm.field.$error.maxlength !== false && (vm.field.$touched || vm.form.$submitted)">
             Too long
           </xos-alert>
-          <xos-alert config="vm.config" show="vm.field.$error.custom !== undefined && vm.field.$error.custom !== false  && (vm.field.$touched || vm.form.$submitted)">
+          <xos-alert config="vm.config" show="vm.field.$error.custom !== undefined && vm.field.$error.custom !== false && (vm.field.$touched || vm.form.$submitted)">
             Field invalid
           </xos-alert>
         </div>
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/smartComponents/smartPie/smartPie.component.js b/views/ngXosLib/xosHelpers/src/ui_components/smartComponents/smartPie/smartPie.component.js
index c1f08fa..f8a3985 100644
--- a/views/ngXosLib/xosHelpers/src/ui_components/smartComponents/smartPie/smartPie.component.js
+++ b/views/ngXosLib/xosHelpers/src/ui_components/smartComponents/smartPie/smartPie.component.js
@@ -198,13 +198,11 @@
         const formatLabels = (data) => angular.isFunction(this.config.labelFormatter) ? this.config.labelFormatter(Object.keys(data)) : Object.keys(data);
 
         const prepareData = (data) => {
-          // $timeout(() => {
-            // group data
-            let grouped = groupData(data);
-            this.data = formatData(grouped);
-            // create labels
-            this.labels = formatLabels(grouped);
-          // }, 10);
+          // group data
+          let grouped = groupData(data);
+          this.data = formatData(grouped);
+          // create labels
+          this.labels = formatLabels(grouped);
         }
 
         if(this.config.resource){
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/smartComponents/smartTable/smartTable.component.js b/views/ngXosLib/xosHelpers/src/ui_components/smartComponents/smartTable/smartTable.component.js
index b3a2eec..27b1ef6 100644
--- a/views/ngXosLib/xosHelpers/src/ui_components/smartComponents/smartTable/smartTable.component.js
+++ b/views/ngXosLib/xosHelpers/src/ui_components/smartComponents/smartTable/smartTable.component.js
@@ -225,7 +225,7 @@
             let props = Object.keys(item);
 
             _.remove(props, p => {
-              return p == 'id' || p == 'validators'
+              return p === 'id' || p === 'validators'
             });
 
             // TODO move out cb,  non sense triggering a lot of times
diff --git a/views/ngXosViews/synchronizerNotifier/src/js/main.js b/views/ngXosViews/synchronizerNotifier/src/js/main.js
index e761fad..f65c4d1 100644
--- a/views/ngXosViews/synchronizerNotifier/src/js/main.js
+++ b/views/ngXosViews/synchronizerNotifier/src/js/main.js
@@ -3,9 +3,13 @@
 angular.module('xos.synchronizerNotifier', [
   'ngResource',
   'ngCookies',
-  'ui.router',
   'xos.helpers'
 ])
+.run(function($rootScope){
+  $rootScope.$on('$locationChangeStart', function(event) {
+    event.preventDefault();
+  });
+})
 .service('Diag', function($rootScope, $http, $q, $interval){
 
   let isRunning = false;
diff --git a/xos/api/tenant/ceilometer/__init__.py b/xos/api/tenant/ceilometer/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/xos/api/tenant/ceilometer/__init__.py
@@ -0,0 +1 @@
+
diff --git a/xos/api/tenant/ceilometer/monitoringchannel.py b/xos/api/tenant/ceilometer/monitoringchannel.py
new file mode 100644
index 0000000..43e1636
--- /dev/null
+++ b/xos/api/tenant/ceilometer/monitoringchannel.py
@@ -0,0 +1,94 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework import status
+from core.models import *
+from django.forms import widgets
+from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
+from api.xosapi_helpers import PlusModelSerializer, XOSViewSet, ReadOnlyField
+
+from services.ceilometer.models import MonitoringChannel, CeilometerService
+
+def get_default_ceilometer_service():
+    ceilometer_services = CeilometerService.get_service_objects().all()
+    if ceilometer_services:
+        return ceilometer_services[0].id
+    return None
+
+class MonitoringChannelForAPI(MonitoringChannel):
+    class Meta:
+        proxy = True
+        app_label = "ceilometer"
+
+    @property
+    def related(self):
+        related = {}
+        if self.creator:
+            related["creator"] = self.creator.username
+        if self.instance:
+            related["instance_id"] = self.instance.id
+            related["instance_name"] = self.instance.name
+            if self.instance.node:
+                related["compute_node_name"] = self.instance.node.name
+        return related
+
+class MonitoringChannelSerializer(PlusModelSerializer):
+        id = ReadOnlyField()
+        service_specific_attribute = ReadOnlyField()
+        ceilometer_url = ReadOnlyField()
+        tenant_list_str = ReadOnlyField()
+        #creator = ReadOnlyField()
+        #instance = ReadOnlyField()
+        provider_service = serializers.PrimaryKeyRelatedField(queryset=CeilometerService.get_service_objects().all(), default=get_default_ceilometer_service)
+
+        humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+        related = serializers.DictField(required=False)
+
+        #computeNodeName = serializers.SerializerMethodField("getComputeNodeName")
+
+        class Meta:
+            model = MonitoringChannelForAPI
+            fields = ('humanReadableName', 'id', 'provider_service', 'service_specific_attribute', 'ceilometer_url', 'tenant_list_str', 'related' )
+
+        def getHumanReadableName(self, obj):
+            return obj.__unicode__()
+
+        #def getComputeNodeName(self, obj):
+        #    instance = obj.instance
+        #    if not instance:
+        #        return None
+        #    return instance.node.name
+
+class MonitoringChannelSet(XOSViewSet):
+    base_name = "monitoringchannel"
+    method_name = "monitoringchannel"
+    method_kind = "viewset"
+    queryset = MonitoringChannelForAPI.get_tenant_objects().all()
+    serializer_class = MonitoringChannelSerializer
+
+    def get_queryset(self):
+        queryset = MonitoringChannelForAPI.get_tenant_objects().all()
+
+        current_user = self.request.user.username
+        if current_user is not None:
+            ids = [x.id for x in queryset if x.creator.username==current_user]
+            queryset = queryset.filter(id__in=ids)
+
+        return queryset
+
+    def create(self, request):
+        current_user = request.user.username
+        existing_obj = None
+        for obj in MonitoringChannelForAPI.get_tenant_objects().all():
+            if (obj.creator.username == current_user):
+               existing_obj = obj
+               break
+
+        if existing_obj:
+            serializer = MonitoringChannelSerializer(existing_obj)
+            headers = self.get_success_headers(serializer.data)
+            return Response( serializer.data, status=status.HTTP_200_OK )
+
+        return super(MonitoringChannelSet, self).create(request)
diff --git a/xos/api/utility/onboarding.py b/xos/api/utility/onboarding.py
new file mode 100644
index 0000000..dd66d6d
--- /dev/null
+++ b/xos/api/utility/onboarding.py
@@ -0,0 +1,97 @@
+import json
+from django.http import HttpResponse
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework import status
+from core.models import *
+from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
+from api.xosapi_helpers import PlusModelSerializer, XOSViewSet, ReadOnlyField
+
+class OnboardingViewSet(XOSViewSet):
+    base_name = "onboarding"
+    method_name = "onboarding"
+    method_kind = "viewset"
+
+    @classmethod
+    def get_urlpatterns(self, api_path="^"):
+        patterns = [] #super(CordSubscriberViewSet, self).get_urlpatterns(api_path=api_path)
+
+        patterns.append( self.list_url("xos/ready/$", {"get": "get_xos_ready"}, "xos_ready") )
+
+        patterns.append( self.list_url("summary/$", {"get": "get_summary"}, "summary") )
+
+        patterns.append( self.list_url("services/$", {"get": "get_service_list"}, "service_list") )
+        patterns.append( self.list_url("services/(?P<service>[a-zA-Z0-9\-_]+)/ready/$", {"get": "get_service_ready"}, "service_ready") )
+
+
+        return patterns
+
+    def is_ready(self, obj):
+        return (obj.enacted is not None) and (obj.updated is not None) and (obj.enacted>=obj.updated) and (obj.backend_status.startswith("1"))
+
+    def get_xos_ready(self, request):
+        xos = XOS.objects.all()
+        if not xos:
+            return Response(false)
+
+        xos=xos[0]
+
+        result = (xos.enacted is not None) and (xos.updated is not None) and (xos.enacted>=xos.updated) and (xos.backend_status.startswith("1"))
+        return HttpResponse( json.dumps(result), content_type="application/javascript" )
+
+    def get_summary(self, request):
+        result = []
+
+        xos = XOS.objects.all()
+        if not xos:
+            result.append( ("XOS", false) )
+        else:
+            xos=xos[0]
+
+            result.append( ("XOS", self.is_ready(xos)) )
+
+            for sc in xos.service_controllers.all():
+                result.append( (sc.name, self.is_ready(sc)) )
+
+        result = "\n".join( ["%s: %s" % (x[0], x[1]) for x in result] )
+        if result:
+            result = result + "\n"
+
+        return HttpResponse( result, content_type="text/ascii" )
+
+    def get_service_list(self, request):
+        xos = XOS.objects.all()
+        if not xos:
+            return Response([])
+
+        xos=xos[0]
+
+        result = []
+        for sc in xos.service_controllers.all():
+            result.append(sc.name)
+
+        return HttpResponse( json.dumps(result), content_type="application/javascript")
+
+    def get_service_ready(self, request, service):
+        xos = XOS.objects.all()
+        if not xos:
+            return Response([])
+
+        xos=xos[0]
+
+        sc=xos.service_controllers.filter(name=service)
+        if not sc:
+            return HttpResponse("Not Found", status_code=404)
+
+        sc=sc[0]
+        result = self.is_ready(sc)
+
+        return HttpResponse( json.dumps(result), content_type="application/javascript")
+
+
+
+
+
diff --git a/xos/configurations/acord/Makefile b/xos/configurations/acord/Makefile
index cfa04f8..e9b234c 100644
--- a/xos/configurations/acord/Makefile
+++ b/xos/configurations/acord/Makefile
@@ -13,9 +13,13 @@
 	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/common/cloudlab-openstack.yaml
 	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/nodes.yaml
 
-acord: cord
+acord: cord exampleservice
 	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/acord/ceilometer.yaml
 
+exampleservice:
+	#Ensure exampleservice is enabled in xos/tools/xos-manage and xos/settings.py file before uncommenting below lines
+	#sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/acord/acord-exampleservice.yaml
+
 containers:
 	cd ../../../containers/xos; make devel
 	cd ../../../containers/synchronizer; make
diff --git a/xos/configurations/acord/acord-exampleservice.yaml b/xos/configurations/acord/acord-exampleservice.yaml
new file mode 100644
index 0000000..b6b23dd
--- /dev/null
+++ b/xos/configurations/acord/acord-exampleservice.yaml
@@ -0,0 +1,56 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Setup the ExampleService on the ACORD setup
+
+imports:
+   - custom_types/xos.yaml
+   - custom_types/exampleservice.yaml
+
+topology_template:
+  node_templates:
+
+    mysite:
+      type: tosca.nodes.Site
+
+    trusty-server-multi-nic:
+      type: tosca.nodes.Image
+
+    m1.small:
+      type: tosca.nodes.Flavor
+
+    mysite_exampleservice:
+      description: This slice holds the ExampleService
+      type: tosca.nodes.Slice
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+          - exmapleservice:
+              node: service_example
+              relationship: tosca.relationships.MemberOfService
+          - default_image:
+                node: trusty-server-multi-nic
+                relationship: tosca.relationships.DefaultImage
+          - m1.small:
+                node: m1.small
+                relationship: tosca.relationships.DefaultFlavor
+
+    service_example:
+      type: tosca.nodes.ExampleService
+      properties:
+          view_url: /admin/exampleservice/exampleservice/$id$/
+          kind: exampleservice
+          public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
+          private_key_fn: /opt/xos/synchronizers/exampleservice/exampleservice_private_key
+          service_message: hello
+      artifacts:
+          pubkey: /opt/xos/synchronizers/exampleservice/exampleservice_public_key
+
+    exampletenant1:
+        type: tosca.nodes.ExampleTenant
+        properties:
+            tenant_message: world
+        requirements:
+          - tenant:
+              node: service_example
+              relationship: tosca.relationships.TenantOfService
diff --git a/xos/configurations/acord/ceilometer.yaml b/xos/configurations/acord/ceilometer.yaml
index 66d5d32..089837d 100644
--- a/xos/configurations/acord/ceilometer.yaml
+++ b/xos/configurations/acord/ceilometer.yaml
@@ -122,38 +122,38 @@
       properties:
           view_url: /admin/ceilometer/ceilometerservice/$id$/
           kind: ceilometer
-          ceilometer_pub_sub_url: http://10.11.10.1:4455/
+          ceilometer_pub_sub_url: http://130.127.133.58:4455/
           public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
       artifacts:
           pubkey: /opt/xos/synchronizers/monitoring_channel/monitoring_channel_public_key
 
-#    service_sflow:
-#      type: tosca.nodes.SFlowService
-#      requirements:
-#      properties:
-#          view_url: /admin/ceilometer/sflowservice/$id$/
-#          kind: sflow
-#          sflow_port: 6343
-#          sflow_api_port: 33333
+    service_sflow:
+      type: tosca.nodes.SFlowService
+      requirements:
+      properties:
+          view_url: /admin/ceilometer/sflowservice/$id$/
+          kind: sflow
+          sflow_port: 6343
+          sflow_api_port: 33333
 
     Private:
       type: tosca.nodes.NetworkTemplate
-
-    ceilometer_network:
-      type: tosca.nodes.network.Network.XOS
-      properties:
-          ip_version: 4
-          labels: ceilometer_client_access
-      requirements:
-          - network_template:
-              node: Private
-              relationship: tosca.relationships.UsesNetworkTemplate
-          - owner:
-              node: mysite_ceilometer
-              relationship: tosca.relationships.MemberOfSlice
-          - connection:
-              node: mysite_ceilometer
-              relationship: tosca.relationships.ConnectsToSlice
+#
+#    ceilometer_network:
+#      type: tosca.nodes.network.Network.XOS
+#      properties:
+#          ip_version: 4
+#          labels: ceilometer_client_access
+#      requirements:
+#          - network_template:
+#              node: Private
+#              relationship: tosca.relationships.UsesNetworkTemplate
+#          - owner:
+#              node: mysite_ceilometer
+#              relationship: tosca.relationships.MemberOfSlice
+#          - connection:
+#              node: mysite_ceilometer
+#              relationship: tosca.relationships.ConnectsToSlice
 
     mysite:
       type: tosca.nodes.Site
@@ -186,19 +186,24 @@
       properties:
           max_instances: 2
 
-#    mysite_sflow:
-#      description: Slice for sFlow service
-#      type: tosca.nodes.Slice
-#      requirements:
-#          - sflow_service:
-#              node: service_sflow
-#              relationship: tosca.relationships.MemberOfService
-#          - site:
-#              node: mysite
-#              relationship: tosca.relationships.MemberOfSite
-#      properties:
-#          default_flavor: m1.small
-#          max_instances: 2
+    mysite_sflow:
+      description: Slice for sFlow service
+      type: tosca.nodes.Slice
+      requirements:
+          - sflow_service:
+              node: service_sflow
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+          - default_image:
+                node: trusty-server-multi-nic
+                relationship: tosca.relationships.DefaultImage
+          - m1.small:
+                node: m1.small
+                relationship: tosca.relationships.DefaultFlavor
+      properties:
+          max_instances: 2
 
     my_ceilometer_tenant:
       description: Ceilometer Service default Tenant
@@ -209,27 +214,27 @@
               relationship: tosca.relationships.MemberOfService
        
     # Virtual machines
-#    sflow_service_instance:
-#      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_sflow
-#                relationship: tosca.relationships.MemberOfSlice
+    sflow_service_instance:
+      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_sflow
+                relationship: tosca.relationships.MemberOfSlice
 
     Ceilometer:
       type: tosca.nodes.DashboardView
diff --git a/xos/configurations/acord/ceilometer_pub_sub.tar.gz b/xos/configurations/acord/ceilometer_pub_sub.tar.gz
deleted file mode 100644
index eb88a2b..0000000
--- a/xos/configurations/acord/ceilometer_pub_sub.tar.gz
+++ /dev/null
Binary files differ
diff --git a/xos/configurations/acord/docker-compose.yml b/xos/configurations/acord/docker-compose.yml
index f40761a..da9562e 100644
--- a/xos/configurations/acord/docker-compose.yml
+++ b/xos/configurations/acord/docker-compose.yml
@@ -31,6 +31,19 @@
     volumes:
         - ../setup/id_rsa:/opt/xos/synchronizers/monitoring_channel/monitoring_channel_private_key:ro  # private key
 
+#Ensure exampleservice is enabled in xos/tools/xos-manage and xos/settings.py file before uncommenting below lines
+#xos_synchronizer_exampleservice:
+#    image: xosproject/xos-synchronizer-openstack
+#    command: bash -c "sleep 120; python /opt/xos/synchronizers/exampleservice/exampleservice-synchronizer.py -C /opt/xos/synchronizers/exampleservice/exampleservice_config"
+#    labels:
+#        org.xosproject.kind: synchronizer
+#        org.xosproject.target: exampleservice
+#    links:
+#        - xos_db
+#    volumes:
+#        - ../setup:/root/setup:ro
+#        - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
+#        - ../setup/id_rsa:/opt/xos/synchronizers/exampleservice/exampleservice_private_key:ro
 
 # FUTURE
 #xos_swarm_synchronizer:
@@ -51,3 +64,4 @@
       - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
       - ./xos_cord_config:/opt/xos/xos_configuration/xos_cord_config:ro
       - ../setup/id_rsa.pub:/opt/xos/synchronizers/monitoring_channel/monitoring_channel_public_key:ro
+#      - ../setup/id_rsa.pub:/opt/xos/synchronizers/exampleservice/exampleservice_public_key:ro
diff --git a/xos/configurations/acord/install_ceilometer_patch.sh b/xos/configurations/acord/install_ceilometer_patch.sh
deleted file mode 100755
index 77aa05b..0000000
--- a/xos/configurations/acord/install_ceilometer_patch.sh
+++ /dev/null
@@ -1,26 +0,0 @@
-if [ -d /usr/lib/python2.7/dist-packages/ceilometer/network/ext_services ]; then
-    echo "Seems VCPE notification listeners are already enabled in ceilometer... so exiting gracefully..."
-    exit 0
-fi
-echo "Verifying if all the required files are present"
-if [ ! -f openstack_ceilometer_patch.tar.gz ] || [ ! -f ceilometer_pub_sub.tar.gz ];
-then
-    echo "File openstack_ceilometer_patch.tar.gz or ceilometer_pub_sub.tar.gz not found"
-    exit 1
-fi
-echo "Copying the ceilometer patch files to /usr/lib/python2.7/dist-packages/ceilometer"
-tar -xzf openstack_ceilometer_patch.tar.gz
-sudo mv ceilometer/network/ext_services /usr/lib/python2.7/dist-packages/ceilometer/network/
-sudo mv ceilometer/network/statistics/onos /usr/lib/python2.7/dist-packages/ceilometer/network/statistics/
-sudo mv /usr/lib/python2.7/dist-packages/ceilometer/network/statistics/__init__.py /usr/lib/python2.7/dist-packages/ceilometer/network/statistics/orig_init.orig_py
-sudo mv ceilometer/network/statistics/__init__.py /usr/lib/python2.7/dist-packages/ceilometer/network/statistics/
-sudo mv ceilometer-2015.1.1.egg-info/entry_points.txt /usr/lib/python2.7/dist-packages/ceilometer-*egg-info/
-sudo mv pipeline.yaml /etc/ceilometer/
-echo "Restarting ceilometer-agent-notification"
-sudo service ceilometer-agent-notification restart
-echo "Restarting ceilometer-agent-central"
-sudo service ceilometer-agent-central restart
-tar -xzf ceilometer_pub_sub.tar.gz
-echo "Starting Ceilometer PUB/SUB service"
-cd ceilometer_pub_sub
-python sub_main.py &
diff --git a/xos/configurations/acord/openstack_ceilometer_patch.tar.gz b/xos/configurations/acord/openstack_ceilometer_patch.tar.gz
deleted file mode 100644
index 2c4f02c..0000000
--- a/xos/configurations/acord/openstack_ceilometer_patch.tar.gz
+++ /dev/null
Binary files differ
diff --git a/xos/configurations/common/fixtures.yaml b/xos/configurations/common/fixtures.yaml
index e28b03c..6b3234e 100644
--- a/xos/configurations/common/fixtures.yaml
+++ b/xos/configurations/common/fixtures.yaml
@@ -8,6 +8,10 @@
 topology_template:
   node_templates:
 
+    xos:
+      type: tosca.nodes.XOS
+
+
 # -----------------------------------------------------------------------------
 # Network Parameter Types
 # -----------------------------------------------------------------------------
diff --git a/xos/configurations/common/mydeployment.yaml b/xos/configurations/common/mydeployment.yaml
index 66bb75d..c81fd93 100644
--- a/xos/configurations/common/mydeployment.yaml
+++ b/xos/configurations/common/mydeployment.yaml
@@ -16,9 +16,15 @@
     m1.small:
       type: tosca.nodes.Flavor
 
+    m1.xlarge:
+      type: tosca.nodes.Flavor
+
     MyDeployment:
       type: tosca.nodes.Deployment
       requirements:
+          - m1.xlarge:
+             node: m1.large
+             relationship: tosca.relationships.SupportsFlavor
           - m1.large:
              node: m1.large
              relationship: tosca.relationships.SupportsFlavor
diff --git a/xos/configurations/common/wait_for_onboarding_ready.sh b/xos/configurations/common/wait_for_onboarding_ready.sh
new file mode 100755
index 0000000..9606dbb
--- /dev/null
+++ b/xos/configurations/common/wait_for_onboarding_ready.sh
@@ -0,0 +1,27 @@
+#! /bin/bash
+
+display_usage() { 
+    echo -e "\nUsage:\n$0 [xos-listen-port] [name] \n" 
+} 
+
+if [  $# -lt 2 ] 
+then 
+    display_usage
+    exit 1
+fi 
+
+echo "Waiting for $2 to be onboarded"
+while [[ 1 ]]; do
+    STATUS=`curl 0.0.0.0:$1/api/utility/onboarding/$2/ready/ 2> /dev/null`
+    if [[ "$STATUS" == "true" ]]; then
+        echo "$2 is onboarded"
+        exit 0
+    fi
+    sleep 1
+#    RUNNING_CONTAINER=`sudo docker ps|grep "xos"|awk '{print $$NF}'`
+#    if [[ $RUNNING_CONTAINER == "" ]]; then
+#        echo Container may have failed. check with \"make showlogs\'
+#        exit 1
+#    fi
+done
+
diff --git a/xos/configurations/common/wait_for_xos_file.sh b/xos/configurations/common/wait_for_xos_file.sh
new file mode 100755
index 0000000..1214dc4
--- /dev/null
+++ b/xos/configurations/common/wait_for_xos_file.sh
@@ -0,0 +1,24 @@
+#! /bin/bash
+
+display_usage() { 
+    echo -e "\nUsage:\n$0 [fn] \n" 
+} 
+
+if [  $# -lt 1 ] 
+then 
+    display_usage
+    exit 1
+fi 
+
+echo "Waiting for XOS to create file $1"
+
+until find $1 &> /dev/null
+do
+    sleep 1
+    RUNNING_CONTAINER=`sudo docker ps|grep "xos"|awk '{print $$NF}'`
+    if [[ $RUNNING_CONTAINER == "" ]]; then
+        echo Container may have failed. check with \"make showlogs\'
+        exit 1
+    fi
+done
+echo "XOS is ready"
diff --git a/xos/configurations/common/wait_for_xos_port.sh b/xos/configurations/common/wait_for_xos_port.sh
index 3ed5833..9c9e041 100755
--- a/xos/configurations/common/wait_for_xos_port.sh
+++ b/xos/configurations/common/wait_for_xos_port.sh
@@ -10,7 +10,7 @@
     exit 1
 fi 
 
-echo "Waiting for XOS to come up"
+echo "Waiting for XOS to start listening on port $1"
 until curl 0.0.0.0:$1 &> /dev/null
 do
     sleep 1
diff --git a/xos/configurations/cord-pod/Makefile b/xos/configurations/cord-pod/Makefile
index 8835964..1f8d3ae 100644
--- a/xos/configurations/cord-pod/Makefile
+++ b/xos/configurations/cord-pod/Makefile
@@ -1,3 +1,4 @@
+<<<<<<< HEAD
 .PHONY: xos
 xos: up bootstrap
 
@@ -5,24 +6,50 @@
 	touch id_rsa id_rsa.pub
 	sudo docker-compose up -d
 	../common/wait_for_xos_port.sh 80
+=======
+CONFIG_DIR:=$(shell pwd)
+DOCKER_COMPOSE_YML=./onboarding-docker-compose/docker-compose.yml
+BOOTSTRAP_YML=./docker-compose-bootstrap.yml
+DOCKER_PROJECT=cordpod
+>>>>>>> master
 
-bootstrap: nodes.yaml images.yaml
-	sudo docker-compose run xos python /opt/xos/tosca/run.py none /opt/xos/configurations/common/fixtures.yaml
-	sudo docker-compose run xos python /opt/xos/tosca/run.py none /opt/xos/configurations/common/mydeployment.yaml
-	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
+.PHONY: xos
+xos: prereqs bootstrap onboarding podconfig
+
+prereqs:
+	sudo make -f ../common/Makefile.prereqs
+
+bootstrap:
+	echo "[BOOTSTRAP]"
+	sudo rm -f onboarding-docker-compose/docker-compose.yml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f docker-compose-bootstrap.yml up -d
+	bash ../common/wait_for_xos_port.sh 81
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run -e CONFIG_DIR=$(CONFIG_DIR) xos_bootstrap_ui python /opt/xos/tosca/run.py none /opt/xos/configurations/cord-pod/xos.yaml
+
+onboarding:
+	echo "[ONBOARDING]"
+	# on-board any services here
+	bash ../common/wait_for_onboarding_ready.sh 81 xos
+	bash ../common/wait_for_xos_port.sh 80
+
+podconfig: nodes.yaml images.yaml
+	echo "[PODCONFIG]"
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py none /opt/xos/configurations/common/fixtures.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py none /opt/xos/configurations/common/mydeployment.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/setup.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/nodes.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/images.yaml
 
 vtn: vtn-external.yaml
-	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/vtn-external.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/vtn-external.yaml
 
 fabric: fabric.yaml
-	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/fabric.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/fabric.yaml
 
-cord: # vsg_custom_images
-	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 /root/setup/cord-vtn-vsg.yaml
-	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/cord-volt-devices.yaml
+cord: vsg_custom_images
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/mgmt-net.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/cord-vtn-vsg.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/cord-volt-devices.yaml
 
 exampleservice:
 	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/pod-exampleservice.yaml
@@ -49,10 +76,12 @@
 	export SETUPDIR=.; bash ./make-vtn-networkconfig-json.sh
 
 stop:
-	sudo MYIP=$(MYIP) docker-compose stop
+	test ! -s $(DOCKER_COMPOSE_YML) || sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) stop
+	sudo docker-compose -f $(BOOTSTRAP_YML) stop
 
 rm:
-	sudo MYIP=$(MYIP) docker-compose rm
+	test ! -s $(DOCKER_COMPOSE_YML) || sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) rm
+	sudo docker-compose -f $(BOOTSTRAP_YML) rm
 
 showlogs:
 	sudo MYIP=$(MYIP) docker-compose logs
@@ -80,10 +109,14 @@
 .PHONY: local_containers
 local_containers:
 	echo "" > ../../../containers/xos/local_certs.crt
-	for CRT in /usr/local/share/ca-certificates/* ; do \
+	for CRT in $$(ls /usr/local/share/ca-certificates/*) ; do \
 		echo Adding Certificate: $$CRT ;\
 		cat $$CRT >> ../../../containers/xos/local_certs.crt ;\
 		echo "" >> ../../../containers/xos/local_certs.crt ;\
 	done
 	cd ../../../containers/xos; make devel
 	cd ../../../containers/synchronizer; make
+<<<<<<< HEAD
+=======
+	cd ../../../containers/onboarding_synchronizer; make
+>>>>>>> master
diff --git a/xos/configurations/cord-pod/ceilometer.yaml b/xos/configurations/cord-pod/ceilometer.yaml
index d07f2e9..07b163e 100644
--- a/xos/configurations/cord-pod/ceilometer.yaml
+++ b/xos/configurations/cord-pod/ceilometer.yaml
@@ -124,6 +124,7 @@
           kind: ceilometer
           ceilometer_pub_sub_url: http://10.11.10.1:4455/
           public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
+          private_key_fn: /opt/xos/synchronizers/monitoring_channel/monitoring_channel_private_key
       artifacts:
           pubkey: /opt/xos/synchronizers/monitoring_channel/monitoring_channel_public_key
 
diff --git a/xos/configurations/cord-pod/docker-compose.yml b/xos/configurations/cord-pod/docker-compose-bootstrap.yml
similarity index 82%
rename from xos/configurations/cord-pod/docker-compose.yml
rename to xos/configurations/cord-pod/docker-compose-bootstrap.yml
index b9006b0..9f17c42 100644
--- a/xos/configurations/cord-pod/docker-compose.yml
+++ b/xos/configurations/cord-pod/docker-compose-bootstrap.yml
@@ -3,6 +3,24 @@
     expose:
         - "5432"
 
+xos_synchronizer_onboarding:
+    image: xosproject/xos-synchronizer-onboarding
+    command: bash -c "cd /opt/xos/synchronizers/onboarding; ./run.sh"
+    #command: sleep 86400
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: onboarding
+    links:
+        - xos_db
+    volumes:
+        - /var/run/docker.sock:/var/run/docker.sock
+        - ./key_import:/opt/xos/key_import:ro
+        - ./onboarding-docker-compose:/opt/xos/synchronizers/onboarding/docker-compose
+    log_driver: "json-file"
+    log_opt:
+            max-size: "100k"
+            max-file: "5"
+
 xos_synchronizer_openstack:
     command: bash -c "sleep 120; python /opt/xos/synchronizers/openstack/xos-synchronizer.py"
     image: xosproject/xos-synchronizer-openstack
@@ -116,21 +134,21 @@
             max-size: "100k"
             max-file: "5"
 
-xos:
-    command: python /opt/xos/manage.py runserver 0.0.0.0:80 --insecure --makemigrations
+xos_bootstrap_ui:
+    command: python /opt/xos/manage.py runserver 0.0.0.0:81 --insecure --makemigrations
     image: xosproject/xos
     links:
         - xos_db
     ports:
-        - "80:80"
+        - "81:81"
     volumes:
-        - .:/root/setup:ro
+#        - .:/root/setup:ro
         - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
         - ./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
-        - ./id_rsa.pub:/opt/xos/synchronizers/monitoring_channel/monitoring_channel_public_key:ro
+#        - ./id_rsa.pub:/opt/xos/synchronizers/onos/onos_key.pub:ro
+#        - ./id_rsa.pub:/opt/xos/synchronizers/vcpe/vcpe_public_key:ro
+#        - ./id_rsa.pub:/opt/xos/synchronizers/monitoring_channel/monitoring_channel_public_key:ro
     log_driver: "json-file"
     log_opt:
             max-size: "100k"
diff --git a/xos/configurations/cord-pod/pod-cdn.yaml b/xos/configurations/cord-pod/pod-cdn.yaml
new file mode 100644
index 0000000..2229686
--- /dev/null
+++ b/xos/configurations/cord-pod/pod-cdn.yaml
@@ -0,0 +1,52 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Setup the CDN on the pod
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+
+    Private:
+      type: tosca.nodes.NetworkTemplate
+
+    management:
+      type: tosca.nodes.network.Network.XOS
+      properties:
+          no-create: true
+          no-delete: true
+          no-update: true
+
+    cdn-public:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
+          cidr: 207.141.192.128/28
+      requirements:
+          - network_template:
+              node: Private
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - owner:
+              node: mysite_cdn
+              relationship: tosca.relationships.MemberOfSlice
+          - connection:
+              node: mysite_cdn
+              relationship: tosca.relationships.ConnectsToSlice
+
+    mysite:
+      type: tosca.nodes.Site
+
+    mysite_cdn:
+      description: This slice holds the CDN
+      type: tosca.nodes.Slice
+      properties:
+          network: noauto
+      requirements:
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+          - management:
+              node: management
+              relationship: tosca.relationships.ConnectsToNetwork
+
diff --git a/xos/configurations/cord-pod/pod-exampleservice.yaml b/xos/configurations/cord-pod/pod-exampleservice.yaml
index 677e889..0182a59 100644
--- a/xos/configurations/cord-pod/pod-exampleservice.yaml
+++ b/xos/configurations/cord-pod/pod-exampleservice.yaml
@@ -79,10 +79,10 @@
           view_url: /admin/exampleservice/exampleservice/$id$/
           kind: exampleservice
           public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }
-          private_key_fn: /opt/xos/synchronizers/exampleservice/exampleservice_private_key
+          private_key_fn: /opt/xos/services/exampleservice/keys/exampleservice_rsa
           service_message: hello
       artifacts:
-          pubkey: /opt/xos/synchronizers/exampleservice/exampleservice_public_key
+          pubkey: /opt/xos/services/exampleservice/keys/exampleservice_rsa.pub
 
     tenant#exampletenant1:
         type: tosca.nodes.ExampleTenant
diff --git a/xos/configurations/cord-pod/xos.yaml b/xos/configurations/cord-pod/xos.yaml
new file mode 100644
index 0000000..06b5eb5
--- /dev/null
+++ b/xos/configurations/cord-pod/xos.yaml
@@ -0,0 +1,85 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Onboard the exampleservice
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    xos:
+      type: tosca.nodes.XOS
+      properties:
+        ui_port: 80
+        bootstrap_ui_port: 81
+        docker_project_name: cordpod
+
+    /opt/xos/xos_configuration/xos_common_config:
+      type: tosca.nodes.XOSVolume
+      properties:
+          host_path: { path_join: [ SELF, CONFIG_DIR, ../common/xos_common_config, ENV_VAR ] }
+          read_only: true
+      requirements:
+          - xos:
+             node: xos
+             relationship: tosca.relationships.UsedByXOS
+
+    /opt/xos/xos_configuration/xos_cord_config:
+      type: tosca.nodes.XOSVolume
+      properties:
+          host_path: { path_join: [ SELF, CONFIG_DIR, xos_cord_config, ENV_VAR ] }
+          read_only: true
+      requirements:
+          - xos:
+             node: xos
+             relationship: tosca.relationships.UsedByXOS
+
+    /opt/xos/xos_configuration/xos_vtn_config:
+      type: tosca.nodes.XOSVolume
+      properties:
+          host_path: { path_join: [ SELF, CONFIG_DIR, ../vtn/files/xos_vtn_config, ENV_VAR ] }
+          read_only: true
+      requirements:
+          - xos:
+              node: xos
+              relationship: tosca.relationships.UsedByXOS
+
+    /root/setup:
+      type: tosca.nodes.XOSVolume
+      properties:
+          host_path: { path_join: [ SELF, CONFIG_DIR, ., ENV_VAR ] }
+          read_only: true
+      requirements:
+          - xos:
+             node: xos
+             relationship: tosca.relationships.UsedByXOS
+
+    /opt/xos/synchronizers/onos/onos_key.pub:
+      type: tosca.nodes.XOSVolume
+      properties:
+          host_path: { path_join: [ SELF, CONFIG_DIR, id_rsa.pub, ENV_VAR ] }
+          read_only: true
+      requirements:
+          - xos:
+             node: xos
+             relationship: tosca.relationships.UsedByXOS
+
+    /opt/xos/synchronizers/vcpe/vcpe_public_key:
+      type: tosca.nodes.XOSVolume
+      properties:
+          host_path: { path_join: [ SELF, CONFIG_DIR, id_rsa.pub, ENV_VAR ] }                                                      
+          read_only: true
+      requirements:
+          - xos:
+             node: xos
+             relationship: tosca.relationships.UsedByXOS
+
+    /opt/xos/synchronizers/monitoring_channel/monitoring_channel_public_key:
+      type: tosca.nodes.XOSVolume
+      properties:
+          host_path: { path_join: [ SELF, CONFIG_DIR, id_rsa.pub, ENV_VAR ] }                                                      
+          read_only: true
+      requirements:
+          - xos:
+             node: xos
+             relationship: tosca.relationships.UsedByXOS
diff --git a/xos/configurations/devel/Makefile b/xos/configurations/devel/Makefile
index cc29f53..524e4cd 100644
--- a/xos/configurations/devel/Makefile
+++ b/xos/configurations/devel/Makefile
@@ -1,8 +1,8 @@
 MYIP:=$(shell hostname -i)
 
-cloudlab: common_cloudlab containers xos
+cloudlab: common_cloudlab local_containers xos
 
-devstack: upgrade_pkgs common_devstack containers xos
+devstack: upgrade_pkgs common_devstack local_containers xos
 
 xos:
 	sudo MYIP=$(MYIP) docker-compose up -d
@@ -12,16 +12,25 @@
 	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/common/cloudlab-openstack.yaml
 	sudo MYIP=$(MYIP) docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/nodes.yaml
 
-containers:
-	cd ../../../containers/xos; make devel
-	cd ../../../containers/synchronizer; make
-
 common_cloudlab:
 	make -C ../common -f Makefile.cloudlab
 
 common_devstack:
 	make -C ../common -f Makefile.devstack
 
+base:
+	make -C ../../../containers/xos base
+
+local_containers:
+	echo "" > ../../../containers/xos/local_certs.crt
+	for CRT in $$(ls /usr/local/share/ca-certificates/*) ; do \
+		echo Adding Certificate: $$CRT ;\
+		cat $$CRT >> ../../../containers/xos/local_certs.crt ;\
+		echo "" >> ../../../containers/xos/local_certs.crt ;\
+	done
+	make -C ../../../containers/xos devel
+	make -C ../../../containers/synchronizer
+
 stop:
 	sudo MYIP=$(MYIP) docker-compose stop
 
@@ -43,8 +52,3 @@
 upgrade_pkgs:
 	sudo pip install httpie --upgrade
 
-rebuild_xos:
-	make -C ../../../containers/xos devel
-
-rebuild_synchronizer:
-	make -C ../../../containers/synchronizer
diff --git a/xos/configurations/frontend/Makefile b/xos/configurations/frontend/Makefile
index 562578e..46f39bf 100644
--- a/xos/configurations/frontend/Makefile
+++ b/xos/configurations/frontend/Makefile
@@ -1,24 +1,41 @@
 MYIP:=$(shell hostname -i)
+CONFIG_DIR:=$(shell pwd)
+DOCKER_COMPOSE_YML=./onboarding-docker-compose/docker-compose.yml
+BOOTSTRAP_YML=./docker-compose-bootstrap.yml
+DOCKER_PROJECT=frontend
 
-frontend:
+frontend: prereqs bootstrap
+	bash ../common/wait_for_xos_port.sh 9999
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py none /opt/xos/configurations/common/fixtures.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py none /opt/xos/configurations/common/mydeployment.yaml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/frontend/sample.yaml
+
+prereqs:
 	sudo make -f ../common/Makefile.prereqs
-	sudo docker-compose up -d
-	bash ../common/wait_for_xos.sh
-	sudo docker-compose run xos python /opt/xos/tosca/run.py none /opt/xos/configurations/common/fixtures.yaml
-	sudo docker-compose run xos python /opt/xos/tosca/run.py none /opt/xos/configurations/common/mydeployment.yaml
-	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/frontend/sample.yaml
+
+bootstrap:
+	sudo rm -f onboarding-docker-compose/docker-compose.yml
+	sudo rm -f docker-compose.yml
+	sudo docker-compose -p $(DOCKER_PROJECT) -f docker-compose-bootstrap.yml up -d
+	bash ../common/wait_for_xos_port.sh 9998
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) run -e CONFIG_DIR=$(CONFIG_DIR) xos_bootstrap_ui python /opt/xos/tosca/run.py none /opt/xos/configurations/frontend/xos.yaml
 
 containers:
 	cd ../../../containers/xos; make devel
+	cd ../../../containers/synchronizer; make
+	cd ../../../containers/onboarding_synchronizer; make
+	#cd ../../../containers/xos; make devel
 
 stop:
-	sudo docker-compose stop
+	test ! -s $(DOCKER_COMPOSE_YML) || sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) stop
+	sudo docker-compose -f $(BOOTSTRAP_YML) stop
 
 showlogs:
 	sudo docker-compose logs
 
 rm: stop
-	sudo docker-compose rm
+	test ! -s $(DOCKER_COMPOSE_YML) || sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) rm
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(BOOTSTRAP_YML) rm
 
 ps:
 	sudo docker-compose ps
@@ -36,7 +53,7 @@
 mock-cord-pod:
 	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/cord-pod/mgmt-net.yaml
-	sudo docker-compose run xos bash -c "echo somekey > /opt/xos/synchronizers/vcpe/vcpe_public_key; python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/cord-pod/cord-vtn-vsg.yaml"
+	#sudo docker-compose run xos bash -c "echo somekey > /opt/xos/synchronizers/vcpe/vcpe_public_key; python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/cord-pod/cord-vtn-vsg.yaml"
 	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/cord-pod/cord-volt-devices.yaml
 	sudo docker exec frontend_xos_1 cp /opt/xos/configurations/cord-pod/xos_cord_config /opt/xos/xos_configuration/
 	sudo docker exec frontend_xos_1 touch /opt/xos/xos/settings.py
@@ -50,3 +67,11 @@
 	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/frontend/mocks/mcord.yaml
 	sudo docker exec frontend_xos_1 cp /opt/xos/configurations/mcord/xos_mcord_config /opt/xos/xos_configuration/
 	sudo docker exec frontend_xos_1 touch /opt/xos/xos/settings.py
+
+exampleservice:
+	mkdir -p key_import
+	# fake keys are fine
+	sudo bash -c "echo somekey > key_import/exampleservice_rsa"
+	sudo bash -c "echo somekey > key_import/exampleservice_rsa.pub"
+	sudo docker-compose -p $(DOCKER_PROJECT) -f $(DOCKER_COMPOSE_YML) run xos_ui python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/onboard/exampleservice/exampleservice-onboard.yaml
+	bash ../common/wait_for_onboarding_ready.sh 9998 xos
diff --git a/xos/configurations/frontend/docker-compose-bootstrap.yml b/xos/configurations/frontend/docker-compose-bootstrap.yml
new file mode 100644
index 0000000..3975893
--- /dev/null
+++ b/xos/configurations/frontend/docker-compose-bootstrap.yml
@@ -0,0 +1,34 @@
+xos_db:
+    image: xosproject/xos-postgres
+    expose:
+        - "5432"
+
+xos_bootstrap_ui:
+    image: xosproject/xos
+    command: python /opt/xos/manage.py runserver 0.0.0.0:9998 --insecure --makemigrations
+    ports:
+        - "9998:9998"
+    links:
+        - xos_db
+    volumes:
+      - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config
+      - ../vtn/files/xos_vtn_config:/opt/xos/xos_configuration/xos_vtn_config:ro
+
+xos_synchronizer_onboarding:
+    image: xosproject/xos-synchronizer-onboarding
+    command: bash -c "cd /opt/xos/synchronizers/onboarding; ./run.sh"
+    #command: sleep 86400
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: onboarding
+    links:
+        - xos_db
+    volumes:
+#        - .:/root/setup:ro
+        - /var/run/docker.sock:/var/run/docker.sock
+        - ./key_import:/opt/xos/key_import:ro
+        - ./onboarding-docker-compose:/opt/xos/synchronizers/onboarding/docker-compose
+    log_driver: "json-file"
+    log_opt:
+            max-size: "100k"
+            max-file: "5"
diff --git a/xos/configurations/frontend/docker-compose.yml b/xos/configurations/frontend/docker-compose.yml
deleted file mode 100644
index 835eb83..0000000
--- a/xos/configurations/frontend/docker-compose.yml
+++ /dev/null
@@ -1,34 +0,0 @@
-xos_db:
-    image: xosproject/xos-postgres
-    expose:
-        - "5432"
-
-# FUTURE
-#xos_swarm_synchronizer:
-#    image: xosproject/xos-swarm-synchronizer
-#    labels:
-#        org.xosproject.kind: synchronizer
-#        org.xosproject.target: swarm
-
-xos:
-    image: xosproject/xos
-    command: python /opt/xos/manage.py runserver 0.0.0.0:8000 --insecure --makemigrations
-    #command: sleep 86400    # For interactive session
-    ports:
-        - "9999:8000"
-    links:
-        - xos_db
-    volumes:
-      - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config
-      - ../../tosca:/opt/xos/tosca
-      - ../../core/xoslib:/opt/xos/core/xoslib
-      - ../../core/static:/opt/xos/core/static
-      - ../../core/dashboard:/opt/xos/core/dashboard
-      - ../../core/templatetags:/opt/xos/core/templatetags
-      - ../../core/views:/opt/xos/core/views
-      - ../../templates:/opt/xos/templates
-      - ../../configurations:/opt/xos/configurations
-      - ../../xos:/opt/xos/xos
-      - ../../api:/opt/xos/api
-      - ../../services:/opt/xos/services
-
diff --git a/xos/configurations/frontend/xos.yaml b/xos/configurations/frontend/xos.yaml
new file mode 100644
index 0000000..8b286cd
--- /dev/null
+++ b/xos/configurations/frontend/xos.yaml
@@ -0,0 +1,35 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Onboard the exampleservice
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    xos:
+      type: tosca.nodes.XOS
+      properties:
+        ui_port: 9999
+        bootstrap_ui_port: 9998
+        docker_project_name: frontend
+
+    /opt/xos/xos_configuration/xos_common_config:
+      type: tosca.nodes.XOSVolume
+      properties:
+          host_path: { path_join: [ SELF, CONFIG_DIR, ../common/xos_common_config, ENV_VAR ] }
+          read_only: false
+      requirements:
+          - xos:
+             node: xos
+             relationship: tosca.relationships.UsedByXOS
+
+    /opt/xos/xos_configuration/xos_vtn_config:
+      type: tosca.nodes.XOSVolume
+      properties:
+          host_path: { path_join: [ SELF, CONFIG_DIR, ../vtn/files/xos_vtn_config, ENV_VAR ] }
+          read_only: true
+      requirements:
+          - xos:
+              node: xos
+              relationship: tosca.relationships.UsedByXOS
diff --git a/xos/configurations/mcord/Makefile b/xos/configurations/mcord/Makefile
index 7f4d9a5..53fec7b 100644
--- a/xos/configurations/mcord/Makefile
+++ b/xos/configurations/mcord/Makefile
@@ -31,6 +31,9 @@
 enter-vbbu:
 	sudo docker exec -it mcord_xos_synchronizer_vbbu_1 bash
 
+enter-vpgwc:
+	sudo docker exec -it mcord_xos_synchronizer_vpgwc_1 bash
+
 upgrade_pkgs:
 	sudo pip install httpie --upgrade
 
diff --git a/xos/configurations/mcord/docker-compose.yml b/xos/configurations/mcord/docker-compose.yml
index 8598396..367b168 100644
--- a/xos/configurations/mcord/docker-compose.yml
+++ b/xos/configurations/mcord/docker-compose.yml
@@ -40,6 +40,25 @@
         - "compute9:10.102.81.9"
         - "compute10:10.102.81.10"
 
+xos_synchronizer_vpgwc:
+    image: xosproject/xos-synchronizer-openstack
+    command: bash -c "sleep 120; python /opt/xos/synchronizers/vpgwc/vpgwc-synchronizer.py -C /opt/xos/synchronizers/vpgwc/vpgwc_config"
+    labels:
+        org.xosproject.kind: synchronizer
+        org.xosproject.target: vpgwc 
+    links:
+        - xos_db
+    volumes:
+        - ../setup/id_rsa_mcord:/opt/xos/configurations/mcord/mcord_private_key:ro  # private key
+        - ../setup/id_rsa_mcord.pub:/opt/xos/configurations/mcord/mcord_public_key:ro  # public key
+        - ../setup:/root/setup:ro
+    extra_hosts:
+        - "controller:10.102.81.3"
+        - "computeBBU1:10.102.81.6"
+        - "computeBBU2:10.102.81.7"
+        - "compute9:10.102.81.9"
+        - "compute10:10.102.81.10"
+
 # FUTURE
 #xos_swarm_synchronizer:
 #    image: xosproject/xos-swarm-synchronizer
diff --git a/xos/configurations/mcord/mcord.yaml b/xos/configurations/mcord/mcord.yaml
index 42241f0..450bd23 100644
--- a/xos/configurations/mcord/mcord.yaml
+++ b/xos/configurations/mcord/mcord.yaml
@@ -92,6 +92,25 @@
                 default: New vBBU Component 

                 description: Just a message 

                 

+    tosca.nodes.VPGWCComponent:

+        derived_from: tosca.nodes.Root

+        description: >

+            CORD: vPGWC Component of MCORD Service.

+        properties:

+            kind:

+                type: string

+                default: VPGWC_KIND

+                description: Kind of component

+            s5s8_pgw_tag:

+                type: string

+                required: false

+                default: 300

+                description: VTN stag port-name

+            display_message:

+                type: string

+                required: false

+                default: New vPGWc Component 

+                description: Just a message 

 

 topology_template:

   node_templates:

@@ -107,6 +126,18 @@
       artifacts:

           pubkey: /opt/xos/configurations/mcord/mcord_public_key

 

+    vPGWC:

+      type: tosca.nodes.MCORDService

+      requirements:

+      properties:

+          kind: vEPC

+          icon_url: /static/mCordServices/service_server.png

+          view_url: /admin/mcord/vpgwccomponent

+          public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }

+          private_key_fn: /opt/xos/configurations/mcord/mcord_private_key

+      artifacts:

+          pubkey: /opt/xos/configurations/mcord/mcord_public_key

+

     m1.xlarge:

       type: tosca.nodes.Flavor

 

@@ -189,12 +220,35 @@
               node: mysite_vbbu_slice1

               relationship: tosca.relationships.ConnectsToSlice

 

+    lan_3gpp_s5s8_pgw_network:

+      type: tosca.nodes.network.Network.XOS

+      properties:

+          ip_version: 4

+          labels: lan_3gpp_s5s8_pgw_net

+          cidr: 172.17.1.0/24

+          start_ip: 172.17.1.2

+          end_ip: 172.17.1.8

+          gateway_ip: 172.17.1.1

+      requirements:

+          - network_template:

+              node: External

+              relationship: tosca.relationships.UsesNetworkTemplate

+          - owner:

+              node: mysite_mobile_net

+              relationship: tosca.relationships.MemberOfSlice

+          - connection:

+              node: mysite_vpgwc_slice1

+              relationship: tosca.relationships.ConnectsToSlice

+

     mysite:

       type: tosca.nodes.Site

 

     mcord-bbu-multi-nic:

       type: tosca.nodes.Image

 

+    mcord-vpgwc-onos-multi-nic:

+      type: tosca.nodes.Image

+

     mysite_management:

       description: This slice exists solely to own the management network

       type: tosca.nodes.Slice

@@ -238,4 +292,41 @@
           network: noauto

 #          default_flavor: m1.xlarge

           default_node: computeBBU2 

-    

+

+    mysite_vpgwc_slice1:

+      description: vPGWC Service Slice 1

+      type: tosca.nodes.Slice

+      requirements:

+          - vPGWC:

+              node: vPGWC

+              relationship: tosca.relationships.MemberOfService

+          - site:

+              node: mysite

+              relationship: tosca.relationships.MemberOfSite

+          - default_image:

+                node: mcord-vpgwc-onos-multi-nic 

+                relationship: tosca.relationships.DefaultImage

+          - default_flavor:

+                node: m1.xlarge

+                relationship: tosca.relationships.DefaultFlavor

+          - management:

+              node: management

+              relationship: tosca.relationships.ConnectsToNetwork

+      properties:

+          network: noauto

+          default_node: compute10

+

+    mysite_VPGWC_Component:

+      description: MCORD Service default Component

+      type: tosca.nodes.VPGWCComponent

+      requirements:

+          - provider_service:

+              node: vPGWC

+              relationship: tosca.relationships.MemberOfService

+          - vpgwc_slice:

+              node: mysite_vpgwc_slice1

+              relationship: tosca.relationships.MemberOfSlice

+      properties:

+          display_message: vPGWC looks good!

+          s5s8_pgw_tag: 300

+

diff --git a/xos/configurations/mcord/migrations/0001_initial.py b/xos/configurations/mcord/migrations/0001_initial.py
index c53e548..a11fe30 100644
--- a/xos/configurations/mcord/migrations/0001_initial.py
+++ b/xos/configurations/mcord/migrations/0001_initial.py
@@ -31,4 +31,14 @@
             },
             bases=('core.tenantwithcontainer',),
         ),
+        migrations.CreateModel(
+            name='VPGWCComponent',
+            fields=[
+            ],
+            options={
+                'verbose_name': 'VPGWC MCORD Service Component',
+                'proxy': True,
+            },
+            bases=('core.tenantwithcontainer',),
+        ),
     ]
diff --git a/xos/configurations/mcord/nodes.yaml b/xos/configurations/mcord/nodes.yaml
index ae22112..48e7247 100644
--- a/xos/configurations/mcord/nodes.yaml
+++ b/xos/configurations/mcord/nodes.yaml
@@ -22,3 +22,23 @@
               node: MyDeployment
               relationship: tosca.relationships.MemberOfDeployment
 
+    nova-compute:
+      type: tosca.nodes.Node
+      requirements:
+        - site:
+            node: mysite
+            relationship: tosca.relationships.MemberOfSite
+        - deployment:
+            node: MyDeployment
+            relationship: tosca.relationships.MemberOfDeployment
+
+    compute10:
+        type: tosca.nodes.Node
+        requirements:
+          - site:
+              node: mysite 
+              relationship: tosca.relationships.MemberOfSite
+          - deployment:
+              node: MyDeployment
+              relationship: tosca.relationships.MemberOfDeployment
+
diff --git a/xos/configurations/mcord/setup.yaml b/xos/configurations/mcord/setup.yaml
index 0dd2769..9db865e 100644
--- a/xos/configurations/mcord/setup.yaml
+++ b/xos/configurations/mcord/setup.yaml
@@ -166,12 +166,6 @@
           icon_url: /static/mCordServices/service_server.png
           kind: vEPC
 
-    vPGW:
-      type: tosca.nodes.Service
-      properties:
-          view_url: /mcord/?service=vPGW
-          icon_url: /static/mCordServices/service_server.png
-          kind: vEPC
 
     # EDGE
     Cache:
@@ -223,10 +217,10 @@
           icon_url: /static/mCordServices/service_server.png
           kind: vEPC
 
-    vPGW:
+    vPGWC:
       type: tosca.nodes.Service
       properties:
-          view_url: /mcord/?service=vPGW
+          view_url: /mcord/?service=vPGWC
           icon_url: /static/mCordServices/service_server.png
           kind: vEPC
 
diff --git a/xos/configurations/mcord/vpgwc.yaml b/xos/configurations/mcord/vpgwc.yaml
new file mode 100644
index 0000000..d003bb2
--- /dev/null
+++ b/xos/configurations/mcord/vpgwc.yaml
@@ -0,0 +1,203 @@
+tosca_definitions_version: tosca_simple_yaml_1_0

+

+description: Setup MCORD-related services.

+

+imports:

+   - custom_types/xos.yaml

+

+node_types:

+

+    tosca.nodes.MCORDService:

+        derived_from: tosca.nodes.Root

+        description: >

+            An XOS Service object. Services may be listed in the Service

+            directory and may be linked together via Tenancy Relationships.

+        capabilities:

+            scalable:

+                type: tosca.capabilities.Scalable

+            service:

+                type: tosca.capabilities.xos.Service

+        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

+            kind:

+                type: string

+                default: VPGWC_KIND

+                description: Type of service.

+            view_url:

+                type: string

+                required: false

+                description: URL to follow when icon is clicked in the Service Directory.

+            icon_url:

+                type: string

+                required: false

+                description: ICON to display in the Service Directory.

+            enabled:

+                type: boolean

+                default: true

+            published:

+                type: boolean

+                default: true

+                description: If True then display this Service in the Service Directory.

+            public_key:

+                type: string

+                required: false

+                description: Public key to install into Instances to allows Services to SSH into them.

+            private_key_fn:

+                type: string

+                required: false

+                description: Location of private key file

+            versionNumber:

+                type: string

+                required: false

+                description: Version number of Service.

+

+    tosca.nodes.VPGWCComponent:

+        derived_from: tosca.nodes.Root

+        description: >

+            CORD: vPGWC Component of MCORD Service.

+        properties:

+            kind:

+                type: string

+                default: VPGWC_KIND 

+                description: Kind of component

+            s5s8_pgw_tag:

+                type: string

+                required: false

+                default: 300

+                description: VTN stag port-name

+            display_message:

+                type: string

+                required: false

+                default: New vPGWC Component 

+                description: Just a message 

+                

+

+topology_template:

+  node_templates:

+    vPGWC:

+      type: tosca.nodes.MCORDService

+      requirements:

+      properties:

+          kind: VPGWC_KIND

+          icon_url: /static/mCordServices/service_server.png

+          view_url: /admin/mcord/vpgwccomponent

+          public_key: { get_artifact: [ SELF, pubkey, LOCAL_FILE] }

+          private_key_fn: /opt/xos/configurations/mcord/mcord_private_key

+      artifacts:

+          pubkey: /opt/xos/configurations/mcord/mcord_public_key

+

+    m1.xlarge:

+      type: tosca.nodes.Flavor

+

+    Private:

+      type: tosca.nodes.NetworkTemplate

+

+    External:

+      type: tosca.nodes.NetworkTemplate

+

+    management_template:

+      type: tosca.nodes.NetworkTemplate

+      properties:

+          visibility: private

+          translation: none

+

+    management:

+      type: tosca.nodes.network.Network.XOS

+#      properties:

+#          no-create: true

+#          no-delete: true

+#          no-update: true

+

+    lan_3gpp_s5s8_pgw_network:

+      type: tosca.nodes.network.Network.XOS

+      properties:

+          ip_version: 4

+          labels: lan_3gpp_s5s8_pgw_net

+          cidr: 172.17.1.0/24

+          start_ip: 172.17.1.2

+          end_ip: 172.17.1.8

+          gateway_ip: 172.17.1.1

+      requirements:

+          - network_template:

+              node: External

+              relationship: tosca.relationships.UsesNetworkTemplate

+          - owner:

+              node: mysite_mobile_net

+              relationship: tosca.relationships.MemberOfSlice

+          - connection:

+              node: mysite_vpgwc_slice1

+              relationship: tosca.relationships.ConnectsToSlice

+

+    mysite:

+      type: tosca.nodes.Site

+

+    mcord-vpgwc-onos-multi-nic:

+      type: tosca.nodes.Image

+

+    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

+

+    mysite_mobile_net:

+      description: This slice exists solely to own the mobile network

+      type: tosca.nodes.Slice

+      properties:

+          network: noauto

+      requirements:

+          - site:

+              node: mysite

+              relationship: tosca.relationships.MemberOfSite

+

+    mysite_vpgwc_slice1:

+      description: vPGWC Service Slice 1

+      type: tosca.nodes.Slice

+      requirements:

+          - vPGWC:

+              node: vPGWC

+              relationship: tosca.relationships.MemberOfService

+          - site:

+              node: mysite

+              relationship: tosca.relationships.MemberOfSite

+          - default_image:

+                node: mcord-vpgwc-onos-multi-nic 

+                relationship: tosca.relationships.DefaultImage

+          - default_flavor:

+                node: m1.xlarge

+                relationship: tosca.relationships.DefaultFlavor

+          - management:

+              node: management

+              relationship: tosca.relationships.ConnectsToNetwork

+      properties:

+          network: noauto

+          default_node: compute10 

+    

+    mysite_VPGWC_Component:

+      description: MCORD Service default Component

+      type: tosca.nodes.VPGWCComponent

+      requirements:

+          - provider_service:

+              node: vPGWC

+              relationship: tosca.relationships.MemberOfService

+          - vpgwc_slice:

+              node: mysite_vpgwc_slice1

+              relationship: tosca.relationships.MemberOfSlice

+      properties:

+          display_message: vPGWC looks good!

+          s5s8_pgw_tag: 300

diff --git a/xos/configurations/test-standalone/docker-compose.yml b/xos/configurations/test-standalone/docker-compose.yml
index 5039f08..a0b87ed 100644
--- a/xos/configurations/test-standalone/docker-compose.yml
+++ b/xos/configurations/test-standalone/docker-compose.yml
@@ -11,7 +11,7 @@
 #        org.xosproject.target: swarm
 
 xos:
-    image: xosproject/xos
+    image: xosproject/xos-test
     command: python /opt/xos/manage.py runserver 0.0.0.0:8000 --insecure --makemigrations
     #command: sleep 86400    # For interactive session
     ports:
diff --git a/xos/core/admin.py b/xos/core/admin.py
index 200bb5c..c5e36be 100644
--- a/xos/core/admin.py
+++ b/xos/core/admin.py
@@ -1034,7 +1034,7 @@
     list_display = ("backend_status_icon", "name", "kind",
                     "versionNumber", "enabled", "published")
     list_display_links = ('backend_status_icon', 'name', )
-    fieldList = ["backend_status_text", "name", "kind", "description", "versionNumber", "enabled", "published",
+    fieldList = ["backend_status_text", "name", "kind", "description", "controller", "versionNumber", "enabled", "published",
                  "view_url", "icon_url", "public_key", "private_key_fn", "service_specific_attribute", "service_specific_id"]
     fieldsets = [
         (None, {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
@@ -1051,6 +1051,27 @@
                       ('serviceprivileges', 'Privileges')
                       )
 
+class ServiceControllerResourceInline(XOSTabularInline):
+    model = ServiceControllerResource
+    fields = ['name', 'kind', 'format', 'url']
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-resources'
+
+class ServiceControllerAdmin(XOSBaseAdmin):
+    list_display = ("backend_status_icon", "name",)
+    list_display_links = ('backend_status_icon', 'name',)
+    fieldList = ["backend_status_text", "name", "xos", "base_url"]
+    fieldsets = [
+        (None, {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
+    inlines = [ServiceControllerResourceInline]
+    readonly_fields = ('backend_status_text', )
+
+    user_readonly_fields = fieldList
+
+    suit_form_tabs = (('general', 'Service Details'),
+                      ('resources', 'Resources'),
+                      )
+
 
 class SiteNodeInline(XOSTabularInline):
     model = Node
@@ -2416,6 +2437,7 @@
 admin.site.register(Site, SiteAdmin)
 admin.site.register(Slice, SliceAdmin)
 admin.site.register(Service, ServiceAdmin)
+admin.site.register(ServiceController, ServiceControllerAdmin)
 #admin.site.register(Reservation, ReservationAdmin)
 admin.site.register(Network, NetworkAdmin)
 admin.site.register(Port, PortAdmin)
diff --git a/xos/core/models/__init__.py b/xos/core/models/__init__.py
index 5b0ad4b..41e6b3b 100644
--- a/xos/core/models/__init__.py
+++ b/xos/core/models/__init__.py
@@ -1,8 +1,10 @@
 from .plcorebase import PlCoreBase,PlCoreBaseManager,PlCoreBaseDeletionManager,PlModelMixIn
 from .project import Project
 from .singletonmodel import SingletonModel
+from .xosmodel import XOS, XOSVolume
 from .service import Service, Tenant, TenantWithContainer, CoarseTenant, ServicePrivilege, TenantRoot, TenantRootPrivilege, TenantRootRole, TenantPrivilege, TenantRole, Subscriber, Provider
 from .service import ServiceAttribute, TenantAttribute, ServiceRole
+from .service import ServiceController, ServiceControllerResource
 from .tag import Tag
 from .role import Role
 from .site import Site, Deployment, DeploymentRole, DeploymentPrivilege, Controller, ControllerRole, ControllerSite, SiteDeployment,Diag
diff --git a/xos/core/models/service.py b/xos/core/models/service.py
index b341e83..c871c7e 100644
--- a/xos/core/models/service.py
+++ b/xos/core/models/service.py
@@ -1,13 +1,22 @@
 import json
 from operator import attrgetter
 
-from core.models import PlCoreBase, PlCoreBaseManager, SingletonModel
+from core.models import PlCoreBase, PlCoreBaseManager, SingletonModel, XOS
 from core.models.plcorebase import StrippedCharField
 from django.db import models
 from xos.exceptions import *
+import urlparse
 
 COARSE_KIND = "coarse"
 
+def get_xos():
+    xos = XOS.objects.all()
+
+    if xos:
+       return xos[0]
+    else:
+       return None
+

 
 class AttributeMixin(object):
     # helper for extracting things from a json-encoded
@@ -56,6 +65,55 @@
                                             None,
                                             attrname))
 
+class ServiceController(PlCoreBase):
+    xos = models.ForeignKey(XOS, related_name='service_controllers', help_text="Pointer to XOS", default=get_xos)
+    name = StrippedCharField(max_length=30, help_text="Service Name")
+    base_url = StrippedCharField(max_length=1024, help_text="Base URL, allows use of relative URLs for resources", null=True, blank=True)
+
+    def __unicode__(self): return u'%s' % (self.name)
+
+    def save(self, *args, **kwargs):
+       super(ServiceController, self).save(*args, **kwargs)
+
+       if self.xos:
+           # force XOS to rebuild
+           # XXX somewhat hackish XXX
+           self.xos.save(update_fields=["updated"])
+
+class ServiceControllerResource(PlCoreBase):
+    KIND_CHOICES = (('models', 'Models'),
+                    ('admin', 'Admin'),
+                    ('django_library', 'Django Library'),
+                    ('synchronizer', 'Synchronizer'),
+                    ('rest_service', 'REST API (service)'),
+                    ('rest_tenant', 'REST API (tenant)'),
+                    ('tosca_custom_types', 'Tosca Custom Types'),
+                    ('tosca_resource', 'Tosca Resource'),
+                    ('private_key', 'Private Key'),
+                    ('public_key', 'Public Key'))
+
+    FORMAT_CHOICES = (('python', 'Python'),
+                      ('manifest', 'Manifest'),
+                      ('docker', 'Docker Container'),
+                      ('yaml', 'YAML'),
+                      ('raw', 'raw'))
+
+    service_controller = models.ForeignKey(ServiceController, related_name='service_controller_resources',
+                                help_text="The Service Controller this resource is associated with")
+
+    name = StrippedCharField(max_length=30, help_text="Object Name")
+    kind = StrippedCharField(choices=KIND_CHOICES, max_length=30)
+    format = StrippedCharField(choices=FORMAT_CHOICES, max_length=30)
+    url = StrippedCharField(max_length=1024, help_text="URL of resource", null=True, blank=True)
+
+    def __unicode__(self): return u'%s' % (self.name)
+
+    @property
+    def full_url(self):
+        if self.service_controller and self.service_controller.base_url:
+            return urlparse.urljoin(self.service_controller.base_url, self.url)
+        else:
+            return self.url
 
 class Service(PlCoreBase, AttributeMixin):
     # when subclassing a service, redefine KIND to describe the new service
@@ -81,6 +139,10 @@
         max_length=30, blank=True, null=True)
     service_specific_attribute = models.TextField(blank=True, null=True)
 
+    controller = models.ForeignKey(ServiceController, related_name='services',
+                                help_text="The Service Controller this Service uses",
+                                null=True, blank=True)
+
     def __init__(self, *args, **kwargs):
         # for subclasses, set the default kind appropriately
         self._meta.get_field("kind").default = self.KIND
@@ -548,7 +610,7 @@
         if self.slice.default_image:
             return self.slice.default_image
 
-        raise XOPSProgrammingError("Please set a default image for %s" % self.slice.name)
+        raise XOSProgrammingError("Please set a default image for %s" % self.slice.name)
 
     def make_new_instance(self):
         from core.models import Instance, Flavor
@@ -683,7 +745,7 @@
         if slice.default_image:
             return slice.default_image
 
-        raise XOPSProgrammingError("Please set a default image for %s" % self.slice.name)
+        raise XOSProgrammingError("Please set a default image for %s" % self.slice.name)
 
     def save_instance(self, instance):
         # Override this function to do custom pre-save or post-save processing,
diff --git a/xos/core/models/xosmodel.py b/xos/core/models/xosmodel.py
new file mode 100644
index 0000000..4942241
--- /dev/null
+++ b/xos/core/models/xosmodel.py
@@ -0,0 +1,44 @@
+import os
+from django.db import models
+from core.models import PlCoreBase
+from core.models.plcorebase import StrippedCharField
+
+# XOS: Serves as the root of the build system
+
+
+
+class XOS(PlCoreBase):
+    name = StrippedCharField(max_length=200, unique=True, help_text="Name of XOS", default="XOS")
+    ui_port = models.IntegerField(help_text="Port for XOS UI", default=80)
+    bootstrap_ui_port = models.IntegerField(help_text="Port for XOS UI", default=81)
+    db_container_name = StrippedCharField(max_length=200, help_text="name of XOS db container", default="xos_db")
+    docker_project_name = StrippedCharField(max_length=200, help_text="docker project name")
+    enable_build = models.BooleanField(help_text="True if Onboarding Synchronizer should build XOS as necessary", default=True)
+
+    def __unicode__(self):  return u'%s' % (self.name)
+
+    def __init__(self, *args, **kwargs):
+        super(XOS, self).__init__(*args, **kwargs)
+
+    def save(self, *args, **kwds):
+        super(XOS, self).save(*args, **kwds)
+
+#    def can_update(self, user):
+#        return user.can_update_site(self.site, allow=['tech'])
+
+    def rebuild(self):
+        for service_controller in self.service_controllers.all():
+            for scr in service_controller.service_controller_resources.all():
+               scr.save()
+            service_controller.save()
+        self.save()
+
+class XOSVolume(PlCoreBase):
+    xos = models.ForeignKey(XOS, related_name='volumes', help_text="The XOS object for this Volume")
+    container_path=StrippedCharField(max_length=1024, unique=True, help_text="Path of Volume in Container")
+    host_path=StrippedCharField(max_length=1024, help_text="Path of Volume in Host")
+    read_only=models.BooleanField(default=False, help_text="True if mount read-only")
+
+    def __unicode__(self): return u'%s' % (self.container_path)
+
+
diff --git a/xos/core/xoslib/methods/ceilometerview.py b/xos/core/xoslib/methods/ceilometerview.py
index 16b32d4..9c87e40 100644
--- a/xos/core/xoslib/methods/ceilometerview.py
+++ b/xos/core/xoslib/methods/ceilometerview.py
@@ -1151,8 +1151,8 @@
         if (not tenant_ceilometer_url):
             raise XOSMissingField("Tenant ceilometer URL is missing")
 
-        tenant_id = request.QUERY_PARAMS.get('tenant', None)
-        resource_id = request.QUERY_PARAMS.get('resource', None)
+        tenant_id = request.query_params.get('tenant', None)
+        resource_id = request.query_params.get('resource', None)
 
         query = []
         if tenant_id:
@@ -1187,9 +1187,9 @@
             raise XOSMissingField("Tenant ceilometer URL is missing")
         tenant_map = getTenantControllerTenantMap(request.user)
         
-        date_options = request.QUERY_PARAMS.get('period', 1)
-        date_from = request.QUERY_PARAMS.get('date_from', '')
-        date_to = request.QUERY_PARAMS.get('date_to', '')
+        date_options = request.query_params.get('period', 1)
+        date_from = request.query_params.get('date_from', '')
+        date_to = request.query_params.get('date_to', '')
 
         try:
             date_from, date_to = calc_date_args(date_from,
@@ -1208,9 +1208,9 @@
                                      'op': 'le',
                                      'value': date_to})
 
-        meter_name = request.QUERY_PARAMS.get('meter', None)
-        tenant_id = request.QUERY_PARAMS.get('tenant', None)
-        resource_id = request.QUERY_PARAMS.get('resource', None)
+        meter_name = request.query_params.get('meter', None)
+        tenant_id = request.query_params.get('tenant', None)
+        resource_id = request.query_params.get('resource', None)
 
         query = []
         if tenant_id:
@@ -1284,12 +1284,12 @@
         tenant_ceilometer_url = getTenantCeilometerProxyURL(request.user)
         if (not tenant_ceilometer_url):
             raise XOSMissingField("Tenant ceilometer URL is missing")
-        meter_name = request.QUERY_PARAMS.get('meter', None)
+        meter_name = request.query_params.get('meter', None)
         if not meter_name:
             raise XOSMissingField("Meter name in query params is missing")
-        limit = request.QUERY_PARAMS.get('limit', 10)
-        tenant_id = request.QUERY_PARAMS.get('tenant', None)
-        resource_id = request.QUERY_PARAMS.get('resource', None)
+        limit = request.query_params.get('limit', 10)
+        tenant_id = request.query_params.get('tenant', None)
+        resource_id = request.query_params.get('resource', None)
         query = []
         if tenant_id:
             query.extend(make_query(tenant_id=tenant_id))
@@ -1340,7 +1340,7 @@
         tenant_ceilometer_url = getTenantCeilometerProxyURL(request.user)
         if (not tenant_ceilometer_url):
             raise XOSMissingField("Tenant ceilometer URL is missing")
-        instance_uuid = request.QUERY_PARAMS.get('instance-uuid', None)
+        instance_uuid = request.query_params.get('instance-uuid', None)
         if not instance_uuid:
             raise XOSMissingField("Instance UUID in query params is missing")
         if not Instance.objects.filter(instance_uuid=instance_uuid):
@@ -1354,9 +1354,9 @@
             #neutron port resource id is represented in ceilometer as "nova instance-name"+"-"+"nova instance-id"+"-"+"tap"+first 11 characters of port-id
             resource_ids.append(xos_instance.instance_id+"-"+instance_uuid+"-tap"+p.port_id[:11])
         
-        date_options = request.QUERY_PARAMS.get('period', 1)
-        date_from = request.QUERY_PARAMS.get('date_from', '')
-        date_to = request.QUERY_PARAMS.get('date_to', '')
+        date_options = request.query_params.get('period', 1)
+        date_from = request.query_params.get('date_from', '')
+        date_to = request.query_params.get('date_to', '')
 
         try:
             date_from, date_to = calc_date_args(date_from,
@@ -1437,9 +1437,9 @@
     def get(self, request, format=None):
         if (not request.user.is_authenticated()) or (not request.user.is_admin):
             raise PermissionDenied("You must be authenticated admin user in order to use this API")
-        service = request.QUERY_PARAMS.get('service', None)
-        slice_hint = request.QUERY_PARAMS.get('slice_hint', None)
-        scale = request.QUERY_PARAMS.get('scale', None)
+        service = request.query_params.get('service', None)
+        slice_hint = request.query_params.get('slice_hint', None)
+        scale = request.query_params.get('scale', None)
         if not service or not slice_hint or not scale:
             raise XOSMissingField("Mandatory fields missing")
         services = Service.select_by_user(request.user)
diff --git a/xos/core/xoslib/static/js/vendor/ngXosHelpers.js b/xos/core/xoslib/static/js/vendor/ngXosHelpers.js
index 4af4da5..90049b8 100644
--- a/xos/core/xoslib/static/js/vendor/ngXosHelpers.js
+++ b/xos/core/xoslib/static/js/vendor/ngXosHelpers.js
@@ -1 +1 @@
-"use strict";!function(){angular.module("xos.uiComponents",["chart.js","RecursionHelper"])}(),function(){function e(){var e=function(e){return e.split("_").join(" ").trim()},n=function(e){return e.split(/(?=[A-Z])/).map(function(e){return e.toLowerCase()}).join(" ")},o=function(e){return e.slice(0,1).toUpperCase()+e.slice(1)},t=function(t){return t=e(t),t=n(t),t=o(t).replace(/\s\s+/g," ")+":",t.replace("::",":")};return{_formatByUnderscore:e,_formatByUppercase:n,_capitalize:o,format:t}}angular.module("xos.uiComponents").factory("LabelFormatter",e)}();var _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};!function(){angular.module("xos.uiComponents").service("XosFormHelpers",["_","LabelFormatter",function(e,n){var o=this;this._isEmail=function(e){var n=/(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/;return n.test(e)},this._getFieldFormat=function(n){return angular.isArray(n)?"array":e.isDate(n)||!Number.isNaN(Date.parse(n))&&new Date(n).getTime()>6311808e5?"date":"boolean"==typeof n?"boolean":o._isEmail(n)?"email":"string"==typeof n||null===n?"text":"undefined"==typeof n?"undefined":_typeof(n)},this.buildFormStructure=function(t,i,r){return t=Object.keys(t).length>0?t:i,i=i||{},e.reduce(Object.keys(t),function(e,t){return e[t]={label:i[t]&&i[t].label?i[t].label+":":n.format(t),type:i[t]&&i[t].type?i[t].type:o._getFieldFormat(r[t]),validators:i[t]&&i[t].validators?i[t].validators:{},hint:i[t]&&i[t].hint?i[t].hint:""},"date"===e[t].type&&(r[t]=new Date(r[t])),"number"===e[t].type&&(r[t]=parseInt(r[t],10)),e},{})},this.parseModelField=function(n){return e.reduce(n,function(e,n){return e[n]={},e},{})}}])}(),function(){angular.module("xos.uiComponents").directive("xosValidation",function(){return{restrict:"E",scope:{field:"=",form:"="},template:'\n        <div ng-cloak>\n          <xos-alert config="vm.config" show="vm.field.$error.required !== undefined && vm.field.$error.required !== false  && (vm.field.$touched || vm.form.$submitted)">\n            Field required\n          </xos-alert>\n          <xos-alert config="vm.config" show="vm.field.$error.email !== undefined && vm.field.$error.email !== false  && (vm.field.$touched || vm.form.$submitted)">\n            This is not a valid email\n          </xos-alert>\n          <xos-alert config="vm.config" show="vm.field.$error.minlength !== undefined && vm.field.$error.minlength !== false  && (vm.field.$touched || vm.form.$submitted)">\n            Too short\n          </xos-alert>\n          <xos-alert config="vm.config" show="vm.field.$error.maxlength !== undefined && vm.field.$error.maxlength !== false  && (vm.field.$touched || vm.form.$submitted)">\n            Too long\n          </xos-alert>\n          <xos-alert config="vm.config" show="vm.field.$error.custom !== undefined && vm.field.$error.custom !== false  && (vm.field.$touched || vm.form.$submitted)">\n            Field invalid\n          </xos-alert>\n        </div>\n      ',transclude:!0,bindToController:!0,controllerAs:"vm",controller:function(){this.config={type:"danger"}}}})}(),function(){angular.module("xos.uiComponents").directive("xosForm",function(){return{restrict:"E",scope:{config:"=",ngModel:"="},template:'\n        <ng-form name="vm.{{vm.config.formName || \'form\'}}">\n          <div class="form-group" ng-repeat="(name, field) in vm.formField">\n            <xos-field name="name" field="field" ng-model="vm.ngModel[name]"></xos-field>\n            <xos-validation errors="vm[vm.config.formName || \'form\'][name].$error"></xos-validation>\n          </div>\n          <div class="form-group" ng-if="vm.config.actions">\n            <button role="button" href=""\n              ng-repeat="action in vm.config.actions"\n              ng-click="action.cb(vm.ngModel)"\n              class="btn btn-{{action.class}}"\n              title="{{action.label}}">\n              <i class="glyphicon glyphicon-{{action.icon}}"></i>\n              {{action.label}}\n            </button>\n          </div>\n        </ng-form>\n      ',bindToController:!0,controllerAs:"vm",controller:["$scope","$log","_","XosFormHelpers",function(e,n,o,t){var i=this;if(!this.config)throw new Error('[xosForm] Please provide a configuration via the "config" attribute');if(!this.config.actions)throw new Error("[xosForm] Please provide an action list in the configuration");this.excludedField=["id","validators","created","updated","deleted","backend_status"],this.config&&this.config.exclude&&(this.excludedField=this.excludedField.concat(this.config.exclude)),this.formField=[],e.$watch(function(){return i.ngModel},function(e){if(i.formField={},e){var n=o.difference(Object.keys(e),i.excludedField),r=t.parseModelField(n);i.formField=t.buildFormStructure(r,i.config.fields,e)}})}]}})}(),function(){angular.module("xos.uiComponents").directive("xosTable",function(){return{restrict:"E",scope:{data:"=",config:"="},template:'\n          <div ng-show="vm.data.length > 0">\n            <div class="row" ng-if="vm.config.filter == \'fulltext\'">\n              <div class="col-xs-12">\n                <input\n                  class="form-control"\n                  placeholder="Type to search.."\n                  type="text"\n                  ng-model="vm.query"/>\n              </div>\n            </div>\n            <table ng-class="vm.classes" ng-hide="vm.data.length == 0">\n              <thead>\n                <tr>\n                  <th ng-repeat="col in vm.columns">\n                    {{col.label}}\n                    <span ng-if="vm.config.order">\n                      <a href="" ng-click="vm.orderBy = col.prop; vm.reverse = false">\n                        <i class="glyphicon glyphicon-chevron-up"></i>\n                      </a>\n                      <a href="" ng-click="vm.orderBy = col.prop; vm.reverse = true">\n                        <i class="glyphicon glyphicon-chevron-down"></i>\n                      </a>\n                    </span>\n                  </th>\n                  <th ng-if="vm.config.actions">Actions:</th>\n                </tr>\n              </thead>\n              <tbody ng-if="vm.config.filter == \'field\'">\n                <tr>\n                  <td ng-repeat="col in vm.columns">\n                    <input\n                      ng-if="col.type !== \'boolean\'"\n                      class="form-control"\n                      placeholder="Type to search by {{col.label}}"\n                      type="text"\n                      ng-model="vm.query[col.prop]"/>\n                    <select\n                      ng-if="col.type === \'boolean\'"\n                      class="form-control"\n                      ng-model="vm.query[col.prop]">\n                      <option value="">-</option>\n                      <option value="true">True</option>\n                      <option value="false">False</option>\n                    </select>\n                  </td>\n                  <td ng-if="vm.config.actions"></td>\n                </tr>\n              </tbody>\n              <tbody>\n                <tr ng-repeat="item in vm.data | filter:vm.query | orderBy:vm.orderBy:vm.reverse | pagination:vm.currentPage * vm.config.pagination.pageSize | limitTo: (vm.config.pagination.pageSize || vm.data.length) track by $index">\n                  <td ng-repeat="col in vm.columns" link-wrapper>\n                    <span ng-if="!col.type">{{item[col.prop]}}</span>\n                    <span ng-if="col.type === \'boolean\'">\n                      <i class="glyphicon"\n                        ng-class="{\'glyphicon-ok\': item[col.prop], \'glyphicon-remove\': !item[col.prop]}">\n                      </i>\n                    </span>\n                    <span ng-if="col.type === \'date\'">\n                      {{item[col.prop] | date:\'H:mm MMM d, yyyy\'}}\n                    </span>\n                    <span ng-if="col.type === \'array\'">\n                      {{item[col.prop] | arrayToList}}\n                    </span>\n                    <span ng-if="col.type === \'object\'">\n                      <dl class="dl-horizontal">\n                        <span ng-repeat="(k,v) in item[col.prop]">\n                          <dt>{{k}}</dt>\n                          <dd>{{v}}</dd>\n                        </span>\n                      </dl>\n                    </span>\n                    <span ng-if="col.type === \'custom\'">\n                      {{col.formatter(item)}}\n                    </span>\n                    <span ng-if="col.type === \'icon\'">\n                      <i class="glyphicon glyphicon-{{col.formatter(item)}}">\n                      </i>\n                    </span>\n                  </td>\n                  <td ng-if="vm.config.actions">\n                    <a href=""\n                      ng-repeat="action in vm.config.actions"\n                      ng-click="action.cb(item)"\n                      title="{{action.label}}">\n                      <i\n                        class="glyphicon glyphicon-{{action.icon}}"\n                        style="color: {{action.color}};"></i>\n                    </a>\n                  </td>\n                </tr>\n              </tbody>\n            </table>\n            <xos-pagination\n              ng-if="vm.config.pagination"\n              page-size="vm.config.pagination.pageSize"\n              total-elements="vm.data.length"\n              change="vm.goToPage">\n              </xos-pagination>\n          </div>\n          <div ng-show="vm.data.length == 0 || !vm.data">\n             <xos-alert config="{type: \'info\'}">\n              No data to show.\n            </xos-alert>\n          </div>\n        ',bindToController:!0,controllerAs:"vm",controller:["_",function(e){var n=this;if(!this.config)throw new Error('[xosTable] Please provide a configuration via the "config" attribute');if(!this.config.columns)throw new Error("[xosTable] Please provide a columns list in the configuration");this.config.order&&angular.isObject(this.config.order)&&(this.reverse=this.config.order.reverse||!1,this.orderBy=this.config.order.field||"id");var o=e.filter(this.config.columns,{type:"custom"});angular.isArray(o)&&o.length>0&&e.forEach(o,function(e){if(!e.formatter||!angular.isFunction(e.formatter))throw new Error("[xosTable] You have provided a custom field type, a formatter function should provided too.")});var t=e.filter(this.config.columns,{type:"icon"});angular.isArray(t)&&t.length>0&&e.forEach(t,function(e){if(!e.formatter||!angular.isFunction(e.formatter))throw new Error("[xosTable] You have provided an icon field type, a formatter function should provided too.")});var i=e.filter(this.config.columns,function(e){return angular.isDefined(e.link)});angular.isArray(i)&&i.length>0&&e.forEach(i,function(e){if(!angular.isFunction(e.link))throw new Error("[xosTable] The link property should be a function.")}),this.columns=this.config.columns,this.classes=this.config.classes||"table table-striped table-bordered",this.config.actions,this.config.pagination&&(this.currentPage=0,this.goToPage=function(e){n.currentPage=e})}]}}).filter("arrayToList",function(){return function(e){return angular.isArray(e)?e.join(", "):e}}).directive("linkWrapper",function(){return{restrict:"A",transclude:!0,template:'\n          <a ng-if="col.link" href="{{col.link(item)}}">\n            <div ng-transclude></div>\n          </a>\n          <div ng-transclude ng-if="!col.link"></div>\n        '}})}(),function(){angular.module("xos.uiComponents").directive("xosPagination",function(){return{restrict:"E",scope:{pageSize:"=",totalElements:"=",change:"="},template:'\n        <div class="row" ng-if="vm.pageList.length > 1">\n          <div class="col-xs-12 text-center">\n            <ul class="pagination">\n              <li\n                ng-click="vm.goToPage(vm.currentPage - 1)"\n                ng-class="{disabled: vm.currentPage == 0}">\n                <a href="" aria-label="Previous">\n                    <span aria-hidden="true">&laquo;</span>\n                </a>\n              </li>\n              <li ng-repeat="i in vm.pageList" ng-class="{active: i === vm.currentPage}">\n                <a href="" ng-click="vm.goToPage(i)">{{i + 1}}</a>\n              </li>\n              <li\n                ng-click="vm.goToPage(vm.currentPage + 1)"\n                ng-class="{disabled: vm.currentPage == vm.pages - 1}">\n                <a href="" aria-label="Next">\n                    <span aria-hidden="true">&raquo;</span>\n                </a>\n              </li>\n            </ul>\n          </div>\n        </div>\n      ',bindToController:!0,controllerAs:"vm",controller:["$scope",function(e){var n=this;this.currentPage=0,this.goToPage=function(e){0>e||e===n.pages||(n.currentPage=e,n.change(e))},this.createPages=function(e){for(var n=[],o=0;e>o;o++)n.push(o);return n},e.$watch(function(){return n.totalElements},function(){n.totalElements&&(n.pages=Math.ceil(n.totalElements/n.pageSize),n.pageList=n.createPages(n.pages))})}]}}).filter("pagination",function(){return function(e,n){return e&&angular.isArray(e)?(n=parseInt(n,10),e.slice(n)):e}})}(),function(){angular.module("xos.uiComponents").directive("xosAlert",function(){return{restrict:"E",scope:{config:"=",show:"=?"},template:'\n        <div ng-cloak class="alert alert-{{vm.config.type}}" ng-hide="!vm.show">\n          <button type="button" class="close" ng-if="vm.config.closeBtn" ng-click="vm.dismiss()">\n            <span aria-hidden="true">&times;</span>\n          </button>\n          <p ng-transclude></p>\n        </div>\n      ',transclude:!0,bindToController:!0,controllerAs:"vm",controller:["$timeout",function(e){var n=this;if(!this.config)throw new Error('[xosAlert] Please provide a configuration via the "config" attribute');this.show=this.show!==!1,this.dismiss=function(){n.show=!1},this.config.autoHide&&!function(){var o=e(function(){n.dismiss(),e.cancel(o)},n.config.autoHide)}()}]}})}(),function(){angular.module("xos.uiComponents").directive("xosField",["RecursionHelper",function(e){return{restrict:"E",scope:{name:"=",field:"=",ngModel:"="},template:'\n        <label ng-if="vm.field.type !== \'object\'">{{vm.field.label}}</label>\n            <input\n              ng-if="vm.field.type !== \'boolean\' && vm.field.type !== \'object\'"\n              type="{{vm.field.type}}"\n              name="{{vm.name}}"\n              class="form-control"\n              ng-model="vm.ngModel"\n              ng-minlength="vm.field.validators.minlength || 0"\n              ng-maxlength="vm.field.validators.maxlength || 2000"\n              ng-required="vm.field.validators.required || false" />\n            <span class="boolean-field" ng-if="vm.field.type === \'boolean\'">\n              <button\n                class="btn btn-success"\n                ng-show="vm.ngModel"\n                ng-click="vm.ngModel = false">\n                <i class="glyphicon glyphicon-ok"></i>\n              </button>\n              <button\n                class="btn btn-danger"\n                ng-show="!vm.ngModel"\n                ng-click="vm.ngModel = true">\n                <i class="glyphicon glyphicon-remove"></i>\n              </button>\n            </span>\n            <div\n              class="panel panel-default object-field"\n              ng-if="vm.field.type == \'object\' && !vm.isEmptyObject(vm.ngModel)"\n              >\n              <div class="panel-heading">{{vm.field.label}}</div>\n              <div class="panel-body">\n                <div ng-repeat="(k, v) in vm.ngModel">\n                  <xos-field\n                    name="k"\n                    field="{label: vm.formatLabel(k), type: vm.getType(v)}"\n                    ng-model="v">\n                  </xos-field>\n                </div>\n              </div>\n            </div>\n      ',bindToController:!0,controllerAs:"vm",compile:function(n){return e.compile(n)},controller:["$attrs","XosFormHelpers","LabelFormatter",function(e,n,o){if(!this.name)throw new Error("[xosField] Please provide a field name");if(!this.field)throw new Error("[xosField] Please provide a field definition");if(!e.ngModel)throw new Error("[xosField] Please provide an ng-model");this.getType=n._getFieldFormat,this.formatLabel=o.format,this.isEmptyObject=function(e){return 0===Object.keys(e).length}}]}}])}();var _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};!function(){angular.module("xos.uiComponents").directive("xosSmartTable",function(){return{restrict:"E",scope:{config:"="},template:'\n        <div class="row" ng-show="vm.data.length > 0">\n          <div class="col-xs-12 text-right">\n            <a href="" class="btn btn-success" ng-click="vm.createItem()">\n              Add\n            </a>\n          </div>\n        </div>\n        <div class="row">\n          <div class="col-xs-12 table-responsive">\n            <xos-table config="vm.tableConfig" data="vm.data"></xos-table>\n          </div>\n        </div>\n        <div class="panel panel-default" ng-show="vm.detailedItem">\n          <div class="panel-heading">\n            <div class="row">\n              <div class="col-xs-11">\n                <h3 class="panel-title" ng-show="vm.detailedItem.id">Update {{vm.config.resource}} {{vm.detailedItem.id}}</h3>\n                <h3 class="panel-title" ng-show="!vm.detailedItem.id">Create {{vm.config.resource}} item</h3>\n              </div>\n              <div class="col-xs-1">\n                <a href="" ng-click="vm.cleanForm()">\n                  <i class="glyphicon glyphicon-remove pull-right"></i>\n                </a>\n              </div>\n            </div>\n          </div>\n          <div class="panel-body">\n            <xos-form config="vm.formConfig" ng-model="vm.detailedItem"></xos-form>\n          </div>\n        </div>\n        <xos-alert config="{type: \'success\', closeBtn: true}" show="vm.responseMsg">{{vm.responseMsg}}</xos-alert>\n        <xos-alert config="{type: \'danger\', closeBtn: true}" show="vm.responseErr">{{vm.responseErr}}</xos-alert>\n      ',bindToController:!0,controllerAs:"vm",controller:["$injector","LabelFormatter","_","XosFormHelpers",function(e,n,o,t){var i=this;this.responseMsg=!1,this.responseErr=!1,this.tableConfig={columns:[],actions:[{label:"delete",icon:"remove",cb:function(e){i.Resource["delete"]({id:e.id}).$promise.then(function(){o.remove(i.data,function(n){return n.id===e.id}),i.responseMsg=i.config.resource+" with id "+e.id+" successfully deleted"})["catch"](function(n){i.responseErr=n.data.detail||"Error while deleting "+i.config.resource+" with id "+e.id})},color:"red"},{label:"details",icon:"search",cb:function(e){i.detailedItem=e}}],classes:"table table-striped table-bordered table-responsive",filter:"field",order:!0,pagination:{pageSize:10}},this.formConfig={exclude:this.config.hiddenFields,fields:{},formName:this.config.resource+"Form",actions:[{label:"Save",icon:"ok",cb:function(e){var n=void 0,o=!0;e.id?(n=e.$update(),o=!1):n=e.$save(),n.then(function(n){o&&i.data.push(angular.copy(n)),delete i.detailedItem,i.responseMsg=i.config.resource+" with id "+e.id+" successfully saved"})["catch"](function(n){i.responseErr=n.data.detail||"Error while saving "+i.config.resource+" with id "+e.id})},"class":"success"}]},this.cleanForm=function(){delete i.detailedItem},this.createItem=function(){i.detailedItem=new i.Resource},this.Resource=e.get(this.config.resource);var r=function(){i.Resource.query().$promise.then(function(e){if(e[0]){var r=e[0],s=Object.keys(r);o.remove(s,function(e){return"id"==e||"validators"==e}),angular.isArray(i.config.hiddenFields)&&(s=o.difference(s,i.config.hiddenFields));var a=s.map(function(e){return n.format(e)});s.forEach(function(e,n){var o={label:a[n],prop:e};"string"!=typeof r[e]&&"undefined"!=typeof r[e]&&(o.type=_typeof(r[e])),i.tableConfig.columns.push(o)}),s.forEach(function(e,o){i.formConfig.fields[e]={label:n.format(a[o]).replace(":",""),type:t._getFieldFormat(r[e])}}),i.data=e}})};r()}]}})}(),function(){angular.module("xos.uiComponents").directive("xosSmartPie",function(){return{restrict:"E",scope:{config:"="},template:'\n        <canvas\n          class="chart chart-pie {{vm.config.classes}}"\n          chart-data="vm.data" chart-labels="vm.labels"\n          chart-legend="{{vm.config.legend}}">\n        </canvas>\n      ',bindToController:!0,controllerAs:"vm",controller:["$injector","$interval","$scope","$timeout","_",function(e,n,o,t,i){var r=this;if(!this.config.resource&&!this.config.data)throw new Error("[xosSmartPie] Please provide a resource or an array of data in the configuration");var s=function(e){return i.groupBy(e,r.config.groupBy)},a=function(e){return i.reduce(Object.keys(e),function(n,o){return n.concat(e[o].length)},[])},c=function(e){return angular.isFunction(r.config.labelFormatter)?r.config.labelFormatter(Object.keys(e)):Object.keys(e)},l=function(e){var n=s(e);r.data=a(n),r.labels=c(n)};this.config.resource?!function(){r.Resource=e.get(r.config.resource);var o=function(){r.Resource.query().$promise.then(function(e){e[0]&&l(e)})};o(),r.config.poll&&n(function(){o()},1e3*r.config.poll)}():o.$watch(function(){return r.config.data},function(e){e&&l(r.config.data)},!0),o.$on("create",function(e,n){console.log("create: "+n.id)}),o.$on("destroy",function(e,n){console.log("destroy: "+n.id)})}]}})}(),function(){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){window.Bugsnag?Bugsnag.notifyException(e,{diagnostics:{cause:n}}):console.error(e,n,e.stack)}}),angular.module("xos.helpers",["ngCookies","ngResource","ngAnimate","bugSnag","xos.uiComponents"]).config(e).factory("_",["$window",function(e){return e._}])}(),function(){angular.module("xos.helpers").service("vSG-Collection",["$resource",function(e){return e("/api/service/vsg/")}])}(),function(){angular.module("xos.helpers").service("vOLT-Collection",["$resource",function(e){return e("/api/tenant/cord/volt/:volt_id/",{volt_id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Login",["$resource",function(e){return e("/api/utility/login/")}]).service("Logout",["$resource",function(e){return e("/api/utility/logout/")}])}(),function(){angular.module("xos.helpers").service("Users",["$resource",function(e){return e("/api/core/users/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Truckroll",["$resource",function(e){return e("/api/tenant/truckroll/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Tenants",["$resource",function(e){return e("/api/core/tenants/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Subscribers",["$resource",function(e){return e("/api/tenant/cord/subscriber/:id/",{id:"@id"},{update:{method:"PUT"},"View-a-Subscriber-Features-Detail":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/"},"Read-Subscriber-uplink_speed":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/uplink_speed/"},"Update-Subscriber-uplink_speed":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/uplink_speed/"},"Read-Subscriber-downlink_speed":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/downlink_speed/"},"Update-Subscriber-downlink_speed":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/downlink_speed/"},"Read-Subscriber-cdn":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/cdn/"},"Update-Subscriber-cdn":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/cdn/"},"Read-Subscriber-uverse":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/uverse/"},"Update-Subscriber-uverse":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/uverse/"},"Read-Subscriber-status":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/status/"},"Update-Subscriber-status":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/status/"}})}])}(),function(){angular.module("xos.helpers").service("SlicesPlus",["$http","$q",function(e,n){this.query=function(o){var t=n.defer();return e.get("/api/utility/slicesplus/",{params:o}).then(function(e){t.resolve(e.data)})["catch"](function(e){t.reject(e.data)}),{$promise:t.promise}},this.get=function(o,t){var i=n.defer();return e.get("/api/utility/slicesplus/"+o,{params:t}).then(function(e){i.resolve(e.data)})["catch"](function(e){i.reject(e.data)}),{$promise:i.promise}}}])}(),function(){angular.module("xos.helpers").service("Slices",["$resource",function(e){return e("/api/core/slices/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Sites",["$resource",function(e){return e("/api/core/sites/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Services",["$resource",function(e){return e("/api/core/services/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("ONOS-Services-Collection",["$resource",function(e){return e("/api/service/onos/")}])}(),function(){angular.module("xos.helpers").service("ONOS-App-Collection",["$resource",function(e){return e("/api/tenant/onos/app/")}])}(),function(){angular.module("xos.helpers").service("Nodes",["$resource",function(e){return e("/api/core/nodes/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Networks",["$resource",function(e){return e("/api/core/networks/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Instances",["$resource",function(e){return e("/api/core/instances/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Flavors",["$resource",function(e){return e("/api/core/flavors/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Example-Services-Collection",["$resource",function(e){return e("/api/service/exampleservice/")}])}(),function(){angular.module("xos.helpers").service("Deployments",["$resource",function(e){return e("/api/core/deployments/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("XosUserPrefs",["$cookies",function(e){var n=this,o=e.get("xosUserPrefs")?JSON.parse(e.get("xosUserPrefs")):{};this.getAll=function(){return o=e.get("xosUserPrefs")?JSON.parse(e.get("xosUserPrefs")):{}},this.setAll=function(n){e.put("xosUserPrefs",JSON.stringify(n))},this.getSynchronizerNotificationStatus=function(){var e=arguments.length<=0||void 0===arguments[0]?!1:arguments[0];return e?n.getAll().synchronizers.notification[e]:n.getAll().synchronizers.notification},this.setSynchronizerNotificationStatus=function(){var e=arguments.length<=0||void 0===arguments[0]?!1:arguments[0],o=arguments[1];if(!e)throw new Error("[XosUserPrefs] When updating a synchronizer is mandatory to provide a name.");var t=n.getAll();t.synchronizers||(t.synchronizers={notification:{}}),t.synchronizers.notification[e]=o,n.setAll(t)}}])}(),function(){angular.module("xos.helpers").service("GraphService",["$q","Tenants","Services",function(e,n,o){var t=this;this.loadCoarseData=function(){var t=void 0,i=e.defer();return o.query().$promise.then(function(e){return t=e,n.query({kind:"coarse"}).$promise}).then(function(e){i.resolve({tenants:e,services:t})}),i.promise},this.getCoarseGraph=function(){return t.loadCoarseData().then(function(e){console.log(e)}),"ciao"}}])}(),function(){angular.module("xos.helpers").factory("Notification",function(){return window.Notification}).service("xosNotification",["$q","$log","Notification",function(e,n,o){var t=this;this.checkPermission=function(){var n=e.defer();return o.requestPermission().then(function(e){"granted"===e?n.resolve(e):n.reject(e)}),n.promise},this.sendNotification=function(e,t){var i=new o(e,t);i.onerror=function(e){n.error(e)}},this.notify=function(e,i){"Notification"in window?"granted"!==o.permission?t.checkPermission().then(function(){return t.sendNotification(e,i)}):"granted"===o.permission&&t.sendNotification(e,i):n.info("This browser does not support desktop notification")}}])}(),function(){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)}(),angular.module("xos.helpers").config(["$provide",function(e){e.decorator("$log",["$delegate",function(e){var n=function(){return window.location.href.indexOf("debug=true")>=0},o=e.log,t=e.info,i=e.warn,r=e.error,s=e.debug,a=function(o){return function(){if(n()){var t=[].slice.call(arguments),i=new Date;t[0]="["+i.getHours()+":"+i.getMinutes()+":"+i.getSeconds()+"] "+t[0],"function"!=typeof e.reset||e.debug.logs instanceof Array||e.reset(),o.apply(null,t)}}};return e.info=a(t),e.log=a(o),e.warn=a(i),e.error=a(r),e.debug=a(s),e}])}]),function(){function e(){var e=function(e){return e.split("_").join(" ").trim()},n=function(e){return e.split(/(?=[A-Z])/).map(function(e){return e.toLowerCase()}).join(" ")},o=function(e){return e.slice(0,1).toUpperCase()+e.slice(1)},t=function(t){return t=e(t),t=n(t),t=o(t).replace(/\s\s+/g," ")+":",t.replace("::",":")};return{_formatByUnderscore:e,_formatByUppercase:n,_capitalize:o,format:t}}angular.module("xos.uiComponents").factory("LabelFormatter",e)}(),function(){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)}();
\ No newline at end of file
+"use strict";!function(){angular.module("xos.uiComponents",["chart.js","RecursionHelper"])}();var _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};!function(){angular.module("xos.uiComponents").directive("xosSmartTable",function(){return{restrict:"E",scope:{config:"="},template:'\n        <div class="row" ng-show="vm.data.length > 0">\n          <div class="col-xs-12 text-right">\n            <a href="" class="btn btn-success" ng-click="vm.createItem()">\n              Add\n            </a>\n          </div>\n        </div>\n        <div class="row">\n          <div class="col-xs-12 table-responsive">\n            <xos-table config="vm.tableConfig" data="vm.data"></xos-table>\n          </div>\n        </div>\n        <div class="panel panel-default" ng-show="vm.detailedItem">\n          <div class="panel-heading">\n            <div class="row">\n              <div class="col-xs-11">\n                <h3 class="panel-title" ng-show="vm.detailedItem.id">Update {{vm.config.resource}} {{vm.detailedItem.id}}</h3>\n                <h3 class="panel-title" ng-show="!vm.detailedItem.id">Create {{vm.config.resource}} item</h3>\n              </div>\n              <div class="col-xs-1">\n                <a href="" ng-click="vm.cleanForm()">\n                  <i class="glyphicon glyphicon-remove pull-right"></i>\n                </a>\n              </div>\n            </div>\n          </div>\n          <div class="panel-body">\n            <xos-form config="vm.formConfig" ng-model="vm.detailedItem"></xos-form>\n          </div>\n        </div>\n        <xos-alert config="{type: \'success\', closeBtn: true}" show="vm.responseMsg">{{vm.responseMsg}}</xos-alert>\n        <xos-alert config="{type: \'danger\', closeBtn: true}" show="vm.responseErr">{{vm.responseErr}}</xos-alert>\n      ',bindToController:!0,controllerAs:"vm",controller:["$injector","LabelFormatter","_","XosFormHelpers",function(e,n,o,t){var i=this;this.responseMsg=!1,this.responseErr=!1,this.tableConfig={columns:[],actions:[{label:"delete",icon:"remove",cb:function(e){i.Resource["delete"]({id:e.id}).$promise.then(function(){o.remove(i.data,function(n){return n.id===e.id}),i.responseMsg=i.config.resource+" with id "+e.id+" successfully deleted"})["catch"](function(n){i.responseErr=n.data.detail||"Error while deleting "+i.config.resource+" with id "+e.id})},color:"red"},{label:"details",icon:"search",cb:function(e){i.detailedItem=e}}],classes:"table table-striped table-bordered table-responsive",filter:"field",order:!0,pagination:{pageSize:10}},this.formConfig={exclude:this.config.hiddenFields,fields:{},formName:this.config.resource+"Form",actions:[{label:"Save",icon:"ok",cb:function(e){var n=void 0,o=!0;e.id?(n=e.$update(),o=!1):n=e.$save(),n.then(function(n){o&&i.data.push(angular.copy(n)),delete i.detailedItem,i.responseMsg=i.config.resource+" with id "+e.id+" successfully saved"})["catch"](function(n){i.responseErr=n.data.detail||"Error while saving "+i.config.resource+" with id "+e.id})},"class":"success"}]},this.cleanForm=function(){delete i.detailedItem},this.createItem=function(){i.detailedItem=new i.Resource},this.Resource=e.get(this.config.resource);var r=function(){i.Resource.query().$promise.then(function(e){if(e[0]){var r=e[0],s=Object.keys(r);o.remove(s,function(e){return"id"===e||"validators"===e}),angular.isArray(i.config.hiddenFields)&&(s=o.difference(s,i.config.hiddenFields));var a=s.map(function(e){return n.format(e)});s.forEach(function(e,n){var o={label:a[n],prop:e};"string"!=typeof r[e]&&"undefined"!=typeof r[e]&&(o.type=_typeof(r[e])),i.tableConfig.columns.push(o)}),s.forEach(function(e,o){i.formConfig.fields[e]={label:n.format(a[o]).replace(":",""),type:t._getFieldFormat(r[e])}}),i.data=e}})};r()}]}})}(),function(){angular.module("xos.uiComponents").directive("xosValidation",function(){return{restrict:"E",scope:{field:"=",form:"="},template:'\n        <div ng-cloak>\n          <xos-alert config="vm.config" show="vm.field.$error.required !== undefined && vm.field.$error.required !== false  && (vm.field.$touched || vm.form.$submitted)">\n            Field required\n          </xos-alert>\n          <xos-alert config="vm.config" show="vm.field.$error.email !== undefined && vm.field.$error.email !== false && (vm.field.$touched || vm.form.$submitted)">\n            This is not a valid email\n          </xos-alert>\n          <xos-alert config="vm.config" show="vm.field.$error.minlength !== undefined && vm.field.$error.minlength !== false && (vm.field.$touched || vm.form.$submitted)">\n            Too short\n          </xos-alert>\n          <xos-alert config="vm.config" show="vm.field.$error.maxlength !== undefined && vm.field.$error.maxlength !== false && (vm.field.$touched || vm.form.$submitted)">\n            Too long\n          </xos-alert>\n          <xos-alert config="vm.config" show="vm.field.$error.custom !== undefined && vm.field.$error.custom !== false && (vm.field.$touched || vm.form.$submitted)">\n            Field invalid\n          </xos-alert>\n        </div>\n      ',transclude:!0,bindToController:!0,controllerAs:"vm",controller:function(){this.config={type:"danger"}}}})}(),function(){angular.module("xos.uiComponents").directive("xosSmartPie",function(){return{restrict:"E",scope:{config:"="},template:'\n        <canvas\n          class="chart chart-pie {{vm.config.classes}}"\n          chart-data="vm.data" chart-labels="vm.labels"\n          chart-legend="{{vm.config.legend}}">\n        </canvas>\n      ',bindToController:!0,controllerAs:"vm",controller:["$injector","$interval","$scope","$timeout","_",function(e,n,o,t,i){var r=this;if(!this.config.resource&&!this.config.data)throw new Error("[xosSmartPie] Please provide a resource or an array of data in the configuration");var s=function(e){return i.groupBy(e,r.config.groupBy)},a=function(e){return i.reduce(Object.keys(e),function(n,o){return n.concat(e[o].length)},[])},l=function(e){return angular.isFunction(r.config.labelFormatter)?r.config.labelFormatter(Object.keys(e)):Object.keys(e)},c=function(e){var n=s(e);r.data=a(n),r.labels=l(n)};this.config.resource?!function(){r.Resource=e.get(r.config.resource);var o=function(){r.Resource.query().$promise.then(function(e){e[0]&&c(e)})};o(),r.config.poll&&n(function(){o()},1e3*r.config.poll)}():o.$watch(function(){return r.config.data},function(e){e&&c(r.config.data)},!0),o.$on("create",function(e,n){console.log("create: "+n.id)}),o.$on("destroy",function(e,n){console.log("destroy: "+n.id)})}]}})}(),function(){angular.module("xos.uiComponents").directive("xosTable",function(){return{restrict:"E",scope:{data:"=",config:"="},template:'\n          <div ng-show="vm.data.length > 0">\n            <div class="row" ng-if="vm.config.filter == \'fulltext\'">\n              <div class="col-xs-12">\n                <input\n                  class="form-control"\n                  placeholder="Type to search.."\n                  type="text"\n                  ng-model="vm.query"/>\n              </div>\n            </div>\n            <table ng-class="vm.classes" ng-hide="vm.data.length == 0">\n              <thead>\n                <tr>\n                  <th ng-repeat="col in vm.columns">\n                    {{col.label}}\n                    <span ng-if="vm.config.order">\n                      <a href="" ng-click="vm.orderBy = col.prop; vm.reverse = false">\n                        <i class="glyphicon glyphicon-chevron-up"></i>\n                      </a>\n                      <a href="" ng-click="vm.orderBy = col.prop; vm.reverse = true">\n                        <i class="glyphicon glyphicon-chevron-down"></i>\n                      </a>\n                    </span>\n                  </th>\n                  <th ng-if="vm.config.actions">Actions:</th>\n                </tr>\n              </thead>\n              <tbody ng-if="vm.config.filter == \'field\'">\n                <tr>\n                  <td ng-repeat="col in vm.columns">\n                    <input\n                      ng-if="col.type !== \'boolean\'"\n                      class="form-control"\n                      placeholder="Type to search by {{col.label}}"\n                      type="text"\n                      ng-model="vm.query[col.prop]"/>\n                    <select\n                      ng-if="col.type === \'boolean\'"\n                      class="form-control"\n                      ng-model="vm.query[col.prop]">\n                      <option value="">-</option>\n                      <option value="true">True</option>\n                      <option value="false">False</option>\n                    </select>\n                  </td>\n                  <td ng-if="vm.config.actions"></td>\n                </tr>\n              </tbody>\n              <tbody>\n                <tr ng-repeat="item in vm.data | filter:vm.query | orderBy:vm.orderBy:vm.reverse | pagination:vm.currentPage * vm.config.pagination.pageSize | limitTo: (vm.config.pagination.pageSize || vm.data.length) track by $index">\n                  <td ng-repeat="col in vm.columns" link-wrapper>\n                    <span ng-if="!col.type">{{item[col.prop]}}</span>\n                    <span ng-if="col.type === \'boolean\'">\n                      <i class="glyphicon"\n                        ng-class="{\'glyphicon-ok\': item[col.prop], \'glyphicon-remove\': !item[col.prop]}">\n                      </i>\n                    </span>\n                    <span ng-if="col.type === \'date\'">\n                      {{item[col.prop] | date:\'H:mm MMM d, yyyy\'}}\n                    </span>\n                    <span ng-if="col.type === \'array\'">\n                      {{item[col.prop] | arrayToList}}\n                    </span>\n                    <span ng-if="col.type === \'object\'">\n                      <dl class="dl-horizontal">\n                        <span ng-repeat="(k,v) in item[col.prop]">\n                          <dt>{{k}}</dt>\n                          <dd>{{v}}</dd>\n                        </span>\n                      </dl>\n                    </span>\n                    <span ng-if="col.type === \'custom\'">\n                      {{col.formatter(item)}}\n                    </span>\n                    <span ng-if="col.type === \'icon\'">\n                      <i class="glyphicon glyphicon-{{col.formatter(item)}}">\n                      </i>\n                    </span>\n                  </td>\n                  <td ng-if="vm.config.actions">\n                    <a href=""\n                      ng-repeat="action in vm.config.actions"\n                      ng-click="action.cb(item)"\n                      title="{{action.label}}">\n                      <i\n                        class="glyphicon glyphicon-{{action.icon}}"\n                        style="color: {{action.color}};"></i>\n                    </a>\n                  </td>\n                </tr>\n              </tbody>\n            </table>\n            <xos-pagination\n              ng-if="vm.config.pagination"\n              page-size="vm.config.pagination.pageSize"\n              total-elements="vm.data.length"\n              change="vm.goToPage">\n              </xos-pagination>\n          </div>\n          <div ng-show="vm.data.length == 0 || !vm.data">\n             <xos-alert config="{type: \'info\'}">\n              No data to show.\n            </xos-alert>\n          </div>\n        ',bindToController:!0,controllerAs:"vm",controller:["_",function(e){var n=this;if(!this.config)throw new Error('[xosTable] Please provide a configuration via the "config" attribute');if(!this.config.columns)throw new Error("[xosTable] Please provide a columns list in the configuration");this.config.order&&angular.isObject(this.config.order)&&(this.reverse=this.config.order.reverse||!1,this.orderBy=this.config.order.field||"id");var o=e.filter(this.config.columns,{type:"custom"});angular.isArray(o)&&o.length>0&&e.forEach(o,function(e){if(!e.formatter||!angular.isFunction(e.formatter))throw new Error("[xosTable] You have provided a custom field type, a formatter function should provided too.")});var t=e.filter(this.config.columns,{type:"icon"});angular.isArray(t)&&t.length>0&&e.forEach(t,function(e){if(!e.formatter||!angular.isFunction(e.formatter))throw new Error("[xosTable] You have provided an icon field type, a formatter function should provided too.")});var i=e.filter(this.config.columns,function(e){return angular.isDefined(e.link)});angular.isArray(i)&&i.length>0&&e.forEach(i,function(e){if(!angular.isFunction(e.link))throw new Error("[xosTable] The link property should be a function.")}),this.columns=this.config.columns,this.classes=this.config.classes||"table table-striped table-bordered",this.config.actions,this.config.pagination&&(this.currentPage=0,this.goToPage=function(e){n.currentPage=e})}]}}).filter("arrayToList",function(){return function(e){return angular.isArray(e)?e.join(", "):e}}).directive("linkWrapper",function(){return{restrict:"A",transclude:!0,template:'\n          <a ng-if="col.link" href="{{col.link(item)}}">\n            <div ng-transclude></div>\n          </a>\n          <div ng-transclude ng-if="!col.link"></div>\n        '}})}(),function(){angular.module("xos.uiComponents").directive("xosPagination",function(){return{restrict:"E",scope:{pageSize:"=",totalElements:"=",change:"="},template:'\n        <div class="row" ng-if="vm.pageList.length > 1">\n          <div class="col-xs-12 text-center">\n            <ul class="pagination">\n              <li\n                ng-click="vm.goToPage(vm.currentPage - 1)"\n                ng-class="{disabled: vm.currentPage == 0}">\n                <a href="" aria-label="Previous">\n                    <span aria-hidden="true">&laquo;</span>\n                </a>\n              </li>\n              <li ng-repeat="i in vm.pageList" ng-class="{active: i === vm.currentPage}">\n                <a href="" ng-click="vm.goToPage(i)">{{i + 1}}</a>\n              </li>\n              <li\n                ng-click="vm.goToPage(vm.currentPage + 1)"\n                ng-class="{disabled: vm.currentPage == vm.pages - 1}">\n                <a href="" aria-label="Next">\n                    <span aria-hidden="true">&raquo;</span>\n                </a>\n              </li>\n            </ul>\n          </div>\n        </div>\n      ',bindToController:!0,controllerAs:"vm",controller:["$scope",function(e){var n=this;this.currentPage=0,this.goToPage=function(e){0>e||e===n.pages||(n.currentPage=e,n.change(e))},this.createPages=function(e){for(var n=[],o=0;e>o;o++)n.push(o);return n},e.$watch(function(){return n.totalElements},function(){n.totalElements&&(n.pages=Math.ceil(n.totalElements/n.pageSize),n.pageList=n.createPages(n.pages))})}]}}).filter("pagination",function(){return function(e,n){return e&&angular.isArray(e)?(n=parseInt(n,10),e.slice(n)):e}})}(),function(){angular.module("xos.uiComponents").directive("xosForm",function(){return{restrict:"E",scope:{config:"=",ngModel:"="},template:'\n        <ng-form name="vm.{{vm.config.formName || \'form\'}}">\n          <div class="form-group" ng-repeat="(name, field) in vm.formField">\n            <xos-field name="name" field="field" ng-model="vm.ngModel[name]"></xos-field>\n            <xos-validation field="vm[vm.config.formName || \'form\'][name]" form="vm[vm.config.formName || \'form\']"></xos-validation>\n          </div>\n          <div class="form-group" ng-if="vm.config.actions">\n            <button role="button" href=""\n              ng-repeat="action in vm.config.actions"\n              ng-click="action.cb(vm.ngModel)"\n              class="btn btn-{{action.class}}"\n              title="{{action.label}}">\n              <i class="glyphicon glyphicon-{{action.icon}}"></i>\n              {{action.label}}\n            </button>\n          </div>\n        </ng-form>\n      ',bindToController:!0,controllerAs:"vm",controller:["$scope","$log","_","XosFormHelpers",function(e,n,o,t){var i=this;if(!this.config)throw new Error('[xosForm] Please provide a configuration via the "config" attribute');if(!this.config.actions)throw new Error("[xosForm] Please provide an action list in the configuration");this.excludedField=["id","validators","created","updated","deleted","backend_status"],this.config&&this.config.exclude&&(this.excludedField=this.excludedField.concat(this.config.exclude)),this.formField=[],e.$watch(function(){return i.ngModel},function(e){if(i.formField={},e){var n=o.difference(Object.keys(e),i.excludedField),r=t.parseModelField(n);i.formField=t.buildFormStructure(r,i.config.fields,e)}})}]}})}(),function(){angular.module("xos.uiComponents").directive("xosField",["RecursionHelper",function(e){return{restrict:"E",scope:{name:"=",field:"=",ngModel:"="},template:'\n        <label ng-if="vm.field.type !== \'object\'">{{vm.field.label}}</label>\n            <input\n              ng-if="vm.field.type !== \'boolean\' && vm.field.type !== \'object\' && vm.field.type !== \'select\'"\n              type="{{vm.field.type}}"\n              name="{{vm.name}}"\n              class="form-control"\n              ng-model="vm.ngModel"\n              ng-minlength="vm.field.validators.minlength || 0"\n              ng-maxlength="vm.field.validators.maxlength || 2000"\n              ng-required="vm.field.validators.required || false" />\n              <select class="form-control" ng-if ="vm.field.type === \'select\'"\n                name = "{{vm.name}}"\n                ng-options="item.id as item.label for item in vm.field.options track by item.id"\n                ng-model="vm.ngModel"\n                ng-required="vm.field.validators.required || false">\n                </select>\n            <span class="boolean-field" ng-if="vm.field.type === \'boolean\'">\n              <button\n                class="btn btn-success"\n                ng-show="vm.ngModel"\n                ng-click="vm.ngModel = false">\n                <i class="glyphicon glyphicon-ok"></i>\n              </button>\n              <button\n                class="btn btn-danger"\n                ng-show="!vm.ngModel"\n                ng-click="vm.ngModel = true">\n                <i class="glyphicon glyphicon-remove"></i>\n              </button>\n            </span>\n            <div\n              class="panel panel-default object-field"\n              ng-if="vm.field.type == \'object\' && (!vm.isEmptyObject(vm.ngModel) || !vm.isEmptyObject(vm.field.properties))"\n              >\n              <div class="panel-heading">{{vm.field.label}}</div>\n              <div class="panel-body">\n                <div ng-if="!vm.field.properties" ng-repeat="(k, v) in vm.ngModel">\n                  <xos-field\n                    name="k"\n                    field="{label: vm.formatLabel(k), type: vm.getType(v)}"\n                    ng-model="v">\n                  </xos-field>\n                </div>\n                <div ng-if="vm.field.properties" ng-repeat="(k, v) in vm.field.properties">\n                  <xos-field\n                    name="k"\n                    field="{\n                      label: v.label || vm.formatLabel(k),\n                      type: v.type,\n                      validators: v.validators\n                    }"\n                    ng-model="vm.ngModel[k]">\n                  </xos-field>\n                </div>\n              </div>\n            </div>\n      ',bindToController:!0,controllerAs:"vm",compile:function(n){return e.compile(n)},controller:["$attrs","XosFormHelpers","LabelFormatter",function(e,n,o){if(!this.name)throw new Error("[xosField] Please provide a field name");if(!this.field)throw new Error("[xosField] Please provide a field definition");if(!this.field.type)throw new Error("[xosField] Please provide a type in the field definition");if(!e.ngModel)throw new Error("[xosField] Please provide an ng-model");this.getType=n._getFieldFormat,this.formatLabel=o.format,this.isEmptyObject=function(e){return e?0===Object.keys(e).length:!0}}]}}])}(),function(){angular.module("xos.uiComponents").directive("xosAlert",function(){return{restrict:"E",scope:{config:"=",show:"=?"},template:'\n        <div ng-cloak class="alert alert-{{vm.config.type}}" ng-hide="!vm.show">\n          <button type="button" class="close" ng-if="vm.config.closeBtn" ng-click="vm.dismiss()">\n            <span aria-hidden="true">&times;</span>\n          </button>\n          <p ng-transclude></p>\n        </div>\n      ',transclude:!0,bindToController:!0,controllerAs:"vm",controller:["$timeout",function(e){var n=this;if(!this.config)throw new Error('[xosAlert] Please provide a configuration via the "config" attribute');this.show=this.show!==!1,this.dismiss=function(){n.show=!1},this.config.autoHide&&!function(){var o=e(function(){n.dismiss(),e.cancel(o)},n.config.autoHide)}()}]}})}(),function(){function e(){var e=function(e){return e.split("_").join(" ").trim()},n=function(e){return e.split(/(?=[A-Z])/).map(function(e){return e.toLowerCase()}).join(" ")},o=function(e){return e.slice(0,1).toUpperCase()+e.slice(1)},t=function(t){return t=e(t),t=n(t),t=o(t).replace(/\s\s+/g," ")+":",t.replace("::",":")};return{_formatByUnderscore:e,_formatByUppercase:n,_capitalize:o,format:t}}angular.module("xos.uiComponents").factory("LabelFormatter",e)}();var _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};!function(){angular.module("xos.uiComponents").service("XosFormHelpers",["_","LabelFormatter",function(e,n){var o=this;this._isEmail=function(e){var n=/(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/;return n.test(e)},this._getFieldFormat=function(n){return angular.isArray(n)?"array":e.isDate(n)||!Number.isNaN(Date.parse(n))&&new Date(n).getTime()>6311808e5?"date":"boolean"==typeof n?"boolean":o._isEmail(n)?"email":"string"==typeof n||null===n?"text":"undefined"==typeof n?"undefined":_typeof(n)},this.buildFormStructure=function(t,i,r){return t=angular.extend(t,i),i=i||{},e.reduce(Object.keys(t),function(e,t){return e[t]={label:i[t]&&i[t].label?i[t].label+":":n.format(t),type:i[t]&&i[t].type?i[t].type:o._getFieldFormat(r[t]),validators:i[t]&&i[t].validators?i[t].validators:{},hint:i[t]&&i[t].hint?i[t].hint:""},i[t]&&i[t].options&&(e[t].options=i[t].options),i[t]&&i[t].properties&&(e[t].properties=i[t].properties),"date"===e[t].type&&(r[t]=new Date(r[t])),"number"===e[t].type&&(r[t]=parseInt(r[t],10)),e},{})},this.parseModelField=function(n){return e.reduce(n,function(e,n){return e[n]={},e},{})}}])}(),function(){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){window.Bugsnag?Bugsnag.notifyException(e,{diagnostics:{cause:n}}):console.error(e,n,e.stack)}}),angular.module("xos.helpers",["ngCookies","ngResource","ngAnimate","bugSnag","xos.uiComponents"]).config(e).factory("_",["$window",function(e){return e._}])}(),function(){angular.module("xos.helpers").service("vSG-Collection",["$resource",function(e){return e("/api/service/vsg/")}])}(),function(){angular.module("xos.helpers").service("vOLT-Collection",["$resource",function(e){return e("/api/tenant/cord/volt/:volt_id/",{volt_id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Login",["$resource",function(e){return e("/api/utility/login/")}]).service("Logout",["$resource",function(e){return e("/api/utility/logout/")}])}(),function(){angular.module("xos.helpers").service("Users",["$resource",function(e){return e("/api/core/users/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Truckroll",["$resource",function(e){return e("/api/tenant/truckroll/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Tenants",["$resource",function(e){return e("/api/core/tenants/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Subscribers",["$resource",function(e){return e("/api/tenant/cord/subscriber/:id/",{id:"@id"},{update:{method:"PUT"},"View-a-Subscriber-Features-Detail":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/"},"Read-Subscriber-uplink_speed":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/uplink_speed/"},"Update-Subscriber-uplink_speed":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/uplink_speed/"},"Read-Subscriber-downlink_speed":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/downlink_speed/"},"Update-Subscriber-downlink_speed":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/downlink_speed/"},"Read-Subscriber-cdn":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/cdn/"},"Update-Subscriber-cdn":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/cdn/"},"Read-Subscriber-uverse":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/uverse/"},"Update-Subscriber-uverse":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/uverse/"},"Read-Subscriber-status":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/status/"},"Update-Subscriber-status":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/status/"}})}])}(),function(){angular.module("xos.helpers").service("SlicesPlus",["$http","$q",function(e,n){this.query=function(o){var t=n.defer();return e.get("/api/utility/slicesplus/",{params:o}).then(function(e){t.resolve(e.data)})["catch"](function(e){t.reject(e.data)}),{$promise:t.promise}},this.get=function(o,t){var i=n.defer();return e.get("/api/utility/slicesplus/"+o,{params:t}).then(function(e){i.resolve(e.data)})["catch"](function(e){i.reject(e.data)}),{$promise:i.promise}}}])}(),function(){angular.module("xos.helpers").service("Slices",["$resource",function(e){return e("/api/core/slices/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Sites",["$resource",function(e){return e("/api/core/sites/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Services",["$resource",function(e){return e("/api/core/services/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("ONOS-Services-Collection",["$resource",function(e){return e("/api/service/onos/")}])}(),function(){angular.module("xos.helpers").service("ONOS-App-Collection",["$resource",function(e){return e("/api/tenant/onos/app/")}])}(),function(){angular.module("xos.helpers").service("Nodes",["$resource",function(e){return e("/api/core/nodes/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Networks",["$resource",function(e){return e("/api/core/networks/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Instances",["$resource",function(e){return e("/api/core/instances/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Flavors",["$resource",function(e){return e("/api/core/flavors/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Example-Services-Collection",["$resource",function(e){return e("/api/service/exampleservice/")}])}(),function(){angular.module("xos.helpers").service("Deployments",["$resource",function(e){return e("/api/core/deployments/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("XosUserPrefs",["$cookies",function(e){var n=this,o=e.get("xosUserPrefs")?JSON.parse(e.get("xosUserPrefs")):{};this.getAll=function(){return o=e.get("xosUserPrefs")?JSON.parse(e.get("xosUserPrefs")):{}},this.setAll=function(n){e.put("xosUserPrefs",JSON.stringify(n))},this.getSynchronizerNotificationStatus=function(){var e=arguments.length<=0||void 0===arguments[0]?!1:arguments[0];return e?n.getAll().synchronizers.notification[e]:n.getAll().synchronizers.notification},this.setSynchronizerNotificationStatus=function(){var e=arguments.length<=0||void 0===arguments[0]?!1:arguments[0],o=arguments[1];if(!e)throw new Error("[XosUserPrefs] When updating a synchronizer is mandatory to provide a name.");var t=n.getAll();t.synchronizers||(t.synchronizers={notification:{}}),t.synchronizers.notification[e]=o,n.setAll(t)}}])}(),function(){angular.module("xos.helpers").service("GraphService",["$q","Tenants","Services",function(e,n,o){var t=this;this.loadCoarseData=function(){var t=void 0,i=e.defer();return o.query().$promise.then(function(e){return t=e,n.query({kind:"coarse"}).$promise}).then(function(e){i.resolve({tenants:e,services:t})}),i.promise},this.getCoarseGraph=function(){return t.loadCoarseData().then(function(e){console.log(e)}),"ciao"}}])}(),function(){angular.module("xos.helpers").factory("Notification",function(){return window.Notification}).service("xosNotification",["$q","$log","Notification",function(e,n,o){var t=this;this.checkPermission=function(){var n=e.defer();return o.requestPermission().then(function(e){"granted"===e?n.resolve(e):n.reject(e)}),n.promise},this.sendNotification=function(e,t){var i=new o(e,t);i.onerror=function(e){n.error(e)}},this.notify=function(e,i){"Notification"in window?"granted"!==o.permission?t.checkPermission().then(function(){return t.sendNotification(e,i)}):"granted"===o.permission&&t.sendNotification(e,i):n.info("This browser does not support desktop notification")}}])}(),function(){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)}(),angular.module("xos.helpers").config(["$provide",function(e){e.decorator("$log",["$delegate",function(e){var n=function(){return window.location.href.indexOf("debug=true")>=0},o=e.log,t=e.info,i=e.warn,r=e.error,s=e.debug,a=function(o){return function(){if(n()){var t=[].slice.call(arguments),i=new Date;t[0]="["+i.getHours()+":"+i.getMinutes()+":"+i.getSeconds()+"] "+t[0],"function"!=typeof e.reset||e.debug.logs instanceof Array||e.reset(),o.apply(null,t)}}};return e.info=a(t),e.log=a(o),e.warn=a(i),e.error=a(r),e.debug=a(s),e}])}]),function(){function e(){var e=function(e){return e.split("_").join(" ").trim()},n=function(e){return e.split(/(?=[A-Z])/).map(function(e){return e.toLowerCase()}).join(" ")},o=function(e){return e.slice(0,1).toUpperCase()+e.slice(1)},t=function(t){return t=e(t),t=n(t),t=o(t).replace(/\s\s+/g," ")+":",t.replace("::",":")};return{_formatByUnderscore:e,_formatByUppercase:n,_capitalize:o,format:t}}angular.module("xos.uiComponents").factory("LabelFormatter",e)}(),function(){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)}();
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/xosSynchronizerNotifier.js b/xos/core/xoslib/static/js/xosSynchronizerNotifier.js
index 894f9ea..5d743c6 100644
--- a/xos/core/xoslib/static/js/xosSynchronizerNotifier.js
+++ b/xos/core/xoslib/static/js/xosSynchronizerNotifier.js
@@ -1 +1 @@
-"use strict";angular.module("xos.synchronizerNotifier",["ngResource","ngCookies","ui.router","xos.helpers"]).service("Diag",["$rootScope","$http","$q","$interval",function(n,t,s,e){var a=this,i=!1;this.getDiags=function(){var n=s.defer();return t.get("/api/core/diags").then(function(t){n.resolve(t.data)})["catch"](function(t){n.reject(t)}),n.promise},this.sendEvents=function(t){t.forEach(function(t){var s=JSON.parse(t.backend_register);s.last_run=new Date(1e3*s.last_run),s.last_duration=1e3*s.last_duration,s.last_synchronizer_start=new Date(1e3*s.last_synchronizer_start),s.last_syncrecord_start=s.last_syncrecord_start?new Date(1e3*s.last_syncrecord_start):null,n.$broadcast("diag",{name:t.name,updated:t.updated,info:s,status:a.getSyncStatus(s)})})},this.start=function(){return i=!0,a.getDiags().then(function(n){a.sendEvents(n)}),i},this.stop=function(){return i=!1},this.getSyncStatus=function(n){var t=new Date,s=9e5;return!(t-n.last_synchronizer_start>s&&t-n.last_syncrecord_start>s&&t-n.last_run>s)},e(function(){i&&a.getDiags().then(function(n){a.sendEvents(n)})},3e5)}]).directive("syncStatus",function(){return{restrict:"E",scope:{},bindToController:!0,controllerAs:"vm",templateUrl:"templates/sync-status.tpl.html",controller:["$log","$rootScope","Diag","xosNotification","XosUserPrefs",function(n,t,s,e,a){var i=this;s.start(),this.synchronizers={},this.showNoSync=!0,t.$on("diag",function(n,t){i.synchronizers[t.name]=t,t.status?a.setSynchronizerNotificationStatus(t.name,!1):(a.getSynchronizerNotificationStatus(t.name)||e.notify("CORD Synchronizer",{icon:"/static/cord-logo.png",body:"The "+t.name+" synchronizer has not performed actions in the last 15 minutes."}),a.setSynchronizerNotificationStatus(t.name,!0)),i.showNoSync=!1,0===Object.keys(i.synchronizers).length&&(i.showNoSync=!0)})}]}}),angular.element(document).ready(function(){angular.bootstrap("#xosSynchronizerNotifier",["xos.synchronizerNotifier"])}),angular.module("xos.synchronizerNotifier").run(["$templateCache",function(n){n.put("templates/sync-status.tpl.html",'<div class="sync-status-container">\n  <div class="btn btn-default" ng-click="vm.showNotificationPanel = !vm.showNotificationPanel">\n    <i class="glyphicon glyphicon-inbox"></i>\n  </div>\n  <div class="notification-panel panel panel-default" ng-show="vm.showNotificationPanel">\n    <ul class="list-group" ng-show="!vm.showNoSync">\n      <li class="list-group-item" ng-repeat="(syncName, syncStatus) in vm.synchronizers">\n        <span class="badge" ng-class="{success: syncStatus.status, warning: !syncStatus.status}">\n          <span ng-show="syncStatus.status"><i class="glyphicon glyphicon-ok"></i></span>\n          <span ng-hide="syncStatus.status"><i class="glyphicon glyphicon-time"></i></span>\n        </span>\n        <b>{{syncName}}</b>\n        <br/>\n        <small><i>{{syncStatus.info.last_run | date:\'mediumTime\'}}</i></small>\n      </li>\n    </ul>\n    <div class="alert alert-info" ng-show="vm.showNoSync">\n      No syncronizers are running.\n    </div>\n  </div>\n</div>\n')}]),angular.module("xos.synchronizerNotifier").run(["$location",function(n){n.path("/")}]);
\ No newline at end of file
+"use strict";angular.module("xos.synchronizerNotifier",["ngResource","ngCookies","xos.helpers"]).run(["$rootScope",function(n){n.$on("$locationChangeStart",function(n){n.preventDefault()})}]).service("Diag",["$rootScope","$http","$q","$interval",function(n,t,s,e){var a=this,o=!1;this.getDiags=function(){var n=s.defer();return t.get("/api/core/diags").then(function(t){n.resolve(t.data)})["catch"](function(t){n.reject(t)}),n.promise},this.sendEvents=function(t){t.forEach(function(t){var s=JSON.parse(t.backend_register);s.last_run=new Date(1e3*s.last_run),s.last_duration=1e3*s.last_duration,s.last_synchronizer_start=new Date(1e3*s.last_synchronizer_start),s.last_syncrecord_start=s.last_syncrecord_start?new Date(1e3*s.last_syncrecord_start):null,n.$broadcast("diag",{name:t.name,updated:t.updated,info:s,status:a.getSyncStatus(s)})})},this.start=function(){return o=!0,a.getDiags().then(function(n){a.sendEvents(n)}),o},this.stop=function(){return o=!1},this.getSyncStatus=function(n){var t=new Date,s=9e5;return!(t-n.last_synchronizer_start>s&&t-n.last_syncrecord_start>s&&t-n.last_run>s)},e(function(){o&&a.getDiags().then(function(n){a.sendEvents(n)})},3e5)}]).directive("syncStatus",function(){return{restrict:"E",scope:{},bindToController:!0,controllerAs:"vm",templateUrl:"templates/sync-status.tpl.html",controller:["$log","$rootScope","Diag","xosNotification","XosUserPrefs",function(n,t,s,e,a){var o=this;s.start(),this.synchronizers={},this.showNoSync=!0,t.$on("diag",function(n,t){o.synchronizers[t.name]=t,t.status?a.setSynchronizerNotificationStatus(t.name,!1):(a.getSynchronizerNotificationStatus(t.name)||e.notify("CORD Synchronizer",{icon:"/static/cord-logo.png",body:"The "+t.name+" synchronizer has not performed actions in the last 15 minutes."}),a.setSynchronizerNotificationStatus(t.name,!0)),o.showNoSync=!1,0===Object.keys(o.synchronizers).length&&(o.showNoSync=!0)})}]}}),angular.element(document).ready(function(){angular.bootstrap("#xosSynchronizerNotifier",["xos.synchronizerNotifier"])}),angular.module("xos.synchronizerNotifier").run(["$templateCache",function(n){n.put("templates/sync-status.tpl.html",'<div class="sync-status-container">\n  <div class="btn btn-default" ng-click="vm.showNotificationPanel = !vm.showNotificationPanel">\n    <i class="glyphicon glyphicon-inbox"></i>\n  </div>\n  <div class="notification-panel panel panel-default" ng-show="vm.showNotificationPanel">\n    <ul class="list-group" ng-show="!vm.showNoSync">\n      <li class="list-group-item" ng-repeat="(syncName, syncStatus) in vm.synchronizers">\n        <span class="badge" ng-class="{success: syncStatus.status, warning: !syncStatus.status}">\n          <span ng-show="syncStatus.status"><i class="glyphicon glyphicon-ok"></i></span>\n          <span ng-hide="syncStatus.status"><i class="glyphicon glyphicon-time"></i></span>\n        </span>\n        <b>{{syncName}}</b>\n        <br/>\n        <small><i>{{syncStatus.info.last_run | date:\'mediumTime\'}}</i></small>\n      </li>\n    </ul>\n    <div class="alert alert-info" ng-show="vm.showNoSync">\n      No syncronizers are running.\n    </div>\n  </div>\n</div>\n')}]),angular.module("xos.synchronizerNotifier").run(["$location",function(n){n.path("/")}]);
\ No newline at end of file
diff --git a/xos/onboard/README.md b/xos/onboard/README.md
new file mode 100644
index 0000000..2030708
--- /dev/null
+++ b/xos/onboard/README.md
@@ -0,0 +1,3 @@
+This directory is a temporary placeholder for services that can be on-boarded. 
+
+Once we move to Gerritt and service-per-repo, this directory will be removed.
diff --git a/xos/services/exampleservice/admin.py b/xos/onboard/exampleservice/admin.py
similarity index 100%
rename from xos/services/exampleservice/admin.py
rename to xos/onboard/exampleservice/admin.py
diff --git a/xos/api/service/exampleservice.py b/xos/onboard/exampleservice/api/service/exampleservice.py
similarity index 100%
rename from xos/api/service/exampleservice.py
rename to xos/onboard/exampleservice/api/service/exampleservice.py
diff --git a/xos/api/tenant/exampletenant.py b/xos/onboard/exampleservice/api/tenant/exampletenant.py
similarity index 100%
rename from xos/api/tenant/exampletenant.py
rename to xos/onboard/exampleservice/api/tenant/exampletenant.py
diff --git a/xos/onboard/exampleservice/exampleservice-onboard-longform.yaml b/xos/onboard/exampleservice/exampleservice-onboard-longform.yaml
new file mode 100644
index 0000000..0eddd51
--- /dev/null
+++ b/xos/onboard/exampleservice/exampleservice-onboard-longform.yaml
@@ -0,0 +1,57 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Onboard the exampleservice
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    exampleservice:
+      type: tosca.nodes.ServiceController
+      properties:
+          base_url: file:/opt/xos/onboard/exampleservice/
+
+    exampleservice_models:
+      type: tosca.nodes.ServiceControllerResource
+      properties:
+          kind: models
+          format: python
+          url: models.py
+      requirements:
+          - controller:
+              node: exampleservice
+              relationship: tosca.relationships.UsedByController
+
+    exampleservice_admin:
+      type: tosca.nodes.ServiceControllerResource
+      properties:
+          kind: admin
+          format: python
+          url: admin.py
+      requirements:
+          - controller:
+              node: exampleservice
+              relationship: tosca.relationships.UsedByController
+
+    exampleservice_synchronizer:
+      type: tosca.nodes.ServiceControllerResource
+      properties:
+          kind: synchronizer
+          format: manifest
+          url: synchronizer/manifest
+      requirements:
+          - controller:
+              node: exampleservice
+              relationship: tosca.relationships.UsedByController
+
+    exampleservice_tosca_types:
+      type: tosca.nodes.ServiceControllerResource
+      properties:
+          kind: tosca_custom_types
+          format: yaml
+          url: exampleservice.yaml
+      requirements:
+          - controller:
+              node: exampleservice
+              relationship: tosca.relationships.UsedByController
diff --git a/xos/onboard/exampleservice/exampleservice-onboard.yaml b/xos/onboard/exampleservice/exampleservice-onboard.yaml
new file mode 100644
index 0000000..91dbb2e
--- /dev/null
+++ b/xos/onboard/exampleservice/exampleservice-onboard.yaml
@@ -0,0 +1,24 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Onboard the exampleservice
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    exampleservice:
+      type: tosca.nodes.ServiceController
+      properties:
+          base_url: file:///opt/xos/onboard/exampleservice/
+          # The following will concatenate with base_url automatically, if
+          # base_url is non-null.
+          models: models.py
+          admin: admin.py
+          synchronizer: synchronizer/manifest
+          tosca_custom_types: exampleservice.yaml
+          rest_service: api/service/exampleservice.py
+          rest_tenant: api/tenant/exampletenant.py
+          private_key: file:///opt/xos/key_import/exampleservice_rsa
+          public_key: file:///opt/xos/key_import/exampleservice_rsa.pub
+
diff --git a/xos/tosca/custom_types/exampleservice.m4 b/xos/onboard/exampleservice/exampleservice.m4
similarity index 100%
rename from xos/tosca/custom_types/exampleservice.m4
rename to xos/onboard/exampleservice/exampleservice.m4
diff --git a/xos/tosca/custom_types/exampleservice.yaml b/xos/onboard/exampleservice/exampleservice.yaml
similarity index 100%
rename from xos/tosca/custom_types/exampleservice.yaml
rename to xos/onboard/exampleservice/exampleservice.yaml
diff --git a/xos/onboard/exampleservice/macros.m4 b/xos/onboard/exampleservice/macros.m4
new file mode 100644
index 0000000..1f48f10
--- /dev/null
+++ b/xos/onboard/exampleservice/macros.m4
@@ -0,0 +1,84 @@
+# Note: Tosca derived_from isn't working the way I think it should, it's not
+#    inheriting from the parent template. Until we get that figured out, use
+#    m4 macros do our inheritance
+
+define(xos_base_props,
+            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
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object)
+# Service
+define(xos_base_service_caps,
+            scalable:
+                type: tosca.capabilities.Scalable
+            service:
+                type: tosca.capabilities.xos.Service)
+define(xos_base_service_props,
+            kind:
+                type: string
+                default: generic
+                description: Type of service.
+            view_url:
+                type: string
+                required: false
+                description: URL to follow when icon is clicked in the Service Directory.
+            icon_url:
+                type: string
+                required: false
+                description: ICON to display in the Service Directory.
+            enabled:
+                type: boolean
+                default: true
+            published:
+                type: boolean
+                default: true
+                description: If True then display this Service in the Service Directory.
+            public_key:
+                type: string
+                required: false
+                description: Public key to install into Instances to allows Services to SSH into them.
+            private_key_fn:
+                type: string
+                required: false
+                description: Location of private key file
+            versionNumber:
+                type: string
+                required: false
+                description: Version number of Service.)
+# Subscriber
+define(xos_base_subscriber_caps,
+            subscriber:
+                type: tosca.capabilities.xos.Subscriber)
+define(xos_base_subscriber_props,
+            kind:
+                type: string
+                default: generic
+                description: Kind of subscriber
+            service_specific_id:
+                type: string
+                required: false
+                description: Service specific ID opaque to XOS but meaningful to service)
+define(xos_base_tenant_props,
+            kind:
+                type: string
+                default: generic
+                description: Kind of tenant
+            service_specific_id:
+                type: string
+                required: false
+                description: Service specific ID opaque to XOS but meaningful to service)
+
+# end m4 macros
+
diff --git a/xos/onboard/exampleservice/make_synchronizer_manifest.sh b/xos/onboard/exampleservice/make_synchronizer_manifest.sh
new file mode 100644
index 0000000..4058982
--- /dev/null
+++ b/xos/onboard/exampleservice/make_synchronizer_manifest.sh
@@ -0,0 +1,2 @@
+#! /bin/bash
+find synchronizer -type f | cut -b 14- > synchronizer/manifest 
diff --git a/xos/services/exampleservice/models.py b/xos/onboard/exampleservice/models.py
similarity index 100%
rename from xos/services/exampleservice/models.py
rename to xos/onboard/exampleservice/models.py
diff --git a/xos/synchronizers/exampleservice/exampleservice-synchronizer.py b/xos/onboard/exampleservice/synchronizer/exampleservice-synchronizer.py
similarity index 100%
copy from xos/synchronizers/exampleservice/exampleservice-synchronizer.py
copy to xos/onboard/exampleservice/synchronizer/exampleservice-synchronizer.py
diff --git a/xos/synchronizers/exampleservice/exampleservice_config b/xos/onboard/exampleservice/synchronizer/exampleservice_config
similarity index 100%
copy from xos/synchronizers/exampleservice/exampleservice_config
copy to xos/onboard/exampleservice/synchronizer/exampleservice_config
diff --git a/xos/onboard/exampleservice/synchronizer/manifest b/xos/onboard/exampleservice/synchronizer/manifest
new file mode 100644
index 0000000..8f43610
--- /dev/null
+++ b/xos/onboard/exampleservice/synchronizer/manifest
@@ -0,0 +1,10 @@
+manifest
+steps/sync_exampletenant.py
+steps/roles/install_apache/tasks/main.yml
+steps/roles/create_index/templates/index.html.j2
+steps/roles/create_index/tasks/main.yml
+steps/exampletenant_playbook.yaml
+exampleservice-synchronizer.py
+model-deps
+run.sh
+exampleservice_config
diff --git a/xos/synchronizers/exampleservice/model-deps b/xos/onboard/exampleservice/synchronizer/model-deps
similarity index 100%
copy from xos/synchronizers/exampleservice/model-deps
copy to xos/onboard/exampleservice/synchronizer/model-deps
diff --git a/xos/onboard/exampleservice/synchronizer/run.sh b/xos/onboard/exampleservice/synchronizer/run.sh
new file mode 100755
index 0000000..e6da8f6
--- /dev/null
+++ b/xos/onboard/exampleservice/synchronizer/run.sh
@@ -0,0 +1,2 @@
+export XOS_DIR=/opt/xos
+python exampleservice-synchronizer.py  -C $XOS_DIR/synchronizers/exampleservice/exampleservice_config
diff --git a/xos/synchronizers/exampleservice/steps/exampletenant_playbook.yaml b/xos/onboard/exampleservice/synchronizer/steps/exampletenant_playbook.yaml
similarity index 100%
copy from xos/synchronizers/exampleservice/steps/exampletenant_playbook.yaml
copy to xos/onboard/exampleservice/synchronizer/steps/exampletenant_playbook.yaml
diff --git a/xos/synchronizers/exampleservice/steps/roles/create_index/tasks/main.yml b/xos/onboard/exampleservice/synchronizer/steps/roles/create_index/tasks/main.yml
similarity index 100%
copy from xos/synchronizers/exampleservice/steps/roles/create_index/tasks/main.yml
copy to xos/onboard/exampleservice/synchronizer/steps/roles/create_index/tasks/main.yml
diff --git a/xos/synchronizers/exampleservice/steps/roles/create_index/templates/index.html.j2 b/xos/onboard/exampleservice/synchronizer/steps/roles/create_index/templates/index.html.j2
similarity index 100%
copy from xos/synchronizers/exampleservice/steps/roles/create_index/templates/index.html.j2
copy to xos/onboard/exampleservice/synchronizer/steps/roles/create_index/templates/index.html.j2
diff --git a/xos/synchronizers/exampleservice/steps/roles/install_apache/tasks/main.yml b/xos/onboard/exampleservice/synchronizer/steps/roles/install_apache/tasks/main.yml
similarity index 100%
copy from xos/synchronizers/exampleservice/steps/roles/install_apache/tasks/main.yml
copy to xos/onboard/exampleservice/synchronizer/steps/roles/install_apache/tasks/main.yml
diff --git a/xos/synchronizers/exampleservice/steps/sync_exampletenant.py b/xos/onboard/exampleservice/synchronizer/steps/sync_exampletenant.py
similarity index 100%
copy from xos/synchronizers/exampleservice/steps/sync_exampletenant.py
copy to xos/onboard/exampleservice/synchronizer/steps/sync_exampletenant.py
diff --git a/xos/services/exampleservice/README.md b/xos/services/exampleservice/README.md
deleted file mode 100644
index ce6210d..0000000
--- a/xos/services/exampleservice/README.md
+++ /dev/null
@@ -1,8 +0,0 @@
-# ExampleService
-
-This is an example XOS service, specifically the Django Model and Admin. 
-
-The Synchronizer corresponding to this service can be found in `../../synchronizers/exampleservice`.
-
-Documentation for this is located here: [XOS Guide : DevGuide : ExampleService](http://guide.xosproject.org/devguide/exampleservice/).
-
diff --git a/xos/services/mcord/admin.py b/xos/services/mcord/admin.py
index b496ef7..ee19c7e 100644
--- a/xos/services/mcord/admin.py
+++ b/xos/services/mcord/admin.py
@@ -4,7 +4,7 @@
 from core.models import User
 from django import forms
 from django.contrib import admin
-from services.mcord.models import MCORDService, VBBUComponent, MCORD_KIND
+from services.mcord.models import MCORDService, VBBUComponent, VPGWCComponent, MCORD_KIND
 
 # The class to provide an admin interface on the web for the service.
 # We do only configuration here and don't change any logic because the logic
@@ -114,6 +114,55 @@
     class Meta:
         model = VBBUComponent
 
+# Class to represent the form to add and edit tenants.
+# We need to define this instead of just using an admin like we did for the
+# service because tenants vary more than services and there isn't a common form.
+# This allows us to change the python behavior for the admin form to save extra
+# fields and control defaults.
+class VPGWCComponentForm(forms.ModelForm):
+    # Defines a field for the creator of this service. It is a dropdown which
+    # is populated with all of the users.
+    creator = forms.ModelChoiceField(queryset=User.objects.all())
+    # Defines a text field for the display message, it is not required.
+    display_message = forms.CharField(required=False)
+
+    def __init__(self, *args, **kwargs):
+        super(VPGWCComponentForm, self).__init__(*args, **kwargs)
+        # Set the kind field to readonly
+        self.fields['kind'].widget.attrs['readonly'] = True
+        # Define the logic for obtaining the objects for the provider_service
+        # dropdown of the tenant form.
+        self.fields[
+            'provider_service'].queryset = MCORDService.get_service_objects().all()
+        # Set the initial kind to HELLO_WORLD_KIND for this tenant.
+        self.fields['kind'].initial = MCORD_KIND
+        # If there is an instance of this model then we can set the initial
+        # form values to the existing values.
+        if self.instance:
+            self.fields['creator'].initial = self.instance.creator
+            self.fields[
+                'display_message'].initial = self.instance.display_message
+
+        # If there is not an instance then we need to set initial values.
+        if (not self.instance) or (not self.instance.pk):
+            self.fields['creator'].initial = get_request().user
+            if MCORDService.get_service_objects().exists():
+                self.fields["provider_service"].initial = MCORDService.get_service_objects().all()[0]
+
+    # This function describes what happens when the save button is pressed on
+    # the tenant form. In this case we set the values for the instance that were
+    # entered.
+    def save(self, commit=True):
+        self.instance.creator = self.cleaned_data.get("creator")
+        self.instance.display_message = self.cleaned_data.get(
+            "display_message")
+        return super(VPGWCComponentForm, self).save(commit=commit)
+
+    class Meta:
+        model = VPGWCComponent
+
+
+
 # Define the admin form for the tenant. This uses a similar structure as the
 # service but uses HelloWorldTenantCompleteForm to change the python behavior.
 
@@ -136,6 +185,28 @@
     def queryset(self, request):
         return VBBUComponent.get_tenant_objects_by_user(request.user)
 
+
+# Define the admin form for the tenant. This uses a similar structure as the
+# service but uses HelloWorldTenantCompleteForm to change the python behavior.
+class VPGWCComponentAdmin(ReadOnlyAwareAdmin):
+    verbose_name = "vPGWC Component"
+    verbose_name_plural = "vPGWC Components"
+    list_display = ('id', 'backend_status_icon', 'instance', 'display_message')
+    list_display_links = ('backend_status_icon', 'instance', 'display_message',
+                          'id')
+    fieldsets = [(None, {'fields': ['backend_status_text', 'kind',
+                                    'provider_service', 'instance', 'creator',
+                                    'display_message'],
+                         'classes': ['suit-tab suit-tab-general']})]
+    readonly_fields = ('backend_status_text', 'instance',)
+    form = VPGWCComponentForm
+
+    suit_form_tabs = (('general', 'Details'),)
+
+    def queryset(self, request):
+        return VPGWCComponent.get_tenant_objects_by_user(request.user)
+
 # Associate the admin forms with the models.
 admin.site.register(MCORDService, MCORDServiceAdmin)
 admin.site.register(VBBUComponent, VBBUComponentAdmin)
+admin.site.register(VPGWCComponent, VPGWCComponentAdmin)
diff --git a/xos/services/mcord/models.py b/xos/services/mcord/models.py
index 1b2bd65..6d070d8 100644
--- a/xos/services/mcord/models.py
+++ b/xos/services/mcord/models.py
@@ -18,8 +18,9 @@
 MCORD_USE_VTN = getattr(Config(), "networking_use_vtn", False)
 VBBU_KIND = "RAN"
 VSGW_KIND = "vSGW"
-VPGW_KIND = "vPGW"
-net_types = ("s1u", "s1mme", "rru")
+VPGWC_KIND = "RAN"
+vbbu_net_types = ("s1u", "s1mme", "rru")
+vpgwc_net_types = ("s5s8")
 # The class to represent the service. Most of the service logic is given for us
 # in the Service class but, we have some configuration that is specific for
 # this example.
@@ -91,7 +92,7 @@
         with transaction.atomic():
             super(VBBUComponent, self).save_instance(instance)
             if instance.isolation in ["vm"]:
-                for ntype in net_types:
+                for ntype in vbbu_net_types:
                     lan_network = self.get_lan_network(instance, ntype)
                     port = self.find_or_make_port(instance,lan_network)
                     if (ntype == "s1u"):
@@ -271,6 +272,193 @@
     def rru_mac(self):
         return self.addresses.get("rru", (None, None))[1]
 
+
+# This is the class to represent the tenant. Most of the logic is given to use
+# in TenantWithContainer, however there is some configuration and logic that
+# we need to define for this example.
+class VPGWCComponent(TenantWithContainer):
+
+    class Meta:
+        # Same as a above, HelloWorldTenantComplete is represented as a
+        # TenantWithContainer, but we change the python behavior.
+        proxy = True
+        verbose_name = "VPGWC MCORD Service Component"
+
+    # The kind of the service is used on forms to differentiate this service
+    # from the other services.
+    KIND = VPGWC_KIND
+
+    # Ansible requires that the sync_attributes field contain nat_ip and nat_mac
+    # these will be used to determine where to SSH to for ansible.
+    # Getters must be defined for every attribute specified here.
+    sync_attributes = ("s5s8_pgw_ip", "s5s8_pgw_mac")
+
+    # default_attributes is used cleanly indicate what the default values for
+    # the fields are.
+    default_attributes = {"display_message": "New vPGWC Component", "s5s8_pgw_tag": "300"}
+    def __init__(self, *args, **kwargs):
+        mcord_services = MCORDService.get_service_objects().all()
+        # When the tenant is created the default service in the form is set
+        # to be the first created HelloWorldServiceComplete
+        if mcord_services:
+            self._meta.get_field(
+                "provider_service").default = mcord_services[0].id
+        super(VPGWCComponent, self).__init__(*args, **kwargs)
+
+    def can_update(self, user):
+        #Allow creation of this model instances for non-admin users also
+        return True
+
+    def save(self, *args, **kwargs):
+        if not self.creator:
+            if not getattr(self, "caller", None):
+                # caller must be set when creating a monitoring channel since it creates a slice
+                raise XOSProgrammingError("ServiceComponents's self.caller was not set")
+            self.creator = self.caller
+            if not self.creator:
+                raise XOSProgrammingError("ServiceComponents's self.creator was not set")
+
+        super(VPGWCComponent, self).save(*args, **kwargs)
+        # This call needs to happen so that an instance is created for this
+        # tenant is created in the slice. One instance is created per tenant.
+        model_policy_mcord_servicecomponent(self.pk)
+
+    def save_instance(self, instance):
+        with transaction.atomic():
+            super(VPGWCComponent, self).save_instance(instance)
+            if instance.isolation in ["vm"]:
+                for ntype in vpgwc_net_types:
+                    lan_network = self.get_lan_network(instance, ntype)
+                    port = self.find_or_make_port(instance,lan_network)
+                    if (ntype == "s5s8"):
+                        port.set_parameter("s_tag", self.s5s8_pgw_tag)
+                        port.set_parameter("neutron_port_name", "stag-%s" % self.s5s8_pgw_tag)
+                        port.save()
+                    else:
+			return True
+
+    def delete(self, *args, **kwargs):
+        # Delete the instance that was created for this tenant
+        self.cleanup_container()
+        super(VPGWCComponent, self).delete(*args, **kwargs)
+
+    def find_or_make_port(self, instance, network, **kwargs):
+        port = Port.objects.filter(instance=instance, network=network)
+        if port:
+            port = port[0]
+            print "port already exist", port[0]
+        else:
+            port = Port(instance=instance, network=network, **kwargs)
+            print "NETWORK", network, "MAKE_PORT", port 
+            port.save()
+        return port
+
+    def get_lan_network(self, instance, ntype):
+        slice = self.provider_service.slices.all()[0]
+        lan_networks = [x for x in slice.networks.all() if ntype in x.name]
+        if not lan_networks:
+            raise XOSProgrammingError("No lan_network")
+        return lan_networks[0]
+
+    def manage_container(self):
+        from core.models import Instance, Flavor
+
+        if self.deleted:
+            return
+
+        # For container or container_vm isolation, use what TenantWithCotnainer
+        # provides us
+        slice = self.get_slice()
+        if slice.default_isolation in ["container_vm", "container"]:
+            super(VPGWCComponent,self).manage_container()
+            return
+
+        if not self.s5s8_pgw_tag:
+            raise XOSConfigurationError("S5S8_PGW_TAG is missed")
+
+        if self.instance:
+            # We're good.
+            return
+
+        instance = self.make_instance()
+        self.instance = instance
+        super(TenantWithContainer, self).save()
+
+    def get_slice(self):
+        if not self.provider_service.slices.count():
+            raise XOSConfigurationError("The service has no slices")
+        slice = self.provider_service.slices.all()[0]
+        return slice
+
+    def make_instance(self):
+        slice = self.provider_service.slices.all()[0]            
+        flavors = Flavor.objects.filter(name=slice.default_flavor)
+#        flavors = Flavor.objects.filter(name="m1.xlarge")
+        if not flavors:
+            raise XOSConfigurationError("No default flavor")
+        default_flavor = slice.default_flavor
+        slice = self.provider_service.slices.all()[0]
+        if slice.default_isolation == "container_vm":
+            (node, parent) = ContainerVmScheduler(slice).pick()
+        else:
+            (node, parent) = LeastLoadedNodeScheduler(slice).pick()
+        instance = Instance(slice = slice,
+                        node = node,
+                        image = self.image,
+                        creator = self.creator,
+                        deployment = node.site_deployment.deployment,
+                        flavor = flavors[0],
+                        isolation = slice.default_isolation,
+                        parent = parent)
+        self.save_instance(instance)
+        return instance
+
+    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))
+
+    # Getter for the message that will appear on the webpage
+    # By default it is "Hello World!"
+    @property
+    def display_message(self):
+        return self.get_attribute(
+            "display_message",
+            self.default_attributes['display_message'])
+
+    @display_message.setter
+    def display_message(self, value):
+        self.set_attribute("display_message", value)
+
+    @property
+    def s5s8_pgw_tag(self):
+        return self.get_attribute(
+            "s5s8_pgw_tag",
+            self.default_attributes['s5s8_pgw_tag'])
+
+    @s5s8_pgw_tag.setter
+    def s5s8_pgw_tag(self, value):
+        self.set_attribute("s5s8_pgw_tag", value)
+
+
+    @property
+    def addresses(self):
+        if (not self.id) or (not self.instance):
+            return {}
+
+        addresses = {}
+        for ns in self.instance.ports.all():
+            if "s5s8_pgw" in ns.network.name.lower():
+                addresses["s5s8_pgw"] = (ns.ip, ns.mac)
+        return addresses
+
+
+    @property
+    def s5s8_pgw_ip(self):
+        return self.addresses.get("s5s8_pgw", (None, None))[0]
+    @property
+    def s5s8_pgw_mac(self):
+        return self.addresses.get("s5s8_pgw", (None, None))[1]
+
 def model_policy_mcord_servicecomponent(pk):
     # This section of code is atomic to prevent race conditions
     with transaction.atomic():
@@ -281,3 +469,15 @@
         # Since this code is atomic it is safe to always use the first tenant
         component = component[0]
         component.manage_container()
+
+
+def model_policy_mcord_servicecomponent(pk):
+    # This section of code is atomic to prevent race conditions
+    with transaction.atomic():
+        # We find all of the tenants that are waiting to update
+        component = VPGWCComponent.objects.select_for_update().filter(pk=pk)
+        if not component:
+            return
+        # Since this code is atomic it is safe to always use the first tenant
+        component = component[0]
+        component.manage_container()
diff --git a/xos/synchronizers/base/SyncInstanceUsingAnsible.py b/xos/synchronizers/base/SyncInstanceUsingAnsible.py
index fef8f86..49ca23b 100644
--- a/xos/synchronizers/base/SyncInstanceUsingAnsible.py
+++ b/xos/synchronizers/base/SyncInstanceUsingAnsible.py
@@ -21,7 +21,6 @@
     # observes=VSGTenant
     # 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)
@@ -96,7 +95,10 @@
                        "username": "ubuntu",
                        "ssh_ip": instance.get_ssh_ip(),
                      }
-            key_name = self.service_key_name
+            if (instance.slice) and (instance.slice.service) and (instance.slice.service.private_key_fn):
+                key_name = instance.slice.service.private_key_fn
+            else:
+                raise Exception("Make sure to set private_key_fn in the service")
         elif (instance.isolation == "container"):
             # container on bare metal
             node = self.get_node(instance)
diff --git a/xos/synchronizers/base/event_loop.py b/xos/synchronizers/base/event_loop.py
index 37ec4ca..ae97329 100644
--- a/xos/synchronizers/base/event_loop.py
+++ b/xos/synchronizers/base/event_loop.py
@@ -9,6 +9,7 @@
 import json
 import pdb
 import pprint
+import traceback
 
 
 from datetime import datetime
@@ -349,9 +350,11 @@
 				if (step_status[d] is STEP_STATUS_WORKING):
                                         logger.info("  step %s wait on dep %s" % (step.__name__, d))
 					cond.wait()
+                                        logger.info("  step %s wait on dep %s cond returned" % (step.__name__, d))
 				elif step_status[d] == STEP_STATUS_OK:
 					go = True
 				else:
+                                        logger.info("  step %s has failed dep %s" % (step.__name__, d))
 					go = False
                         		failed_dep = d
 				cond.release()
@@ -361,6 +364,7 @@
 			go = True
 
 		if (not go):
+                        logger.info("Step %s skipped" % step.__name__)
                         self.consolePrint(bcolors.FAIL + "Step %r skipped on %r" % (step,failed_dep) + bcolors.ENDC)
                         # SMBAKER: sync_step was not defined here, so I changed
                         #    this from 'sync_step' to 'step'. Verify.
@@ -416,7 +420,7 @@
 					if failed_objects:
 						self.failed_step_objects.update(failed_objects)
 
-                                        logger.info("Step %r succeeded" % sync_step.__name__)
+                                        logger.info("Step %r succeeded, deletion=%s" % (sync_step.__name__, deletion))
                                         self.consolePrint(bcolors.OKGREEN + "Step %r succeeded" % sync_step.__name__ + bcolors.ENDC)
 					my_status = STEP_STATUS_OK
 					self.update_run_time(sync_step,deletion)
@@ -462,8 +466,27 @@
 
                     self.run_once()
 
+        def check_db_connection_okay(self):
+            # django implodes if the database connection is closed by docker-compose
+            try:
+                diag = Diag.objects.filter(name="foo").first()
+            except Exception, e:
+                from django import db
+                if "connection already closed" in traceback.format_exc():
+                   logger.error("XXX connection already closed")
+                   try:
+#                       if db.connection:
+#                           db.connection.close()
+                       db.close_connection()
+                   except:
+                        logger.log_exc("XXX we failed to fix the failure")
+                else:
+                   logger.log_exc("XXX some other error")
+
         def run_once(self):
                 try:
+                        self.check_db_connection_okay()
+
                         loop_start = time.time()
                         error_map_file = getattr(Config(), "error_map_path", XOS_DIR + "/error_map.txt")
                         self.error_mapper = ErrorMapper(error_map_file)
@@ -499,7 +522,7 @@
                                 schedule = self.ordered_steps if not deletion else reversed(self.ordered_steps)
 
                                 for S in schedule:
-                                        thread = threading.Thread(target=self.sync, args=(S, deletion))
+                                        thread = threading.Thread(target=self.sync, name='synchronizer', args=(S, deletion))
 
                                         logger.info('Deletion=%r...'%deletion)
                                         threads.append(thread)
diff --git a/xos/synchronizers/base/syncstep.py b/xos/synchronizers/base/syncstep.py
index 2fa6c38..eeb61db 100644
--- a/xos/synchronizers/base/syncstep.py
+++ b/xos/synchronizers/base/syncstep.py
@@ -141,6 +141,8 @@
 
 
     def sync_record(self, o):
+        logger.info("Sync_record called for %s %s" % (o.__class__.__name__, str(o)))
+
         try:
             controller = o.get_controller()
             controller_register = json.loads(controller.backend_register)
diff --git a/xos/synchronizers/exampleservice/exampleservice-synchronizer.py b/xos/synchronizers/exampleservice_old/exampleservice-synchronizer.py
similarity index 100%
rename from xos/synchronizers/exampleservice/exampleservice-synchronizer.py
rename to xos/synchronizers/exampleservice_old/exampleservice-synchronizer.py
diff --git a/xos/synchronizers/exampleservice/exampleservice_config b/xos/synchronizers/exampleservice_old/exampleservice_config
similarity index 100%
rename from xos/synchronizers/exampleservice/exampleservice_config
rename to xos/synchronizers/exampleservice_old/exampleservice_config
diff --git a/xos/synchronizers/exampleservice/model-deps b/xos/synchronizers/exampleservice_old/model-deps
similarity index 100%
rename from xos/synchronizers/exampleservice/model-deps
rename to xos/synchronizers/exampleservice_old/model-deps
diff --git a/xos/synchronizers/exampleservice/steps/exampletenant_playbook.yaml b/xos/synchronizers/exampleservice_old/steps/exampletenant_playbook.yaml
similarity index 100%
rename from xos/synchronizers/exampleservice/steps/exampletenant_playbook.yaml
rename to xos/synchronizers/exampleservice_old/steps/exampletenant_playbook.yaml
diff --git a/xos/synchronizers/exampleservice/steps/roles/create_index/tasks/main.yml b/xos/synchronizers/exampleservice_old/steps/roles/create_index/tasks/main.yml
similarity index 100%
rename from xos/synchronizers/exampleservice/steps/roles/create_index/tasks/main.yml
rename to xos/synchronizers/exampleservice_old/steps/roles/create_index/tasks/main.yml
diff --git a/xos/synchronizers/exampleservice/steps/roles/create_index/templates/index.html.j2 b/xos/synchronizers/exampleservice_old/steps/roles/create_index/templates/index.html.j2
similarity index 100%
rename from xos/synchronizers/exampleservice/steps/roles/create_index/templates/index.html.j2
rename to xos/synchronizers/exampleservice_old/steps/roles/create_index/templates/index.html.j2
diff --git a/xos/synchronizers/exampleservice/steps/roles/install_apache/tasks/main.yml b/xos/synchronizers/exampleservice_old/steps/roles/install_apache/tasks/main.yml
similarity index 100%
rename from xos/synchronizers/exampleservice/steps/roles/install_apache/tasks/main.yml
rename to xos/synchronizers/exampleservice_old/steps/roles/install_apache/tasks/main.yml
diff --git a/xos/synchronizers/exampleservice/steps/sync_exampletenant.py b/xos/synchronizers/exampleservice_old/steps/sync_exampletenant.py
similarity index 100%
rename from xos/synchronizers/exampleservice/steps/sync_exampletenant.py
rename to xos/synchronizers/exampleservice_old/steps/sync_exampletenant.py
diff --git a/xos/synchronizers/model_policy.py b/xos/synchronizers/model_policy.py
index ef31d41..aa12092 100644
--- a/xos/synchronizers/model_policy.py
+++ b/xos/synchronizers/model_policy.py
@@ -3,10 +3,11 @@
 import pdb
 from generate.dependency_walker import *
 from synchronizers.openstack import model_policies
-from xos.logger import logger
+from xos.logger import Logger, logging
 from datetime import datetime
 from django.utils import timezone
 import time
+import traceback
 from core.models import *
 from django.db import reset_queries
 from django.db.transaction import atomic
@@ -15,6 +16,8 @@
 modelPolicyEnabled = True
 bad_instances=[]
 
+logger = Logger(level=logging.INFO)
+
 def EnableModelPolicy(x):
     global modelPolicyEnabled
     modelPolicyEnabled = x
@@ -40,9 +43,10 @@
         if (save_fields):
             d.save(update_fields=save_fields)
     except AttributeError,e:
+        logger.log_exc("AttributeError in update_dep")
         raise e
     except Exception,e:
-            logger.info('Could not save %r. Exception: %r'%(d,e), extra=d.tologdict())
+        logger.log_exc("Exception in update_dep")
 
 def delete_if_inactive(d, o):
     try:
@@ -75,7 +79,7 @@
 
     try:
         policy_handler = getattr(model_policies, policy_name, None)
-        logger.error("POLICY HANDLER: %s %s" % (policy_name, policy_handler))
+        logger.info("MODEL POLICY: handler %s %s" % (policy_name, policy_handler))
         if policy_handler is not None:
             if (deleted):
                 try:
@@ -84,23 +88,45 @@
                     pass
             else:
                 policy_handler.handle(instance)
+        logger.info("MODEL POLICY: completed handler %s %s" % (policy_name, policy_handler))
     except:
-        logger.log_exc("Model Policy Error:")
+        logger.log_exc("MODEL POLICY: Exception when running handler")
 
     try:
         instance.policed=timezone.now()
         instance.save(update_fields=['policed'])
     except:
-        logging.error('Object %r is defective'%instance)
+        logger.log_exc('MODEL POLICY: Object %r is defective'%instance)
         bad_instances.append(instance)
 
 def noop(o,p):
         pass
 
+def check_db_connection_okay():
+    # django implodes if the database connection is closed by docker-compose
+    from django import db
+    try:
+        db.connection.cursor()
+        #diag = Diag.objects.filter(name="foo").first()
+    except Exception, e:
+        if "connection already closed" in traceback.format_exc():
+           logger.error("XXX connection already closed")
+           try:
+#               if db.connection:
+#                   db.connection.close()
+               db.close_connection()
+           except:
+                logger.log_exc("XXX we failed to fix the failure")
+        else:
+           logger.log_exc("XXX some other error")
+
 def run_policy():
     while (True):
         start = time.time()
-        run_policy_once()
+        try:
+            run_policy_once()
+        except:
+            logger.log_exc("MODEL_POLICY: Exception in run_policy()")
         if (time.time()-start<1):
             time.sleep(1)
 
@@ -110,6 +136,10 @@
         objects = []
         deleted_objects = []
 
+        logger.info("MODEL POLICY: run_policy_once()")
+
+        check_db_connection_okay()
+
         for m in models:
             res = m.objects.filter((Q(policed__lt=F('updated')) | Q(policed=None)) & Q(no_policy=False))
             objects.extend(res)
@@ -137,4 +167,6 @@
             reset_queries()
         except:
             # this shouldn't happen, but in case it does, catch it...
-            logger.log_exc("exception in reset_queries")
+            logger.log_exc("MODEL POLICY: exception in reset_queries")
+
+        logger.info("MODEL POLICY: finished run_policy_once()")
diff --git a/xos/synchronizers/monitoring_channel/steps/sync_monitoringchannel.yaml b/xos/synchronizers/monitoring_channel/steps/sync_monitoringchannel.yaml
index 1c4da12..ca72c5f 100644
--- a/xos/synchronizers/monitoring_channel/steps/sync_monitoringchannel.yaml
+++ b/xos/synchronizers/monitoring_channel/steps/sync_monitoringchannel.yaml
@@ -66,13 +66,21 @@
 #      dest=/etc/resolv.conf
 {% endif %}
 
+# FIXME: Temporary workaround to delete the monitoring-channel_ceilometer_proxy_config file always 
+# to trigger ansible notify handlers in the following task. 
+# Due to some issue, ansible "changed" flag is set to false even though there is a change of 
+# ceilometer configuration file, because of which the configuration change is not reflecting in 
+# ceilometer containers 
+#  - file: path=/usr/local/share/monitoring-channel-{{ unique_id }}_ceilometer_proxy_config state=absent
+
   - name: ceilometer proxy config
     template: src=/opt/xos/synchronizers/monitoring_channel/templates/ceilometer_proxy_config.j2 dest=/usr/local/share/monitoring-channel-{{ unique_id }}_ceilometer_proxy_config mode=0777
     notify:
-#    - restart monitoring-channel
-     - stop monitoring-channel
-     - remove container
-     - start monitoring-channel
+     - copy ceilo-config-file
+     - restart monitoring-channel container
+#     - stop monitoring-channel
+#     - remove container
+#     - start monitoring-channel
 
   - name: Monitoring channel upstart
     template: src=/opt/xos/synchronizers/monitoring_channel/templates/monitoring-channel.conf.j2 dest=/etc/init/monitoring-channel-{{ unique_id }}.conf
@@ -118,6 +126,12 @@
 {% endif %}
 
   handlers:
+  - name: copy ceilo-config-file
+    shell: docker cp /usr/local/share/monitoring-channel-{{ unique_id }}_ceilometer_proxy_config monitoring-channel-{{ unique_id }}:/usr/local/share/ceilometer_proxy_config
+
+  - name: restart monitoring-channel container
+    shell: docker restart monitoring-channel-{{ unique_id }}
+
   - name: restart monitoring-channel
     shell: service monitoring-channel-{{ unique_id }} stop; sleep 1; service monitoring-channel-{{ unique_id }} start
 
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 1685e07..4486985 100755
--- a/xos/synchronizers/monitoring_channel/templates/start-monitoring-channel.sh.j2
+++ b/xos/synchronizers/monitoring_channel/templates/start-monitoring-channel.sh.j2
@@ -24,9 +24,11 @@
     #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 -v /usr/local/share/monitoring-channel-{{ unique_id }}_ceilometer_proxy_config:/usr/local/share/ceilometer_proxy_config srikanthvavila/monitoring-channel
+#    docker run -d --name=$MONITORING_CHANNEL --privileged=true -p $HOST_FORWARDING_PORT_FOR_CEILOMETER:8000 -v /usr/local/share/monitoring-channel-{{ unique_id }}_ceilometer_proxy_config:/usr/local/share/ceilometer_proxy_config srikanthvavila/monitoring-channel
+    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 -v /usr/local/share/monitoring-channel-{{ unique_id }}_ceilometer_proxy_config:/usr/local/share/ceilometer_proxy_config srikanthvavila/monitoring-channel
+#    docker run -d --name=$MONITORING_CHANNEL --add-host="ctl:$HEADNODEFLATLANIP" --privileged=true -p $HOST_FORWARDING_PORT_FOR_CEILOMETER:8000 -v /usr/local/share/monitoring-channel-{{ unique_id }}_ceilometer_proxy_config:/usr/local/share/ceilometer_proxy_config srikanthvavila/monitoring-channel
+    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
@@ -41,6 +43,7 @@
 
 # Now copy ceilometer proxy configuration to container
 #cat /usr/local/share/monitoring-channel-{{ unique_id }}_ceilometer_proxy_config | sudo docker exec -i $MONITORING_CHANNEL bash -c 'cat > /usr/local/share/ceilometer_proxy_config'
+docker cp /usr/local/share/monitoring-channel-{{ unique_id }}_ceilometer_proxy_config $MONITORING_CHANNEL:/usr/local/share/ceilometer_proxy_config
 
 # Attach to container
-#docker start -a $MONITORING_CHANNEL
+docker start -a $MONITORING_CHANNEL
diff --git a/xos/synchronizers/onboarding/files/__init__.py b/xos/synchronizers/onboarding/files/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/xos/synchronizers/onboarding/files/__init__.py
@@ -0,0 +1 @@
+
diff --git a/xos/synchronizers/onboarding/model-deps b/xos/synchronizers/onboarding/model-deps
new file mode 100644
index 0000000..4aa86c7
--- /dev/null
+++ b/xos/synchronizers/onboarding/model-deps
@@ -0,0 +1,8 @@
+{
+    "XOS": [
+        "ServiceController"
+    ], 
+    "ServiceController": [
+        "ServiceControllerResource"
+    ]
+}
diff --git a/xos/synchronizers/onboarding/onboarding-synchronizer.py b/xos/synchronizers/onboarding/onboarding-synchronizer.py
new file mode 100755
index 0000000..84bec4f
--- /dev/null
+++ b/xos/synchronizers/onboarding/onboarding-synchronizer.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+# This imports and runs ../../xos-observer.py
+
+import importlib
+import os
+import sys
+observer_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),"../../synchronizers/base")
+sys.path.append(observer_path)
+mod = importlib.import_module("xos-synchronizer")
+mod.main()
diff --git a/xos/synchronizers/onboarding/onboarding_synchronizer_config b/xos/synchronizers/onboarding/onboarding_synchronizer_config
new file mode 100644
index 0000000..e2b92fd
--- /dev/null
+++ b/xos/synchronizers/onboarding/onboarding_synchronizer_config
@@ -0,0 +1,38 @@
+
+[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=onboarding
+dependency_graph=/opt/xos/synchronizers/onboarding/model-deps
+steps_dir=/opt/xos/synchronizers/onboarding/steps
+sys_dir=/opt/xos/synchronizers/onboarding/sys
+deleters_dir=/opt/xos/synchronizers/onboarding/deleters
+log_file=console
+driver=None
+backoff_disabled=True
+pretend=False
+save_ansible_output=True
+
+[feefie]
+client_id='vicci_dev_central'
+user_id='pl'
diff --git a/xos/synchronizers/onboarding/run.sh b/xos/synchronizers/onboarding/run.sh
new file mode 100755
index 0000000..d52d39c
--- /dev/null
+++ b/xos/synchronizers/onboarding/run.sh
@@ -0,0 +1,2 @@
+export XOS_DIR=/opt/xos
+python onboarding-synchronizer.py  -C $XOS_DIR/synchronizers/onboarding/onboarding_synchronizer_config
diff --git a/xos/synchronizers/onboarding/steps/sync_servicecontroller.py b/xos/synchronizers/onboarding/steps/sync_servicecontroller.py
new file mode 100644
index 0000000..77d8e12
--- /dev/null
+++ b/xos/synchronizers/onboarding/steps/sync_servicecontroller.py
@@ -0,0 +1,53 @@
+import os
+import sys
+import base64
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.syncstep import SyncStep, DeferredException
+from core.models import XOS, ServiceController
+from xos.logger import Logger, logging
+from synchronizers.base.ansible import run_template
+
+# xosbuilder will be in steps/..
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+from xosbuilder import XOSBuilder
+
+logger = Logger(level=logging.INFO)
+
+class SyncServiceController(SyncStep, XOSBuilder):
+    provides=[ServiceController]
+    observes=ServiceController
+    requested_interval=0
+    playbook = "sync_servicecontroller.yaml"
+
+    def __init__(self, **args):
+        SyncStep.__init__(self, **args)
+        XOSBuilder.__init__(self)
+
+    def sync_record(self, sc):
+        logger.info("Sync'ing ServiceController %s" % sc)
+
+        if sc.xos and (not sc.xos.enable_build):
+            raise DeferredException("XOS build is currently disabled")
+
+        unready = self.check_controller_unready(sc)
+        if unready:
+            raise Exception("Controller %s has unready resources: %s" % (str(sc), ",".join([str(x) for x in unready])))
+
+        dockerfiles = [self.create_synchronizer_dockerfile(sc)]
+        tenant_fields = {"dockerfiles": dockerfiles,
+                         "build_dir": self.build_dir,
+                         "ansible_tag": sc.__class__.__name__ + "_" + str(sc.id)}
+
+        path="servicecontroller"
+        res = run_template(self.playbook, tenant_fields, path=path)
+
+    def delete_record(self, m):
+        pass
+
+    def fetch_pending(self, deleted=False):
+        pend = super(SyncServiceController, self).fetch_pending(deleted)
+        return pend
+
diff --git a/xos/synchronizers/onboarding/steps/sync_servicecontroller.yaml b/xos/synchronizers/onboarding/steps/sync_servicecontroller.yaml
new file mode 100644
index 0000000..9431427
--- /dev/null
+++ b/xos/synchronizers/onboarding/steps/sync_servicecontroller.yaml
@@ -0,0 +1,20 @@
+---
+- hosts: 127.0.0.1
+  connection: local
+
+  vars:
+    dockerfiles:
+    {% for dockerfile in dockerfiles %}
+      - docker_image_name: {{ dockerfile.docker_image_name }}
+        dockerfile_fn: {{ dockerfile.dockerfile_fn }}
+    {% endfor %}  
+
+  tasks: 
+    {% for dockerfile in dockerfiles %}
+    - name: build_docker_{{ dockerfile.docker_image_name }}
+      shell: chdir={{ build_dir }} docker build -f {{ dockerfile.dockerfile_fn }} --rm -t {{ dockerfile.docker_image_name }} .
+    {% endfor %}
+
+#  - build_dockers:
+#    shell: docker build -f {{ '{{' }} item.dockerfile_fn {{ '}}' }} --rm -t {{ '{{' }} item.docker_image_name {{ '}}' }} .
+#    with items: "dockerfiles"
diff --git a/xos/synchronizers/onboarding/steps/sync_servicecontrollerresource.py b/xos/synchronizers/onboarding/steps/sync_servicecontrollerresource.py
new file mode 100644
index 0000000..59ae93f
--- /dev/null
+++ b/xos/synchronizers/onboarding/steps/sync_servicecontrollerresource.py
@@ -0,0 +1,37 @@
+import os
+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, ServiceController, ServiceControllerResource
+from xos.logger import Logger, logging
+
+# xosbuilder will be in steps/..
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+from xosbuilder import XOSBuilder
+
+logger = Logger(level=logging.INFO)
+
+class SyncServiceControllerResource(SyncStep, XOSBuilder):
+    provides=[ServiceControllerResource]
+    observes=ServiceControllerResource
+    requested_interval=0
+
+    def __init__(self, **args):
+        SyncStep.__init__(self, **args)
+        XOSBuilder.__init__(self)
+
+    def sync_record(self, scr):
+        logger.info("Sync'ing ServiceControllerResource %s" % scr)
+        self.download_resource(scr)
+
+    def delete_record(self, m):
+        pass
+
+    def fetch_pending(self, deleted=False):
+        pend = super(SyncServiceControllerResource, self).fetch_pending(deleted)
+        return pend
+
diff --git a/xos/synchronizers/onboarding/steps/sync_xos.py b/xos/synchronizers/onboarding/steps/sync_xos.py
new file mode 100644
index 0000000..dec7a34
--- /dev/null
+++ b/xos/synchronizers/onboarding/steps/sync_xos.py
@@ -0,0 +1,52 @@
+import os
+import sys
+import base64
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.syncstep import SyncStep, DeferredException
+from core.models import XOS
+from xos.logger import Logger, logging
+from synchronizers.base.ansible import run_template
+
+# xosbuilder will be in steps/..
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+from xosbuilder import XOSBuilder
+
+logger = Logger(level=logging.INFO)
+
+class SyncXOS(SyncStep, XOSBuilder):
+    provides=[XOS]
+    observes=XOS
+    requested_interval=0
+    playbook = "sync_xos.yaml"
+
+    def __init__(self, **args):
+        SyncStep.__init__(self, **args)
+        XOSBuilder.__init__(self)
+
+    def sync_record(self, xos):
+        logger.info("Sync'ing XOS %s" % xos)
+
+        if (not xos.enable_build):
+            raise DeferredException("XOS build is currently disabled")
+
+        self.create_docker_compose()
+
+        dockerfiles = [self.create_ui_dockerfile()]
+        tenant_fields = {"dockerfiles": dockerfiles,
+                         "build_dir": self.build_dir,
+                         "docker_project_name": xos.docker_project_name,
+                         "ansible_tag": xos.__class__.__name__ + "_" + str(xos.id)}
+
+        path="XOS"
+        res = run_template(self.playbook, tenant_fields, path=path)
+
+    def delete_record(self, m):
+        pass
+
+    def fetch_pending(self, deleted=False):
+        pend = super(SyncXOS, self).fetch_pending(deleted)
+        return pend
+
diff --git a/xos/synchronizers/onboarding/steps/sync_xos.yaml b/xos/synchronizers/onboarding/steps/sync_xos.yaml
new file mode 100644
index 0000000..8a98873
--- /dev/null
+++ b/xos/synchronizers/onboarding/steps/sync_xos.yaml
@@ -0,0 +1,20 @@
+---
+- hosts: 127.0.0.1
+  connection: local
+
+  vars:
+    dockerfiles:
+    {% for dockerfile in dockerfiles %}
+      - docker_image_name: {{ dockerfile.docker_image_name }}
+        dockerfile_fn: {{ dockerfile.dockerfile_fn }}
+    {% endfor %}  
+
+  tasks: 
+    {% for dockerfile in dockerfiles %}
+    - name: build_docker_{{ dockerfile.docker_image_name }}
+      shell: chdir={{ build_dir }} docker build -f {{ dockerfile.dockerfile_fn }} --rm -t {{ dockerfile.docker_image_name }} .
+    {% endfor %}
+
+    - name: run docker-compose
+      shell: docker-compose -p {{ docker_project_name }} -f /opt/xos/synchronizers/onboarding/docker-compose/docker-compose.yml up -d
+
diff --git a/xos/synchronizers/onboarding/templates/docker-compose.yml.j2 b/xos/synchronizers/onboarding/templates/docker-compose.yml.j2
new file mode 100644
index 0000000..faa9d02
--- /dev/null
+++ b/xos/synchronizers/onboarding/templates/docker-compose.yml.j2
@@ -0,0 +1,48 @@
+{% for container_name, container in containers.iteritems() %}
+
+{{ container_name}}:
+#  container_name: {{ container.container_base_name }}_{{ container_name }}_1
+  image: {{ container.image }}
+{%- if container.command %}
+  command: {{ container.command }}
+{%- endif %}
+{%- if container.ports %}
+  ports:
+{%- for src,dest in container.ports.iteritems() %}
+    - "{{ src }}:{{ dest }}"
+{%- endfor %}
+{%- endif %}
+{%- if container.links %}
+  links:
+{%- for link in container.links %}
+    - {{ link }}
+{%- endfor %}
+{%- endif %}
+{%- if container.external_links %}
+  external_links:
+{%- for link in container.external_links %}
+    - {{ link }}
+{%- endfor %}
+{%- endif %}
+{%- if container.volumes %}
+  volumes:
+{%- for volume in container.volumes %}
+{%- if volume.read_only %}
+    - {{ volume.host_path }}:{{ volume.container_path }}:ro
+{%- else %}
+    - {{ volume.host_path }}:{{ volume.container_path }}
+{%- endif %}
+{%- endfor %}
+{%- endif %}
+{%- if container.expose %}
+  expose:
+{%- for expose in container.expose %}
+    - "{{ expose }}"
+{%- endfor %}
+{%- endif %}
+  log_driver: "json-file"
+  log_opt:

+    max-size: "100k"

+    max-file: "5"
+
+{%- endfor %}
diff --git a/xos/synchronizers/onboarding/xosbuilder.py b/xos/synchronizers/onboarding/xosbuilder.py
new file mode 100644
index 0000000..ffb66ee
--- /dev/null
+++ b/xos/synchronizers/onboarding/xosbuilder.py
@@ -0,0 +1,252 @@
+import os
+import base64
+import jinja2
+import string
+import sys
+import urllib2
+import urlparse
+import xmlrpclib
+
+from xos.config import Config
+from core.models import Service, ServiceController, ServiceControllerResource, XOS
+from xos.logger import Logger, logging
+
+logger = Logger(level=logging.INFO)
+
+class XOSBuilder(object):
+    UI_KINDS=["models", "admin", "django_library", "rest_service", "rest_tenant", "tosca_custom_types", "tosca_resource","public_key"]
+    SYNC_CONTROLLER_KINDS=["synchronizer", "private_key", "public_key"]
+    SYNC_ALLCONTROLLER_KINDS=["models", "django_library"]
+
+    def __init__(self):
+        self.source_ui_image = "xosproject/xos"
+        self.source_sync_image = "xosproject/xos-synchronizer-openstack"
+        self.build_dir = "/opt/xos/BUILD/"
+
+    # stuff that has to do with downloading
+
+    def get_dest_dir(self, scr):
+        xos_base = "opt/xos"
+        service_name = scr.service_controller.name
+        base_dirs = {"models": "%s/services/%s/" % (xos_base, service_name),
+                     "admin": "%s/services/%s/" % (xos_base, service_name),
+                     "django_library": "%s/services/%s/" % (xos_base, service_name),
+                     "synchronizer": "%s/synchronizers/%s/" % (xos_base, service_name),
+                     "tosca_custom_types": "%s/tosca/custom_types/" % (xos_base),
+                     "tosca_resource": "%s/tosca/resources/" % (xos_base),
+                     "rest_service": "%s/api/service/" % (xos_base),
+                     "rest_tenant": "%s/api/tenant/" % (xos_base),
+                     "private_key": "%s/services/%s/keys" % (xos_base, service_name),
+                     "public_key": "%s/services/%s/keys/" % (xos_base, service_name)}
+        return base_dirs[scr.kind]
+
+    def get_build_fn(self, scr):
+        dest_dir = self.get_dest_dir(scr)
+        dest_fn = os.path.split(urlparse.urlsplit(scr.full_url).path)[-1]
+        return os.path.join(dest_dir, dest_fn)
+
+    def get_download_fn(self, scr):
+        dest_fn = self.get_build_fn(scr)
+        return os.path.join(self.build_dir, dest_fn)
+
+    def read_manifest(self, scr, fn):
+        manifest = []
+        manifest_lines = file(fn).readlines()
+        manifest_lines = [x.strip() for x in manifest_lines]
+        manifest_lines = [x for x in manifest_lines if x]
+        for line in manifest_lines:
+            url_parts = urlparse.urlsplit(scr.full_url)
+            new_path = os.path.join(os.path.join(*os.path.split(url_parts.path)[:-1]),line)
+            url = urlparse.urlunsplit( (url_parts.scheme, url_parts.netloc, new_path, url_parts.query, url_parts.fragment) )
+
+            build_fn = os.path.join(self.get_dest_dir(scr), line)
+            download_fn = os.path.join(self.build_dir, build_fn)
+
+            manifest.append( (url, download_fn, build_fn) )
+        return manifest
+
+    def download_file(self, url, dest_fn):
+        logger.info("Download %s to %s" % (url, dest_fn))
+        if not os.path.exists(os.path.dirname(dest_fn)):
+            os.makedirs(os.path.dirname(dest_fn))
+        obj = urllib2.urlopen(url)
+        file(dest_fn,"w").write(obj.read())
+
+        # make python files executable
+        if dest_fn.endswith(".py"): # and contents.startswith("#!"):
+            os.chmod(dest_fn, 0755)
+
+    def download_resource(self, scr):
+        if scr.format == "manifest":
+            manifest_fn = self.get_download_fn(scr)
+            self.download_file(scr.full_url, manifest_fn)
+            manifest = self.read_manifest(scr, manifest_fn)
+            for (url, download_fn, build_fn) in manifest:
+                self.download_file(url, download_fn)
+        else:
+            self.download_file(scr.full_url, self.get_download_fn(scr))
+
+    def get_docker_lines(self, scr):
+        if scr.format == "manifest":
+            manifest_fn = self.get_download_fn(scr)
+            manifest = self.read_manifest(scr, manifest_fn)
+            lines = []
+            for (url, download_fn, build_fn) in manifest:
+               lines.append("ADD %s /%s" % (build_fn, build_fn))
+            return lines
+        else:
+            build_fn = self.get_build_fn(scr)
+            return ["ADD %s /%s" % (build_fn, build_fn)]
+
+    def get_controller_docker_lines(self, controller, kinds):
+        need_service_init_py = False
+        dockerfile=[]
+        for scr in controller.service_controller_resources.all():
+            if scr.kind in kinds:
+                lines = self.get_docker_lines(scr)
+                dockerfile = dockerfile + lines
+            if scr.kind in ["admin", "models"]:
+                need_service_init_py = True
+
+        if need_service_init_py:
+            file(os.path.join(self.build_dir, "opt/xos/empty__init__.py"),"w").write("")
+            dockerfile.append("ADD opt/xos/empty__init__.py /opt/xos/services/%s/__init__.py" % controller.name)
+
+        return dockerfile
+
+    def check_controller_unready(self, controller):
+        unready_resources=[]
+        for scr in controller.service_controller_resources.all():
+            if (not scr.backend_status) or (not scr.backend_status.startswith("1")):
+                unready_resources.append(scr)
+
+        return unready_resources
+
+    # stuff that has to do with building
+
+    def create_xos_app_data(self, name, dockerfile, app_list, migration_list):
+        if not os.path.exists(os.path.join(self.build_dir,"opt/xos/xos")):
+            os.makedirs(os.path.join(self.build_dir,"opt/xos/xos"))
+
+        if app_list:
+            dockerfile.append("COPY opt/xos/xos/%s_xosbuilder_app_list /opt/xos/xos/xosbuilder_app_list" % name)
+            file(os.path.join(self.build_dir, "opt/xos/xos/%s_xosbuilder_app_list") % name, "w").write("\n".join(app_list)+"\n")
+
+        if migration_list:
+            dockerfile.append("COPY opt/xos/xos/%s_xosbuilder_migration_list /opt/xos/xos/xosbuilder_migration_list" % name)
+            file(os.path.join(self.build_dir, "opt/xos/xos/%s_xosbuilder_migration_list") % name, "w").write("\n".join(migration_list)+"\n")
+
+    def create_ui_dockerfile(self):
+        dockerfile_fn = "Dockerfile.UI"
+
+        app_list = []
+        migration_list = []
+
+        dockerfile = ["FROM %s" % self.source_ui_image]
+        for controller in ServiceController.objects.all():
+            if self.check_controller_unready(controller):
+                 logger.warning("Controller %s has unready resources" % str(controller))
+                 continue
+
+            dockerfile = dockerfile + self.get_controller_docker_lines(controller, self.UI_KINDS)
+            if controller.service_controller_resources.filter(kind="models").exists():
+                app_list.append("services." + controller.name)
+                migration_list.append(controller.name)
+
+        self.create_xos_app_data("ui", dockerfile, app_list, migration_list)
+
+        file(os.path.join(self.build_dir, dockerfile_fn), "w").write("\n".join(dockerfile)+"\n")
+
+        return {"dockerfile_fn": dockerfile_fn,
+                "docker_image_name": "xosproject/xos-ui"}
+
+    def create_synchronizer_dockerfile(self, controller):
+        # bake in the synchronizer from this controller
+        sync_lines = self.get_controller_docker_lines(controller, self.SYNC_CONTROLLER_KINDS)
+        if not sync_lines:
+            return []
+
+        dockerfile_fn = "Dockerfile.%s" % controller.name
+        dockerfile = ["FROM %s" % self.source_sync_image]
+
+        # Now bake in models from this controller as well as the others
+        # It's important to bake all services in, because some services'
+        # synchronizers may depend on models from another service.
+        app_list = []
+        for c in ServiceController.objects.all():
+            dockerfile = dockerfile + self.get_controller_docker_lines(c, self.SYNC_ALLCONTROLLER_KINDS)
+            if controller.service_controller_resources.filter(kind="models").exists():
+                app_list.append("services." + controller.name)
+
+        self.create_xos_app_data(controller.name, dockerfile, app_list, None)
+
+        dockerfile = dockerfile + sync_lines
+        file(os.path.join(self.build_dir, dockerfile_fn), "w").write("\n".join(dockerfile)+"\n")
+
+        return {"dockerfile_fn": dockerfile_fn,
+                "docker_image_name": "xosproject/xos-synchronizer-%s" % controller.name}
+
+    def create_docker_compose(self):
+         xos = XOS.objects.all()[0]
+
+         volume_list = []
+         for volume in xos.volumes.all():
+             volume_list.append({"host_path": volume.host_path,
+                                 "container_path": volume.container_path,
+                                 "read_only": volume.read_only})
+
+         containers = {}
+
+         containers["xos_db"] = \
+                            {"image": "xosproject/xos-postgres",
+                             "expose": [5432]}
+
+         db_container_name = xos.docker_project_name + "_xos_db_1"
+
+         containers["xos_ui"] = \
+                            {"image": "xosproject/xos-ui",
+                             "command": "python /opt/xos/manage.py runserver 0.0.0.0:%d --insecure --makemigrations" % xos.ui_port,
+                             "ports": {"%d"%xos.ui_port : "%d"%xos.ui_port},
+                             "links": ["xos_db"],
+                             #"external_links": [db_container_name],
+                             "volumes": volume_list}
+
+#         containers["xos_bootstrap_ui"] = {"image": "xosproject/xos",
+#                             "command": "python /opt/xos/manage.py runserver 0.0.0.0:%d --insecure --makemigrations" % xos.bootstrap_ui_port,
+#                             "ports": {"%d"%xos.bootstrap_ui_port : "%d"%xos.bootstrap_ui_port},
+#                             #"external_links": [db_container_name],
+#                             "links": ["xos_db"],
+#                             "volumes": volume_list}
+
+         for c in ServiceController.objects.all():
+             if self.check_controller_unready(c):
+                 logger.warning("Controller %s has unready resources" % str(c))
+                 continue
+
+             containers["xos_synchronizer_%s" % c.name] = \
+                            {"image": "xosproject/xos-synchronizer-%s" % c.name,
+                             "command": 'bash -c "sleep 120; cd /opt/xos/synchronizers/%s; bash ./run.sh"' % c.name,
+                             #"external_links": [db_container_name],
+                             "links": ["xos_db"],
+                             "volumes": volume_list}
+
+         vars = { "containers": containers }
+
+         template_loader = jinja2.FileSystemLoader( "/opt/xos/synchronizers/onboarding/templates/" )
+         template_env = jinja2.Environment(loader=template_loader)
+         template = template_env.get_template("docker-compose.yml.j2")
+         buffer = template.render(vars)
+
+         if not os.path.exists("/opt/xos/synchronizers/onboarding/docker-compose"):
+             os.makedirs("/opt/xos/synchronizers/onboarding/docker-compose")
+         file("/opt/xos/synchronizers/onboarding/docker-compose/docker-compose.yml", "w").write(buffer)
+
+#    def build_xos(self):
+#        dockerfiles=[]
+#        dockerfiles.append(self.create_ui_dockerfile())
+#
+#        for controller in ServiceController.objects.all():
+#            dockerfiles.append(self.create_synchronizer_dockerfile(controller))
+
+
+
diff --git a/xos/synchronizers/openstack/steps/purge_disabled_users.py b/xos/synchronizers/openstack/steps/purge_disabled_users.py
index 0973b8c..6b1dac3 100644
--- a/xos/synchronizers/openstack/steps/purge_disabled_users.py
+++ b/xos/synchronizers/openstack/steps/purge_disabled_users.py
@@ -7,19 +7,19 @@
 from core.models.user import User
 from xos.logger import observer_logger as logger
 
-class SyncRoles(OpenStackSyncStep):
-    provides=[User]
-    requested_interval=0
-    observes=User
-
-    def fetch_pending(self, deleted):
-        if (deleted):
-            # users marked as deleted
-            return User.deleted_objects.all()
-        else:
-            # disabled users that haven't been updated in over a week 
-            one_week_ago = datetime.datetime.now() - datetime.timedelta(days=7)
-            return User.objects.filter(is_active=False, updated__gt=one_week_ago)             
-
-    def sync_record(self, user):
-        user.delete() 
+#class SyncRoles(OpenStackSyncStep):
+#    provides=[User]
+#    requested_interval=0
+#    observes=User
+#
+#    def fetch_pending(self, deleted):
+#        if (deleted):
+#            # users marked as deleted
+#            return User.deleted_objects.all()
+#        else:
+#            # disabled users that haven't been updated in over a week
+#            one_week_ago = datetime.datetime.now() - datetime.timedelta(days=7)
+#            return User.objects.filter(is_active=False, updated__gt=one_week_ago)
+#
+#    def sync_record(self, user):
+#        user.delete()
diff --git a/xos/services/exampleservice/__init__.py b/xos/synchronizers/vpgwc/__init__.py
old mode 100644
new mode 100755
similarity index 100%
rename from xos/services/exampleservice/__init__.py
rename to xos/synchronizers/vpgwc/__init__.py
diff --git a/xos/synchronizers/exampleservice/model-deps b/xos/synchronizers/vpgwc/model-deps
old mode 100644
new mode 100755
similarity index 100%
copy from xos/synchronizers/exampleservice/model-deps
copy to xos/synchronizers/vpgwc/model-deps
diff --git a/xos/synchronizers/vpgwc/run.sh b/xos/synchronizers/vpgwc/run.sh
new file mode 100755
index 0000000..821e149
--- /dev/null
+++ b/xos/synchronizers/vpgwc/run.sh
@@ -0,0 +1,3 @@
+# Runs the XOS observer using helloworldservice_config
+export XOS_DIR=/opt/xos
+python vpgwc-synchronizer.py  -C $XOS_DIR/synchronizers/vpgwc/vpgwc_config
diff --git a/xos/synchronizers/vpgwc/steps/sync_vpgwc.py b/xos/synchronizers/vpgwc/steps/sync_vpgwc.py
new file mode 100644
index 0000000..446a521
--- /dev/null
+++ b/xos/synchronizers/vpgwc/steps/sync_vpgwc.py
@@ -0,0 +1,37 @@
+import os
+import sys
+from django.db.models import Q, F
+from services.mcord.models import MCORDService, VPGWCComponent
+from synchronizers.base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible
+
+parentdir = os.path.join(os.path.dirname(__file__), "..")
+sys.path.insert(0, parentdir)
+
+class SyncVPGWCComponent(SyncInstanceUsingAnsible):
+
+    provides = [VPGWCComponent]
+
+    observes = VPGWCComponent
+
+    requested_interval = 0
+
+    template_name = "sync_vpgwc.yaml"
+
+    service_key_name = "/opt/xos/configurations/mcord/mcord_private_key"
+
+    def __init__(self, *args, **kwargs):
+        super(SyncVPGWCComponent, self).__init__(*args, **kwargs)
+
+    def fetch_pending(self, deleted):
+
+        if (not deleted):
+            objs = VPGWCComponent.get_tenant_objects().filter(
+                Q(enacted__lt=F('updated')) | Q(enacted=None), Q(lazy_blocked=False))
+        else:
+
+            objs = VPGWCComponent.get_deleted_tenant_objects()
+
+        return objs
+
+    def get_extra_attributes(self, o):
+        return {"display_message": o.display_message, "s5s8_pgw_tag": o.s5s8_pgw_tag}
diff --git a/xos/synchronizers/vpgwc/steps/sync_vpgwc.yaml b/xos/synchronizers/vpgwc/steps/sync_vpgwc.yaml
new file mode 100644
index 0000000..a793976
--- /dev/null
+++ b/xos/synchronizers/vpgwc/steps/sync_vpgwc.yaml
@@ -0,0 +1,13 @@
+---
+- hosts: {{ instance_name }}
+  gather_facts: False
+  connection: ssh
+  user: ubuntu
+  sudo: yes
+  tasks:
+
+  - name: write message
+    shell: echo "{{ display_message }}" > /var/tmp/index.html
+
+  - name: setup s5s8_pgw interface config
+    shell: ./start_3gpp_int.sh eth1 {{ s5s8_pgw_tag }} {{ s5s8_pgw_ip }}/24 
diff --git a/xos/synchronizers/vpgwc/stop.sh b/xos/synchronizers/vpgwc/stop.sh
new file mode 100755
index 0000000..299641a
--- /dev/null
+++ b/xos/synchronizers/vpgwc/stop.sh
@@ -0,0 +1,2 @@
+# Kill the observer
+pkill -9 -f vpgwc-synchronizer.py
diff --git a/xos/synchronizers/vpgwc/vpgwc-synchronizer.py b/xos/synchronizers/vpgwc/vpgwc-synchronizer.py
new file mode 100755
index 0000000..95f4081
--- /dev/null
+++ b/xos/synchronizers/vpgwc/vpgwc-synchronizer.py
@@ -0,0 +1,13 @@
+#!/usr/bin/env python
+
+# This imports and runs ../../xos-observer.py
+# Runs the standard XOS observer
+
+import importlib
+import os
+import sys
+observer_path = os.path.join(os.path.dirname(
+    os.path.realpath(__file__)), "../../synchronizers/base")
+sys.path.append(observer_path)
+mod = importlib.import_module("xos-synchronizer")
+mod.main()
diff --git a/xos/synchronizers/vpgwc/vpgwc_config b/xos/synchronizers/vpgwc/vpgwc_config
new file mode 100755
index 0000000..c6b9c23
--- /dev/null
+++ b/xos/synchronizers/vpgwc/vpgwc_config
@@ -0,0 +1,40 @@
+# Required by XOS
+[db]
+name=xos
+user=postgres
+password=password
+host=localhost
+port=5432
+
+# Required by XOS
+[api]
+nova_enabled=True
+
+# Sets options for the observer
+[observer]
+# Optional name
+name=vpgwc
+# This is the location to the dependency graph you generate
+dependency_graph=/opt/xos/synchronizers/vpgwc/model-deps
+# The location of your SyncSteps
+steps_dir=/opt/xos/synchronizers/vpgwc/steps
+# A temporary directory that will be used by ansible
+sys_dir=/opt/xos/synchronizers/vpgwc/sys
+# Location of the file to save logging messages to the backend log is often used
+logfile=/var/log/xos_backend.log
+# If this option is true, then nothing will change, we simply pretend to run
+pretend=False
+# If this is False then XOS will use an exponential backoff when the observer
+# fails, since we will be waiting for an instance, we don't want this.
+backoff_disabled=True
+# We want the output from ansible to be logged
+save_ansible_output=True
+# This determines how we SSH to a client, if this is set to True then we try
+# to ssh using the instance name as a proxy, if this is disabled we ssh using
+# the NAT IP of the instance. On CloudLab the first option will fail so we must
+# set this to False
+proxy_ssh=True
+proxy_ssh_key=/root/setup/id_rsa
+proxy_ssh_user=root
+[networking]
+use_vtn=True
diff --git a/xos/tools/rebuild.py b/xos/tools/rebuild.py
new file mode 100755
index 0000000..dc2c482
--- /dev/null
+++ b/xos/tools/rebuild.py
@@ -0,0 +1,17 @@
+#!/usr/bin/env python                                                                                                               
+
+import os
+import sys
+sys.path.append("/opt/xos")
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
+import django
+from core.models import XOS
+django.setup()
+
+xoses = XOS.objects.all()
+if not xoses:
+    print "There is no XOS model"
+
+for xos in xoses:
+    xos.rebuild()
+
diff --git a/xos/tosca/custom_types/exampleservice.m4 b/xos/tosca/custom_types/exampleservice.m4._unused
similarity index 100%
copy from xos/tosca/custom_types/exampleservice.m4
copy to xos/tosca/custom_types/exampleservice.m4._unused
diff --git a/xos/tosca/custom_types/exampleservice.yaml b/xos/tosca/custom_types/exampleservice.yaml._unused
similarity index 100%
copy from xos/tosca/custom_types/exampleservice.yaml
copy to xos/tosca/custom_types/exampleservice.yaml._unused
diff --git a/xos/tosca/custom_types/xos.m4 b/xos/tosca/custom_types/xos.m4
index 109fc1d..9497b6d 100644
--- a/xos/tosca/custom_types/xos.m4
+++ b/xos/tosca/custom_types/xos.m4
@@ -6,6 +6,43 @@
 include(macros.m4)
 
 node_types:
+    tosca.nodes.XOS:
+        derived_from: tosca.nodes.Root
+        description: The root of XOS
+        properties:
+            xos_base_props
+            ui_port:
+                type: integer
+                required: false
+                description: TCP port of user interface
+            bootstrap_ui_port:
+                type: integer
+                required: false
+                descrption: TCP port of bootstrap user interface
+            docker_project_name:
+                type: string
+                required: false
+                description: Docker project name
+            enable_build:
+                type: boolean
+                required: false
+                description: True if XOS build should be enabled
+
+
+    tosca.nodes.XOSVolume:
+        derived_from: tosca.nodes.Root
+        description: A volume that should be attached to the XOS docker container
+        properties:
+            xos_base_props
+            host_path:
+                type: string
+                required: false
+                description: path of resource on host
+            read_only:
+                type: boolean
+                required: false
+                description: True if mount read only
+
     tosca.nodes.Service:
         derived_from: tosca.nodes.Root
         description: >
@@ -17,6 +54,68 @@
             xos_base_props
             xos_base_service_props
 
+    tosca.nodes.ServiceController:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS Service Controller.
+        properties:
+            xos_base_props
+            base_url:
+                type: string
+                required: false
+                description: Base url, to allow resources to use relative URLs
+            models:
+                type: string
+                required: false
+                description: url of models.py
+            admin:
+                type: string
+                required: false
+                description: url of admin.py
+            synchronizer:
+                type: string
+                required: false
+                description: url of synchronizer manifest
+            tosca_custom_types:
+                type: string
+                required: false
+                description: url of tosca custom_types
+            rest_service:
+                type: string
+                required: false
+                description: url of REST API service file
+            rest_tenant:
+                type: string
+                required: false
+                description: url of REST API tenant file
+            private_key:
+                type: string
+                required: false
+                description: private key
+            public_key:
+                type: string
+                required: false
+                description: public key
+
+    tosca.nodes.ServiceControllerResource:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS Service Resource.
+        properties:
+            xos_base_props
+            kind:
+                type: string
+                required: false
+                description: models, admin, django_library, synchronizer, rest, tosca_custom_types, or tosca_resource
+            format:
+                type: string
+                required: false
+                description: python, manifest, or docker
+            url:
+                type: string
+                required: false
+                description: url of resource, may be relative to base_url or absolute
+
     tosca.nodes.Tenant:
         derived_from: tosca.nodes.Root
         description: >
@@ -1034,6 +1133,15 @@
     tosca.relationships.UsesAgent:
         derived_from: tosca.relationships.Root
 
+    tosca.relationships.HasResource:
+        derived_from: tosca.relationships.Root
+
+    tosca.relationships.UsedByController:
+        derived_from: tosca.relationships.Root
+
+    tosca.relationships.UsedByXOS:
+        derived_from: tosca.relationships.Root
+
     tosca.capabilities.xos.Service:
         derived_from: tosca.capabilities.Root
         description: An XOS Service
diff --git a/xos/tosca/custom_types/xos.yaml b/xos/tosca/custom_types/xos.yaml
index 8b4c669..66229d5 100644
--- a/xos/tosca/custom_types/xos.yaml
+++ b/xos/tosca/custom_types/xos.yaml
@@ -21,6 +21,73 @@
 
 
 node_types:
+    tosca.nodes.XOS:
+        derived_from: tosca.nodes.Root
+        description: The root of XOS
+        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
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            ui_port:
+                type: integer
+                required: false
+                description: TCP port of user interface
+            bootstrap_ui_port:
+                type: integer
+                required: false
+                descrption: TCP port of bootstrap user interface
+            docker_project_name:
+                type: string
+                required: false
+                description: Docker project name
+            enable_build:
+                type: boolean
+                required: false
+                description: True if XOS build should be enabled
+
+
+    tosca.nodes.XOSVolume:
+        derived_from: tosca.nodes.Root
+        description: A volume that should be attached to the XOS docker container
+        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
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            host_path:
+                type: string
+                required: false
+                description: path of resource on host
+            read_only:
+                type: boolean
+                required: false
+                description: True if mount read only
+
     tosca.nodes.Service:
         derived_from: tosca.nodes.Root
         description: >
@@ -80,6 +147,98 @@
                 required: false
                 description: Version number of Service.
 
+    tosca.nodes.ServiceController:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS Service Controller.
+        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
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            base_url:
+                type: string
+                required: false
+                description: Base url, to allow resources to use relative URLs
+            models:
+                type: string
+                required: false
+                description: url of models.py
+            admin:
+                type: string
+                required: false
+                description: url of admin.py
+            synchronizer:
+                type: string
+                required: false
+                description: url of synchronizer manifest
+            tosca_custom_types:
+                type: string
+                required: false
+                description: url of tosca custom_types
+            rest_service:
+                type: string
+                required: false
+                description: url of REST API service file
+            rest_tenant:
+                type: string
+                required: false
+                description: url of REST API tenant file
+            private_key:
+                type: string
+                required: false
+                description: private key
+            public_key:
+                type: string
+                required: false
+                description: public key
+
+    tosca.nodes.ServiceControllerResource:
+        derived_from: tosca.nodes.Root
+        description: >
+            An XOS Service Resource.
+        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
+            replaces:
+                type: string
+                required: false
+                descrption: Replaces/renames this object
+            kind:
+                type: string
+                required: false
+                description: models, admin, django_library, synchronizer, rest, tosca_custom_types, or tosca_resource
+            format:
+                type: string
+                required: false
+                description: python, manifest, or docker
+            url:
+                type: string
+                required: false
+                description: url of resource, may be relative to base_url or absolute
+
     tosca.nodes.Tenant:
         derived_from: tosca.nodes.Root
         description: >
@@ -881,6 +1040,8 @@
                 required: false
                 description: list of access devices, in format "uplink vlan", multiple entries separated by commas
 
+# XXX - uncomment if we want access device to be specified as separate Tosca
+# objects, rather than encoding them into VOLTDevice.access_devices
 #    tosca.nodes.AccessDevice:
 #        derived_from: tosca.nodes.Root
 #        description: >
@@ -1856,6 +2017,18 @@
     tosca.relationships.MemberOfDevice:
         derived_from: tosca.relationships.Root
 
+    tosca.relationships.UsesAgent:
+        derived_from: tosca.relationships.Root
+
+    tosca.relationships.HasResource:
+        derived_from: tosca.relationships.Root
+
+    tosca.relationships.UsedByController:
+        derived_from: tosca.relationships.Root
+
+    tosca.relationships.UsedByXOS:
+        derived_from: tosca.relationships.Root
+
     tosca.capabilities.xos.Service:
         derived_from: tosca.capabilities.Root
         description: An XOS Service
diff --git a/xos/tosca/resources/exampleservice.py b/xos/tosca/resources/exampleservice._unused
similarity index 100%
rename from xos/tosca/resources/exampleservice.py
rename to xos/tosca/resources/exampleservice._unused
diff --git a/xos/tosca/resources/exampletenant.py b/xos/tosca/resources/exampletenant._unused
similarity index 100%
rename from xos/tosca/resources/exampletenant.py
rename to xos/tosca/resources/exampletenant._unused
diff --git a/xos/tosca/resources/servicecontroller.py b/xos/tosca/resources/servicecontroller.py
new file mode 100644
index 0000000..34b95c2
--- /dev/null
+++ b/xos/tosca/resources/servicecontroller.py
@@ -0,0 +1,42 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from core.models import ServiceController, ServiceControllerResource
+
+from xosresource import XOSResource
+
+class XOSServiceController(XOSResource):
+    provides = "tosca.nodes.ServiceController"
+    xos_model = ServiceController
+    copyin_props = ["base_url"]
+
+    def postprocess_resource_prop(self, obj, kind, format):
+        value = self.get_property(kind)
+        if value:
+            scr = ServiceControllerResource.objects.filter(service_controller=obj, kind=kind, format=format)
+            if scr:
+                scr=scr[0]
+                if scr.url != value:
+                    self.info("updating resource %s" % kind)
+                    scr.url = value
+                    scr.save()
+            else:
+                self.info("adding resource %s" % kind)
+                scr = ServiceControllerResource(service_controller=obj, name=kind, kind=kind, format=format, url=value)
+                scr.save()
+
+    def postprocess(self, obj):
+        # allow these common resource to be specified directly by the ServiceController tosca object
+        self.postprocess_resource_prop(obj, "models", "python")
+        self.postprocess_resource_prop(obj, "admin", "python")
+        self.postprocess_resource_prop(obj, "tosca_custom_types", "yaml")
+        self.postprocess_resource_prop(obj, "synchronizer", "manifest")
+        self.postprocess_resource_prop(obj, "private_key", "raw")
+        self.postprocess_resource_prop(obj, "public_key", "raw")
+        self.postprocess_resource_prop(obj, "rest_service", "python")
+        self.postprocess_resource_prop(obj, "rest_tenant", "python")
+
diff --git a/xos/tosca/resources/servicecontrollerresource.py b/xos/tosca/resources/servicecontrollerresource.py
new file mode 100644
index 0000000..96ea83d
--- /dev/null
+++ b/xos/tosca/resources/servicecontrollerresource.py
@@ -0,0 +1,27 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from core.models import ServiceControllerResource, ServiceController
+
+from xosresource import XOSResource
+
+class XOSServiceControllerResource(XOSResource):
+    provides = "tosca.nodes.ServiceControllerResource"
+    xos_model = ServiceControllerResource
+    copyin_props = ["kind", "format", "url"]
+
+    def get_xos_args(self, throw_exception=True):
+        args = super(XOSServiceControllerResource, self).get_xos_args()
+
+        controller_name = self.get_requirement("tosca.relationships.UsedByController", throw_exception=throw_exception)
+        if controller_name:
+            args["service_controller"] = self.get_xos_object(ServiceController, throw_exception=throw_exception, name=controller_name)
+
+        return args
+
+
+
diff --git a/xos/tosca/resources/vpgwccomponent.py b/xos/tosca/resources/vpgwccomponent.py
new file mode 100644
index 0000000..3b87111
--- /dev/null
+++ b/xos/tosca/resources/vpgwccomponent.py
@@ -0,0 +1,40 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+import pdb
+
+from services.mcord.models import VPGWCComponent, MCORDService
+
+from xosresource import XOSResource
+
+class XOSVPGWCComponent(XOSResource):
+    provides = "tosca.nodes.VPGWCComponent"
+    xos_model = VPGWCComponent
+    copyin_props = ["s5s8_pgw_tag", "display_message"]
+    name_field = None
+
+    def get_xos_args(self, throw_exception=True):
+        args = super(XOSVPGWCComponent, self).get_xos_args()
+
+        provider_name = self.get_requirement("tosca.relationships.MemberOfService", throw_exception=throw_exception)
+        if provider_name:
+            args["provider_service"] = self.get_xos_object(MCORDService, throw_exception=throw_exception, name=provider_name)
+
+        return args
+
+    def get_existing_objs(self):
+        args = self.get_xos_args(throw_exception=False)
+        provider_service = args.get("provider", None)
+        if provider_service:
+            return [ self.get_xos_object(provider_service=provider_service) ]
+        return []
+
+    def postprocess(self, obj):
+        pass
+
+    def can_delete(self, obj):
+        return super(XOSVPGWCComponent, self).can_delete(obj)
+
diff --git a/xos/tosca/resources/xosmodel.py b/xos/tosca/resources/xosmodel.py
new file mode 100644
index 0000000..188bb4f
--- /dev/null
+++ b/xos/tosca/resources/xosmodel.py
@@ -0,0 +1,30 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from core.models import XOS, XOSVolume
+
+from xosresource import XOSResource
+
+class XOSXOS(XOSResource):
+    provides = "tosca.nodes.XOS"
+    xos_model = XOS
+    copyin_props = ["ui_port", "bootstrap_ui_port", "docker_project_name", "enable_build"]
+
+class XOSVolume(XOSResource):
+    provides = "tosca.nodes.XOSVolume"
+    xos_model = XOSVolume
+    copyin_props = ["host_path"]
+    name_field = "container_path"
+
+    def get_xos_args(self, throw_exception=True):
+        args = super(XOSVolume, self).get_xos_args()
+
+        xos_name = self.get_requirement("tosca.relationships.UsedByXOS", throw_exception=throw_exception)
+        if xos_name:
+            args["xos"] = self.get_xos_object(XOS, throw_exception=throw_exception, name=xos_name)
+
+        return args
diff --git a/xos/tosca/resources/xosresource.py b/xos/tosca/resources/xosresource.py
index 012f814..f65a231 100644
--- a/xos/tosca/resources/xosresource.py
+++ b/xos/tosca/resources/xosresource.py
@@ -189,6 +189,17 @@
 
         raise Exception("artifact %s not found" % name)
 
+    def intrinsic_path_join(self, obj=None, name=None, varname=None, method=None):
+        if obj!="SELF":
+            raise Exception("only SELF is supported for get_artifact first arg")
+        if method!="ENV_VAR":
+            raise Exception("only ENV_VAR is supported for get_artifact fourth arg")
+
+        if not (name in os.environ):
+            raise Exception("environment variable %s not found" % name)
+
+        return os.path.join(os.environ[name], varname)
+
     def try_intrinsic_function(self, v):
         try:
             jsv = v.replace("'", '"')
@@ -205,6 +216,8 @@
             return self.intrinsic_get_artifact(*jsv["get_artifact"])
         elif "get_script_env" in jsv:
             return self.intrinsic_get_script_env(*jsv["get_script_env"])
+        elif "path_join" in jsv:
+            return self.intrinsic_path_join(*jsv["path_join"])
 
         return v
 
diff --git a/xos/xos/settings.py b/xos/xos/settings.py
index 7835689..9f20937 100644
--- a/xos/xos/settings.py
+++ b/xos/xos/settings.py
@@ -197,6 +197,13 @@
     'rest_framework_swagger',
 )
 
+# add services that were configured by xosbuilder to INSTALLED_APPS
+if os.path.exists("/opt/xos/xos/xosbuilder_app_list"):
+    for line in file("/opt/xos/xos/xosbuilder_app_list").readlines():
+        line = line.strip()
+        if line:
+            INSTALLED_APPS = list(INSTALLED_APPS) + [line]
+
 if DJANGO_VERSION[1] >= 7:
     # if django >= 1.7, then change the admin module
     INSTALLED_APPS = list(INSTALLED_APPS)