[CORD-1969] VSGWC migration from 3.0 to 4.1

Change-Id: I7c33f351e494ed8a0ba18bf2a0fbf2447442cf95
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..c7fa917
--- /dev/null
+++ b/README.md
@@ -0,0 +1,44 @@
+# Virtual Serving Gateway -- Control Plane Service
+
+## Onboarding
+
+To onboard this service in your system, you can add the service to the `mcord.yml` profile manifest:
+
+```
+xos_services:
+  - name: vsgwc
+    path: orchestration/xos_services/vsgwc
+    keypair: mcord_rsa
+    synchronizer: true
+```
+
+Once you have added the service, you will need to rebuilt and redeploy the XOS containers from source. Login to the `corddev` vm and `cd /cord/build`
+
+```
+$ ./gradlew -PdeployConfig=config/mcord_in_a_box.yml PIprepPlatform
+$ ./gradlew -PdeployConfig=config/mcord_in_a_box.yml :platform-install:buildImages
+$ ./gradlew -PdeployConfig=config/mcord_in_a_box.yml :platform-install:publish
+$ ./gradlew -PdeployConfig=config/mcord_in_a_box.yml :orchestration:xos:publish
+```
+
+Now the new XOS images should be published to the registry on `prod`. To bring them up, login to the `prod` VM and define these aliases:
+
+```
+$ CORD_PROFILE=$( cat /opt/cord_profile/profile_name )
+$ alias xos-pull="docker-compose -p $CORD_PROFILE -f /opt/cord_profile/docker-compose.yml pull"
+$ alias xos-up="docker-compose -p $CORD_PROFILE -f /opt/cord_profile/docker-compose.yml up -d --remove-orphans"
+$ alias xos-teardown="pushd /opt/cord/build/platform-install; ansible-playbook -i inventory/head-localhost --extra-vars @/opt/cord/build/genconfig/config.yml teardown-playbook.yml; popd"
+$ alias compute-node-refresh="pushd /opt/cord/build/platform-install; ansible-playbook -i /etc/maas/ansible/pod-inventory --extra-vars=@/opt/cord/build/genconfig/config.yml compute-node-refresh-playbook.yml; popd"
+```
+
+To pull new images from the database and launch the containers, while retaining the existing XOS database, run:
+
+```
+$ xos-pull; xos-up
+```
+
+Alternatively, to remove the XOS database and reinitialize XOS from scratch, run:
+
+```
+$ xos-teardown; xos-pull; xos-launch; compute-node-refresh
+```
diff --git a/xos/admin.py b/xos/admin.py
deleted file mode 100644
index 834438c..0000000
--- a/xos/admin.py
+++ /dev/null
@@ -1,133 +0,0 @@
-
-# Copyright 2017-present Open Networking Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-# admin.py - VSGW Django Admin
-
-from core.admin import ReadOnlyAwareAdmin, SliceInline
-from core.middleware import get_request
-from core.models import User
-from django import forms
-from django.contrib import admin
-from services.vsgw.models import *
-
-class VSGWServiceForm(forms.ModelForm):
-
-    class Meta:
-        model = VSGWService
-        fields = '__all__'
-
-    def __init__(self, *args, **kwargs):
-        super(VSGWServiceForm, self).__init__(*args, **kwargs)
-
-        if self.instance:
-            self.fields['service_message'].initial = self.instance.service_message
-
-    def save(self, commit=True):
-        self.instance.service_message = self.cleaned_data.get('service_message')
-        return super(VSGWServiceForm, self).save(commit=commit)
-
-class VSGWServiceAdmin(ReadOnlyAwareAdmin):
-
-    model = VSGWService
-    verbose_name = SERVICE_NAME_VERBOSE
-    verbose_name_plural = SERVICE_NAME_VERBOSE_PLURAL
-    form = VSGWServiceForm
-    inlines = [SliceInline]
-
-    list_display = ('backend_status_icon', 'name', 'service_message', 'enabled')
-    list_display_links = ('backend_status_icon', 'name', 'service_message' )
-
-    fieldsets = [(None, {
-        'fields': ['backend_status_text', 'name', 'enabled', 'versionNumber', 'service_message', 'description',],
-        'classes':['suit-tab suit-tab-general',],
-        })]
-
-    readonly_fields = ('backend_status_text', )
-    user_readonly_fields = ['name', 'enabled', 'versionNumber', 'description',]
-
-    extracontext_registered_admins = True
-
-    suit_form_tabs = (
-        ('general', 'Example Service Details', ),
-        ('slices', 'Slices',),
-        )
-
-    suit_form_includes = ((
-        'top',
-        'administration'),
-        )
-
-    def get_queryset(self, request):
-        return ExampleService.get_service_objects_by_user(request.user)
-
-admin.site.register(VSGWService, VSGWServiceAdmin)
-
-class VSGWTenantForm(forms.ModelForm):
-
-    class Meta:
-        model = VSGWTenant
-        fields = '__all__'
-
-    creator = forms.ModelChoiceField(queryset=User.objects.all())
-
-    def __init__(self, *args, **kwargs):
-        super(VSGWTenantForm, self).__init__(*args, **kwargs)
-
-        self.fields['kind'].widget.attrs['readonly'] = True
-        self.fields['kind'].initial = SERVICE_NAME
-
-        self.fields['provider_service'].queryset = VSGWService.get_service_objects().all()
-
-        if self.instance:
-            self.fields['creator'].initial = self.instance.creator
-            self.fields['tenant_message'].initial = self.instance.tenant_message
-            self.fields['image_name'].initial = self.instance.image_name
-
-        if (not self.instance) or (not self.instance.pk):
-            self.fields['creator'].initial = get_request().user
-            if VSGWService.get_service_objects().exists():
-                self.fields['provider_service'].initial = VSGWService.get_service_objects().all()[0]
-
-    def save(self, commit=True):
-        self.instance.creator = self.cleaned_data.get('creator')
-        self.instance.tenant_message = self.cleaned_data.get('tenant_message')
-        self.instance.image_name = self.cleaned_data.get('image_name')
-        return super(VSGWTenantForm, self).save(commit=commit)
-
-
-class VSGWTenantAdmin(ReadOnlyAwareAdmin):
-
-    verbose_name = TENANT_NAME_VERBOSE
-    verbose_name_plural = TENANT_NAME_VERBOSE_PLURAL
-
-    list_display = ('id', 'backend_status_icon', 'instance', 'tenant_message', 'image_name')
-    list_display_links = ('backend_status_icon', 'instance', 'tenant_message', 'id', 'image_name')
-
-    fieldsets = [(None, {
-        'fields': ['backend_status_text', 'kind', 'provider_service', 'instance', 'creator', 'tenant_message', 'image_name'],
-        'classes': ['suit-tab suit-tab-general'],
-        })]
-
-    readonly_fields = ('backend_status_text', 'instance',)
-
-    form = VSGWTenantForm
-
-    suit_form_tabs = (('general', 'Details'),)
-
-    def get_queryset(self, request):
-        return VSGWTenant.get_tenant_objects_by_user(request.user)
-
-admin.site.register(VSGWTenant, VSGWTenantAdmin)
diff --git a/xos/make_synchronizer_manifest.sh b/xos/make_synchronizer_manifest.sh
index 0b16750..5351287 100755
--- a/xos/make_synchronizer_manifest.sh
+++ b/xos/make_synchronizer_manifest.sh
@@ -1,4 +1,3 @@
-
 # Copyright 2017-present Open Networking Foundation
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,6 +12,5 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-
 #! /bin/bash
-find synchronizer -type f | cut -b 14- > synchronizer/manifest 
+find synchronizer -type f | cut -b 14- > synchronizer/manifest
diff --git a/xos/models.py b/xos/models.py
index 355ee8f..55d36c8 100644
--- a/xos/models.py
+++ b/xos/models.py
@@ -1,4 +1,3 @@
-
 # Copyright 2017-present Open Networking Foundation
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,65 +12,83 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+from models_decl import VSGWCService_decl
+from models_decl import VSGWCVendor_decl
+from models_decl import VSGWCTenant_decl
 
-# models.py -  vSGW Models
-
-from core.models import Service, TenantWithContainer, Image
+from django.db import models
+from core.models import Service, XOSBase, Slice, Instance, ServiceInstance, TenantWithContainer, Node, Image, User, Flavor, NetworkParameter, NetworkParameterType, Port, AddressPool
+import os
 from django.db import models, transaction
+from django.forms.models import model_to_dict
+from django.db.models import *
+from operator import itemgetter, attrgetter, methodcaller
+from core.models import Tag
+from core.models.service import LeastLoadedNodeScheduler
+import traceback
+from xos.exceptions import *
 
-MCORD_KIND = 'EPC'
-
-SERVICE_NAME = 'vsgw'
-SERVICE_NAME_VERBOSE = 'Virtual SGW Service'
-SERVICE_NAME_VERBOSE_PLURAL = 'Virtual SGW Services'
-TENANT_NAME_VERBOSE = 'Virtual SGW Tenant'
-TENANT_NAME_VERBOSE_PLURAL = 'Virtual SGW Tenants'
-
-class VSGWService(Service):
-
-    KIND = SERVICE_NAME
-
-    class Meta:
+class VSGWCService(VSGWCService_decl):
+   class Meta:
         proxy = True
-        app_label = SERVICE_NAME
-        verbose_name = SERVICE_NAME_VERBOSE
 
-class VSGWTenant(TenantWithContainer):
+   def create_tenant(self, **kwargs):
+       t = VSGWCTenant(kind="vEPC", provider_service=self, connect_method="na", **kwargs)
+       t.save()
+       return t
 
-    KIND = SERVICE_NAME
+class VSGWCVendor(VSGWCVendor_decl):
+   class Meta:
+        proxy = True
 
-    class Meta:
-        verbose_name = TENANT_NAME_VERBOSE
+class VSGWCTenant(VSGWCTenant_decl):
+   class Meta:
+        proxy = True
 
-    tenant_message = models.CharField(max_length=254, help_text="Tenant Message to Display")
-    image_name = models.CharField(max_length=254, help_text="Name of VM image")
+   def __init__(self, *args, **kwargs):
+       vsgwcservice = VSGWCService.get_service_objects().all()
+       if vsgwcservice:
+           self._meta.get_field(
+                   "provider_service").default = vsgwcservice[0].id
+       super(VSGWCTenant, self).__init__(*args, **kwargs)
 
-    def __init__(self, *args, **kwargs):
-        vsgw_service = VSGWService.get_service_objects().all()
-        if vsgw_service:
-            self._meta.get_field('provider_service').default = vsgw_service[0].id
-        super(VSGWTenant, self).__init__(*args, **kwargs)
+   @property
+   def image(self):
+       if not self.vsgwc_vendor:
+           return super(VSGWCTenant, self).image
+       return self.vsgwc_vendor.image
 
-    def save(self, *args, **kwargs):
-        super(VSGWTenant, self).save(*args, **kwargs)
-        model_policy_vsgwtenant(self.pk)
+   def save_instance(self, instance):
+       if self.vsgwc_vendor:
+           instance.flavor = self.vsgwc_vendor.flavor
+       super(VSGWCTenant, self).save_instance(instance)
 
-    def delete(self, *args, **kwargs):
-        self.cleanup_container()
-        super(VSGWTenant, self).delete(*args, **kwargs)
+   def save(self, *args, **kwargs):
+       if not self.creator:
+           if not getattr(self, "caller", None):
+               raise XOSProgrammingError("VSGWCTenant's self.caller was not set")
+           self.creator = self.caller
+           if not self.creator:
+               raise XOSProgrammingError("VSGWCTenant's self.creator was not set")
 
-    @property
-    def image(self):
-        img = self.image_name.strip()
-        if img.lower() != "default":
-            return Image.objects.get(name=img)
-        else: 
-            return super(VSGWTenant, self).image
+       super(VSGWCTenant, 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_vsgwctenant(self.pk)
 
-def model_policy_vsgwtenant(pk):
+   def delete(self, *args, **kwargs):
+       # Delete the instance that was created for this tenant
+       self.cleanup_container()
+       super(VSGWCTenant, self).delete(*args, **kwargs)
+
+def model_policy_vsgwctenant(pk):
+    # This section of code is atomic to prevent race conditions
     with transaction.atomic():
-        tenant = VSGWTenant.objects.select_for_update().filter(pk=pk)
+        # We find all of the tenants that are waiting to update
+        tenant = VSGWCTenant.objects.select_for_update().filter(pk=pk)
         if not tenant:
             return
+        # Since this code is atomic it is safe to always use the first tenant
         tenant = tenant[0]
         tenant.manage_container()
+
diff --git a/xos/synchronizer/Dockerfile.synchronizer b/xos/synchronizer/Dockerfile.synchronizer
new file mode 100644
index 0000000..859575e
--- /dev/null
+++ b/xos/synchronizer/Dockerfile.synchronizer
@@ -0,0 +1,39 @@
+# xosproject/vsgwc-synchronizer
+FROM xosproject/xos-synchronizer-base:candidate
+
+COPY . /opt/xos/synchronizers/vsgwc
+
+ENTRYPOINT []
+
+WORKDIR "/opt/xos/synchronizers/vsgwc"
+
+# Label image
+ARG org_label_schema_schema_version=1.0
+ARG org_label_schema_name=vsgwc-synchronizer
+ARG org_label_schema_version=unknown
+ARG org_label_schema_vcs_url=unknown
+ARG org_label_schema_vcs_ref=unknown
+ARG org_label_schema_build_date=unknown
+ARG org_opencord_vcs_commit_date=unknown
+ARG org_opencord_component_chameleon_version=unknown
+ARG org_opencord_component_chameleon_vcs_url=unknown
+ARG org_opencord_component_chameleon_vcs_ref=unknown
+ARG org_opencord_component_xos_version=unknown
+ARG org_opencord_component_xos_vcs_url=unknown
+ARG org_opencord_component_xos_vcs_ref=unknown
+
+LABEL org.label-schema.schema-version=$org_label_schema_schema_version \
+      org.label-schema.name=$org_label_schema_name \
+      org.label-schema.version=$org_label_schema_version \
+      org.label-schema.vcs-url=$org_label_schema_vcs_url \
+      org.label-schema.vcs-ref=$org_label_schema_vcs_ref \
+      org.label-schema.build-date=$org_label_schema_build_date \
+      org.opencord.vcs-commit-date=$org_opencord_vcs_commit_date \
+      org.opencord.component.chameleon.version=$org_opencord_component_chameleon_version \
+      org.opencord.component.chameleon.vcs-url=$org_opencord_component_chameleon_vcs_url \
+      org.opencord.component.chameleon.vcs-ref=$org_opencord_component_chameleon_vcs_ref \
+      org.opencord.component.xos.version=$org_opencord_component_xos_version \
+      org.opencord.component.xos.vcs-url=$org_opencord_component_xos_vcs_url \
+      org.opencord.component.xos.vcs-ref=$org_opencord_component_xos_vcs_ref
+
+CMD bash -c "cd /opt/xos/synchronizers/vsgwc; ./run-from-api.sh"
\ No newline at end of file
diff --git a/xos/synchronizer/manifest b/xos/synchronizer/manifest
deleted file mode 100644
index 04700fd..0000000
--- a/xos/synchronizer/manifest
+++ /dev/null
@@ -1,8 +0,0 @@
-model-deps
-manifest
-run.sh
-stop.sh
-vsgw-synchronizer.py
-vsgw_config
-steps/sync_vsgw.py
-steps/sync_vsgw.yaml
diff --git a/xos/synchronizer/stop.sh b/xos/synchronizer/run-from-api.sh
old mode 100644
new mode 100755
similarity index 91%
rename from xos/synchronizer/stop.sh
rename to xos/synchronizer/run-from-api.sh
index 4834de9..94a37fb
--- a/xos/synchronizer/stop.sh
+++ b/xos/synchronizer/run-from-api.sh
@@ -1,4 +1,3 @@
-
 # Copyright 2017-present Open Networking Foundation
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,6 +12,4 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-
-# Kill the observer
-pkill -9 -f vsgw-synchronizer.py
+python vsgwc-synchronizer.py
diff --git a/xos/synchronizer/run.sh b/xos/synchronizer/run.sh
deleted file mode 100644
index 48db7ca..0000000
--- a/xos/synchronizer/run.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-
-# Copyright 2017-present Open Networking Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-# Runs the XOS observer using vsgw_config
-export XOS_DIR=/opt/xos
-python vsgw-synchronizer.py  -C $XOS_DIR/synchronizers/vsgw/vsgw_config
diff --git a/xos/synchronizer/stop.sh b/xos/synchronizer/steps/roles/ngic_config/tasks/main.yml
similarity index 68%
copy from xos/synchronizer/stop.sh
copy to xos/synchronizer/steps/roles/ngic_config/tasks/main.yml
index 4834de9..f6e9b8c 100644
--- a/xos/synchronizer/stop.sh
+++ b/xos/synchronizer/steps/roles/ngic_config/tasks/main.yml
@@ -1,4 +1,3 @@
-
 # Copyright 2017-present Open Networking Foundation
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,6 +12,14 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+---
+- name: create config directory for cp_config file
+  file:
+    path: /var/tmp/config
+    state: directory
+    mode: 0755
 
-# Kill the observer
-pkill -9 -f vsgw-synchronizer.py
+- name: save control plane configuration information in vSGWC VM
+  template:
+    src=cp_config.cfg.j2
+    dest=/var/tmp/config/cp_config.cfg
diff --git a/xos/synchronizer/steps/roles/ngic_config/templates/cp_config.cfg.j2 b/xos/synchronizer/steps/roles/ngic_config/templates/cp_config.cfg.j2
new file mode 100644
index 0000000..f6bb725
--- /dev/null
+++ b/xos/synchronizer/steps/roles/ngic_config/templates/cp_config.cfg.j2
@@ -0,0 +1,10 @@
+{% set date = ansible_date_time['date'] ~ '_' ~ ansible_date_time['hour'] ~ '_' ~ ansible_date_time['minute'] %}
+NOW={{ date }}
+FILE="logs/cp_{{ date }}.log"
+S11_SGW_IP={{ sgwc_shared_ip }}
+S11_MME_IP={{ mme_shared_ip }}
+S1U_SGW_IP={{ sgwu_shared_ip }}
+IP_POOL_IP=16.0.0.0
+IP_POOL_MASK=255.0.0.0
+APN=apn1
+MEMORY=1024
diff --git a/xos/synchronizer/steps/sync_vsgw.py b/xos/synchronizer/steps/sync_vsgw.py
deleted file mode 100644
index 2f16a88..0000000
--- a/xos/synchronizer/steps/sync_vsgw.py
+++ /dev/null
@@ -1,57 +0,0 @@
-
-# Copyright 2017-present Open Networking Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-import os
-import sys
-from django.db.models import Q, F
-from services.vsgw.models import VSGWService, VSGWTenant
-from synchronizers.base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible
-
-parentdir = os.path.join(os.path.dirname(__file__), "..")
-sys.path.insert(0, parentdir)
-
-class SyncVSGWTenant(SyncInstanceUsingAnsible):
-
-    provides = [VSGWTenant]
-
-    observes = VSGWTenant
-
-    requested_interval = 0
-
-    template_name = "sync_vsgw.yaml"
-
-    service_key_name = "/opt/xos/synchronizers/vsgw/vsgw_private_key"
-
-    def __init__(self, *args, **kwargs):
-        super(SyncVSGWTenant, self).__init__(*args, **kwargs)
-
-    def fetch_pending(self, deleted):
-
-        if (not deleted):
-            objs = VSGWTenant.get_tenant_objects().filter(
-                Q(enacted__lt=F('updated')) | Q(enacted=None), Q(lazy_blocked=False))
-        else:
-            # If this is a deletion we get all of the deleted tenants..
-            objs = VSGWTenant.get_deleted_tenant_objects()
-
-        return objs
-
-    def get_extra_attributes(self, o):
-        fields = {}
-        fields['tenant_message'] = o.tenant_message
-        fields['image_name'] = o.image_name
-        return fields
-
diff --git a/xos/synchronizer/steps/sync_vsgw.yaml b/xos/synchronizer/steps/sync_vsgw.yaml
deleted file mode 100644
index 0ad9397..0000000
--- a/xos/synchronizer/steps/sync_vsgw.yaml
+++ /dev/null
@@ -1,43 +0,0 @@
-
-# Copyright 2017-present Open Networking Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
----
-- hosts: {{ instance_name }}
-  connection: ssh
-  user: ubuntu
-  become: yes
-  gather_facts: no
-  tasks:
-
-  vars:
-    - tenant_message: "{{ tenant_message }}"
-  
-#  - name: Write message
-#    shell: echo "{{ tenant_message }}" > /var/tmp/index.html
-#
-#  - name: setup s1u interface config
-#    shell: ./start_3gpp_int.sh eth1 {{ s1u_sgw_tag }} {{ s1u_sgw_ip }}/24
-#
-#  - name: setup s11 interface config
-#    shell: ./start_3gpp_int.sh eth2 {{ s11_sgw_tag }} {{ s11_sgw_ip }}/24
-#
-#  - name: setup s5s8 interface config
-#    shell: ./start_3gpp_int.sh eth3 {{ s5s8_sgw_tag }} {{ s5s8_sgw_ip }}/24
-  
-#  roles:
-#    - install_apache
-#    - create_index
-
diff --git a/xos/synchronizer/steps/sync_vsgwctenant.py b/xos/synchronizer/steps/sync_vsgwctenant.py
new file mode 100644
index 0000000..cc1078c
--- /dev/null
+++ b/xos/synchronizer/steps/sync_vsgwctenant.py
@@ -0,0 +1,71 @@
+# Copyright 2017-present Open Networking Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import sys
+from django.db.models import Q, F
+from synchronizers.new_base.modelaccessor import *
+from synchronizers.new_base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible
+
+parentdir = os.path.join(os.path.dirname(__file__), "..")
+sys.path.insert(0, parentdir)
+
+class SyncVSGWCTenant(SyncInstanceUsingAnsible):
+    provides = [VSGWCTenant]
+
+    observes = VSGWCTenant
+
+    requested_interval = 0
+
+    template_name = "vsgwctenant_playbook.yaml"
+
+    service_key_name = "/opt/xos/configurations/mcord/mcord_private_key"
+
+    def __init__(self, *args, **kwargs):
+        super(SyncVSGWCTenant, self).__init__(*args, **kwargs)
+
+#    def fetch_pending(self, deleted):
+#        if (not deleted):
+#            objs = VSGWCTenant.get_tenant_objects().filter(
+#                Q(enacted__lt=F('updated')) | Q(enacted=None), Q(lazy_blocked=False))
+#        else:
+#            # If this is a deletion we get all of the deleted tenants..
+#            objs = VSGWCTenant.get_deleted_tenant_objects()
+#
+#        return objs
+
+    # Gets the attributes that are used by the Ansible template but are not
+    # part of the set of default attribtues.
+    def get_extra_attributes(self, o):
+        fields = {}
+        shared_net_id = Network.objects.get(name='shared_network').id
+
+	try:
+            fields['sgwc_shared_ip'] = Port.objects.get(network_id=shared_net_id, instance_id=o.instance_id).ip
+        except Exception:
+            print '{} does not have an instance'.format(o.name)
+
+        try:
+            mme = TenantWithContainer.objects.get(provider_service_id=Service.objects.get(name='vmme').id, subscriber_tenant_id=o.subscriber_tenant_id)
+            fields['mme_shared_ip'] = Port.objects.get(network_id=shared_net_id, instance_id=mme.instance_id).ip
+	except Exception:
+            print '{} does not have a VMME instance'.format(o.subscriber_tenant.name)
+
+        try:
+            sgwu = TenantWithContainer.objects.get(provider_service_id=Service.objects.get(name='vsgwu').id, subscriber_tenant_id=o.subscriber_tenant_id)
+            fields['sgwu_shared_ip'] = Port.objects.get(network_id=shared_net_id, instance_id=sgwu.instance_id).ip
+        except Exception:
+            print '{} does not have a VSGWU instance'.format(o.subscriber_tenant.name)
+
+        return fields
diff --git a/xos/synchronizer/stop.sh b/xos/synchronizer/steps/vsgwctenant_playbook.yaml
similarity index 69%
copy from xos/synchronizer/stop.sh
copy to xos/synchronizer/steps/vsgwctenant_playbook.yaml
index 4834de9..ef1b986 100644
--- a/xos/synchronizer/stop.sh
+++ b/xos/synchronizer/steps/vsgwctenant_playbook.yaml
@@ -1,4 +1,3 @@
-
 # Copyright 2017-present Open Networking Foundation
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,6 +12,16 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+---
+- hosts: {{ instance_name }}
+  gather_facts: True
+  connection: ssh
+  user: ubuntu
+  sudo: yes
+  vars:
+    - sgwc_shared_ip: {{ sgwc_shared_ip }}
+    - mme_shared_ip: {{ mme_shared_ip }}
+    - sgwu_shared_ip: {{ sgwu_shared_ip }}
+  roles:
+    - ngic_config
 
-# Kill the observer
-pkill -9 -f vsgw-synchronizer.py
diff --git a/xos/synchronizer/vsgw_config b/xos/synchronizer/vsgw_config
deleted file mode 100644
index 02d3fb0..0000000
--- a/xos/synchronizer/vsgw_config
+++ /dev/null
@@ -1,28 +0,0 @@
-# Required by XOS
-[db]
-name=xos
-user=postgres
-password=password
-host=xos_db
-port=5432
-
-# Required by XOS
-[api]
-nova_enabled=True
-
-# Sets options for the synchronizer
-[observer]
-name=vsgw
-dependency_graph=/opt/xos/synchronizers/vsgw/model-deps
-steps_dir=/opt/xos/synchronizers/vsgw/steps
-sys_dir=/opt/xos/synchronizers/vsgw/sys
-logfile=/var/log/xos_backend.log
-pretend=False
-backoff_disabled=True
-save_ansible_output=True
-proxy_ssh=True
-proxy_ssh_key=/root/setup/id_rsa
-proxy_ssh_user=root
-enable_watchers=True
-[networking]
-use_vtn=True
diff --git a/xos/synchronizer/vsgw-synchronizer.py b/xos/synchronizer/vsgwc-synchronizer.py
old mode 100644
new mode 100755
similarity index 73%
rename from xos/synchronizer/vsgw-synchronizer.py
rename to xos/synchronizer/vsgwc-synchronizer.py
index 616029c..4a527ef
--- a/xos/synchronizer/vsgw-synchronizer.py
+++ b/xos/synchronizer/vsgwc-synchronizer.py
@@ -1,4 +1,3 @@
-
 # Copyright 2017-present Open Networking Foundation
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,7 +12,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-
 #!/usr/bin/env python
 
 # Runs the standard XOS synchronizer
@@ -21,9 +19,13 @@
 import importlib
 import os
 import sys
+from xosconfig import Config
 
-synchronizer_path = os.path.join(os.path.dirname(
-    os.path.realpath(__file__)), "../../synchronizers/base")
+config_file = os.path.abspath(os.path.dirname(os.path.realpath(__file__)) + '/vsgwc_config.yaml')
+
+Config.init(config_file, 'synchronizer-config-schema.yaml')
+observer_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "../../synchronizers/new_base")
+
 sys.path.append(synchronizer_path)
 mod = importlib.import_module("xos-synchronizer")
 mod.main()
diff --git a/xos/synchronizer/stop.sh b/xos/synchronizer/vsgwc_config.yaml
similarity index 66%
copy from xos/synchronizer/stop.sh
copy to xos/synchronizer/vsgwc_config.yaml
index 4834de9..5d3195e 100644
--- a/xos/synchronizer/stop.sh
+++ b/xos/synchronizer/vsgwc_config.yaml
@@ -1,4 +1,3 @@
-
 # Copyright 2017-present Open Networking Foundation
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,6 +12,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-
-# Kill the observer
-pkill -9 -f vsgw-synchronizer.py
+name: vsgwc-synchronizer
+accessor:
+  username: xosadmin@opencord.org
+  password: "@/opt/xos/services/vsgwc/credentials/xosadmin@opencord.org"
+dependency_graph: "/opt/xos/synchronizers/vsgwc/model-deps"
+steps_dir: "/opt/xos/synchronizers/vsgwc/steps"
+sys_dir: "/opt/xos/synchronizers/vsgwc/sys"
diff --git a/xos/synchronizer/vsgwc_from_api_config b/xos/synchronizer/vsgwc_from_api_config
new file mode 100644
index 0000000..fcd8bd3
--- /dev/null
+++ b/xos/synchronizer/vsgwc_from_api_config
@@ -0,0 +1,20 @@
+# Sets options for the synchronizer
+[observer]
+name=vsgwc
+dependency_graph=/opt/xos/synchronizers/vsgwc/model-deps
+steps_dir=/opt/xos/synchronizers/vsgwc/steps
+sys_dir=/opt/xos/synchronizers/vsgwc/sys
+#logfile=/var/log/xos_backend.log
+log_file=console
+log_level=debug
+pretend=False
+backoff_disabled=True
+save_ansible_output=True
+proxy_ssh=True
+proxy_ssh_key=/opt/cord_profile/node_key
+proxy_ssh_user=root
+accessor_kind=api
+accessor_password=@/opt/xos/services/vsgwc/credentials/xosadmin@opencord.org
+
+[networking]
+use_vtn=True
\ No newline at end of file
diff --git a/xos/templates/VSGWAdmin.html b/xos/templates/VSGWAdmin.html
deleted file mode 100644
index a58a1e8..0000000
--- a/xos/templates/VSGWAdmin.html
+++ /dev/null
@@ -1,28 +0,0 @@
-
-<!--
-Copyright 2017-present Open Networking Foundation
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
--->
-
-
-<!-- Template used to for the button leading to the HelloWorldTenantComplete form. -->
-<div class = "left-nav">
-  <ul>
-    <li>
-      <a href="/admin/mcordservice/vsgwcomponent/">
-        vSGW Service Components
-      </a>
-    </li>
-  </ul>
-</div>
diff --git a/xos/macros.m4 b/xos/tosca/custom_types/macros.m4
similarity index 99%
rename from xos/macros.m4
rename to xos/tosca/custom_types/macros.m4
index 391aafd..cd4ff96 100644
--- a/xos/macros.m4
+++ b/xos/tosca/custom_types/macros.m4
@@ -1,4 +1,3 @@
-
 # Copyright 2017-present Open Networking Foundation
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,7 +12,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-
 # 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
diff --git a/xos/tosca/custom_types/vsgwc.m4 b/xos/tosca/custom_types/vsgwc.m4
new file mode 100644
index 0000000..077dc01
--- /dev/null
+++ b/xos/tosca/custom_types/vsgwc.m4
@@ -0,0 +1,53 @@
+# Copyright 2017-present Open Networking Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+# compile this with "m4 vsgwc.m4 > vsgwc.yaml"
+
+# include macros
+include(macros.m4)
+
+node_types:
+    tosca.nodes.VSGWCService:
+        derived_from: tosca.nodes.Root
+        description: >
+            VSGWC Service
+        capabilities:
+            xos_base_service_caps
+        properties:
+            xos_base_props
+            xos_base_service_props
+
+    tosca.nodes.VSGWCTenant:
+        derived_from: tosca.nodes.Root
+        description: >
+            VSGWC Tenant
+        properties:
+            xos_base_tenant_props
+
+    tosca.nodes.VSGWCVendor:
+        derived_from: tosca.nodes.Root
+        description: >
+            VSGWC Vendor
+        properties:
+            xos_base_props
+            name:
+                type: string
+                required: true
+
+    tosca.relationships.VendorOfTenant:
+           derived_from: tosca.relationships.Root
+           valid_target_types: [ tosca.capabilities.xos.VSGWCTenant ]
+
diff --git a/xos/vsgw.yaml b/xos/tosca/custom_types/vsgwc.yaml
similarity index 75%
rename from xos/vsgw.yaml
rename to xos/tosca/custom_types/vsgwc.yaml
index fcc771b..fe5afed 100644
--- a/xos/vsgw.yaml
+++ b/xos/tosca/custom_types/vsgwc.yaml
@@ -1,4 +1,3 @@
-
 # Copyright 2017-present Open Networking Foundation
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,9 +12,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-
 tosca_definitions_version: tosca_simple_yaml_1_0
 
+# compile this with "m4 vsgwc.m4 > vsgwc.yaml"
+
 # include macros
 # 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
@@ -27,11 +27,18 @@
 
 # Subscriber
 
+
+
+
+# end m4 macros
+
+
+
 node_types:
-    tosca.nodes.VSGWService:
+    tosca.nodes.VSGWCService:
         derived_from: tosca.nodes.Root
         description: >
-            vSGW Service
+            VSGWC Service
         capabilities:
             scalable:
                 type: tosca.capabilities.Scalable
@@ -85,14 +92,11 @@
                 type: string
                 required: false
                 description: Version number of Service.
-            service_message:
-                type: string
-                required: false
 
-    tosca.nodes.VSGWTenant:
+    tosca.nodes.VSGWCTenant:
         derived_from: tosca.nodes.Root
         description: >
-            A Tenant of the vsgw service
+            VSGWC Tenant
         properties:
             kind:
                 type: string
@@ -102,7 +106,33 @@
                 type: string
                 required: false
                 description: Service specific ID opaque to XOS but meaningful to service
-            tenant_message:
+
+    tosca.nodes.VSGWCVendor:
+        derived_from: tosca.nodes.Root
+        description: >
+            VSGWC Vendor
+        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
+            name:
+                type: string
+                required: true
+
+    tosca.relationships.VendorOfTenant:
+           derived_from: tosca.relationships.Root
+           valid_target_types: [ tosca.capabilities.xos.VSGWCTenant ]
 
diff --git a/xos/synchronizer/stop.sh b/xos/tosca/resources/vsgwcservice.py
similarity index 65%
copy from xos/synchronizer/stop.sh
copy to xos/tosca/resources/vsgwcservice.py
index 4834de9..217bd0f 100644
--- a/xos/synchronizer/stop.sh
+++ b/xos/tosca/resources/vsgwcservice.py
@@ -1,4 +1,3 @@
-
 # Copyright 2017-present Open Networking Foundation
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,5 +13,11 @@
 # limitations under the License.
 
 
-# Kill the observer
-pkill -9 -f vsgw-synchronizer.py
+from service import XOSService
+from services.vsgwc.models import VSGWCService
+
+class XOSVSGWCService(XOSService):
+    provides = "tosca.nodes.VSGWCService"
+    xos_model = VSGWCService
+    copyin_props = ["view_url", "icon_url", "enabled", "published", "public_key", "private_key_fn", "versionNumber"]
+
diff --git a/xos/tosca/resources/vsgwtenant.py b/xos/tosca/resources/vsgwctenant.py
similarity index 61%
rename from xos/tosca/resources/vsgwtenant.py
rename to xos/tosca/resources/vsgwctenant.py
index b5a5b4b..8f309e9 100644
--- a/xos/tosca/resources/vsgwtenant.py
+++ b/xos/tosca/resources/vsgwctenant.py
@@ -1,4 +1,3 @@
-
 # Copyright 2017-present Open Networking Foundation
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,31 +12,31 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-
-from services.vsgw.models import *
 from xosresource import XOSResource
+from core.models import Service, ServiceInstance
+from services.vsgwc.models import VSGWCTenant
 
-class XOSVSGWTenant(XOSResource):
-    provides = "tosca.nodes.VSGWTenant"
-    xos_model = VSGWTenant
+class XOSVSGWCTenant(XOSResource):
+    provides = "tosca.nodes.VSGWCTenant"
+    xos_model = VSGWCTenant
     name_field = "service_specific_id"
-    copyin_props = ("tenant_message", "image_name")
+    copyin_props = ()
 
     def get_xos_args(self, throw_exception=True):
-        args = super(XOSVSGWTenant, self).get_xos_args()
+        args = super(XOSVSGWCTenant, self).get_xos_args()
 
         # ExampleTenant must always have a provider_service
-        provider_name = self.get_requirement("tosca.relationships.MemberOfService", throw_exception=throw_exception)
+        provider_name = self.get_requirement("tosca.relationships.TenantOfService", throw_exception=throw_exception)
         if provider_name:
-            args["provider_service"] = self.get_xos_object(VSGWService, throw_exception=throw_exception, name=provider_name)
+            args["provider_service"] = self.get_xos_object(Service, throw_exception=throw_exception, name=provider_name)
 
         return args
 
     def get_existing_objs(self):
         args = self.get_xos_args(throw_exception=False)
-        return VSGWTenant.get_tenant_objects().filter(provider_service=args["provider_service"], service_specific_id=args["service_specific_id"])
+        return VSGWCTenant.get_tenant_objects().filter(provider_service=args["provider_service"], service_specific_id=args["service_specific_id"])
         return []
 
     def can_delete(self, obj):
-        return super(XOSVSGWTenant, self).can_delete(obj)
+        return super(XOSVSGWCTenant, self).can_delete(obj)
 
diff --git a/xos/tosca/resources/vsgwcvendor.py b/xos/tosca/resources/vsgwcvendor.py
new file mode 100644
index 0000000..f0db57b
--- /dev/null
+++ b/xos/tosca/resources/vsgwcvendor.py
@@ -0,0 +1,46 @@
+# Copyright 2017-present Open Networking Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from xosresource import XOSResource
+from core.models import ServiceInstance
+from services.vsgwc.models import VSGWCVendor
+
+class XOSVSGWCVendor(XOSResource):
+    provides = "tosca.nodes.VSGWCVendor"
+    xos_model = VSGWCVendor
+    name_field = None
+    copyin_props = ( "name",)
+
+    def get_xos_args(self, throw_exception=True):
+        args = super(XOSVSGWCVendor, self).get_xos_args()
+
+        tenant_name = self.get_requirement("tosca.relationships.VendorOfTenant", throw_exception=throw_exception)
+        if tenant_name:
+            args["provider_tenant"] = self.get_xos_object(ServiceInstance, throw_exception=throw_exception, name=tenant_name)
+
+        return args
+
+    def get_existing_objs(self):
+        args = self.get_xos_args(throw_exception=False)
+        provider_tenant = args.get("provider", None)
+        if provider_tenant:
+            return [ self.get_xos_object(provider_tenant=provider_tenant) ]
+        return []
+
+    def postprocess(self, obj):
+        pass
+
+    def can_delete(self, obj):
+        return super(XOSVSGWCVendor, self).can_delete(obj)
+
diff --git a/xos/tosca/resources/vsgwservice.py b/xos/tosca/resources/vsgwservice.py
deleted file mode 100644
index 5e4339b..0000000
--- a/xos/tosca/resources/vsgwservice.py
+++ /dev/null
@@ -1,45 +0,0 @@
-
-# Copyright 2017-present Open Networking Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-from services.vsgw.models import VSGWService
-from xosresource import XOSResource
-from service import XOSService
-
-class XOSVSGWService(XOSResource):
-    provides = "tosca.nodes.VSGWService"
-    xos_model = VSGWService
-    copyin_props = ["view_url", "icon_url", "enabled", "published", "public_key", "private_key_fn", "versionNumber", "service_message"]
-
-    def postprocess(self, obj):
-        for provider_service_name in self.get_requirements("tosca.relationships.TenantOfService"):
-            provider_service = self.get_xos_object(VSGWService, name=provider_service_name)
-
-            existing_tenancy = CoarseTenant.get_tenant_objects().filter(provider_service = provider_service, subscriber_service = obj)
-            if existing_tenancy:
-                self.info("Tenancy relationship from %s to %s already exists" % (str(obj), str(provider_service)))
-            else:
-                tenancy = CoarseTenant(provider_service = provider_service,
-                                       subscriber_service = obj)
-                tenancy.save()
-
-                self.info("Created Tenancy relationship  from %s to %s" % (str(obj), str(provider_service)))
-
-    def can_delete(self, obj):
-        if obj.slices.exists():
-            self.info("Service %s has active slices; skipping delete" % obj.name)
-            return False
-        return super(XOSVSGWService, self).can_delete(obj)
-
diff --git a/xos/vSGW-onboard.yaml b/xos/vsgwc-onboard.yaml
similarity index 60%
rename from xos/vSGW-onboard.yaml
rename to xos/vsgwc-onboard.yaml
index afc2fa0..e0bb63c 100644
--- a/xos/vSGW-onboard.yaml
+++ b/xos/vsgwc-onboard.yaml
@@ -1,4 +1,3 @@
-
 # Copyright 2017-present Open Networking Foundation
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,31 +12,26 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-
 tosca_definitions_version: tosca_simple_yaml_1_0
 
-description: Onboard the vSGW
+description: Onboard the vsgwc
 
 imports:
    - custom_types/xos.yaml
 
 topology_template:
   node_templates:
-    servicecontroller#vsgw:
+    servicecontroller#vsgwc:
       type: tosca.nodes.ServiceController
       properties:
-          base_url: file:///opt/xos_services/vSGW/xos/
+          base_url: file:///opt/xos_services/vsgw/xos/
           # The following will concatenate with base_url automatically, if
           # base_url is non-null.
-          models: models.py
-          admin: admin.py
-          admin_template: templates/VSGWAdmin.html
+          xproto: ./
           synchronizer: synchronizer/manifest
-          synchronizer_run: vsgw-synchronizer.py
-          #tosca_custom_types: vsgw.yaml
-          tosca_resource: tosca/resources/vsgwtenant.py, tosca/resources/vsgwservice.py
-          #rest_service: api/service/vsgwservice.py
-          #rest_tenant: api/tenant/vsgwtenant.py
-          private_key: file:///opt/xos/key_import/vSGW_rsa
-          public_key: file:///opt/xos/key_import/vSGW_rsa.pub
+          synchronizer_run: vsgwc-synchronizer.py
+          tosca_custom_types: tosca/custom_types/vsgwc.yaml
+          tosca_resource: tosca/resources/vsgwctenant.py, tosca/resources/vsgwcservice.py, tosca/resources/vsgwcvendor.py
+          private_key: file:///opt/xos/key_import/mcord_rsa
+          public_key: file:///opt/xos/key_import/mcord_rsa.pub
 
diff --git a/xos/vsgwc.xproto b/xos/vsgwc.xproto
new file mode 100644
index 0000000..c3cc7df
--- /dev/null
+++ b/xos/vsgwc.xproto
@@ -0,0 +1,38 @@
+# Copyright 2017-present Open Networking Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+option name = "vSGWC";
+option verbose_name = "Virtual Serving Gateway -- Control Plane";
+option app_label = "vsgwc";
+option kind = "vEPC";
+option legacy = "True";
+
+message VSGWCService (Service){
+    option name = "vsgwcservice";
+    option verbose_name = "Virtual Serving Gateway -- Control Plane Service";
+}
+
+message VSGWCVendor (XOSBase){
+    option name = "vsgwcvendor";
+    option verbose_name = "Virtual Serving Gateway -- Control Plane Vendor";
+    required string name = 1 [help_text = "vendor name", max_length = 32, null = False, db_index = False, blank = False];
+    required manytoone image->Image:+ = 2 [help_text = "select image for this vendor", db_index = True, null = False, blank = False];
+    required manytoone flavor->Flavor:+ = 3 [help_text = "select openstack flavor for vendor image", db_index = True, null = False, blank = False];
+}
+
+message VSGWCTenant (TenantWithContainer){
+    option name = "vsgwcserviceinstance";
+    option verbose_name = "Virtual Serving Gateway -- Control Plane ServiceInstance";
+    optional manytoone vsgwc_vendor->VSGWCVendor:vendor_tenants = 1 [help_text = "select vendor of choice, leave blank for slice default", db_index = True, null = True, blank = True];
+}