move over vtn services from XOS repo
diff --git a/xos/admin.py b/xos/admin.py
new file mode 100644
index 0000000..464f197
--- /dev/null
+++ b/xos/admin.py
@@ -0,0 +1,93 @@
+from django.contrib import admin
+
+from django import forms
+from django.utils.safestring import mark_safe
+from django.contrib.auth.admin import UserAdmin
+from django.contrib.admin.widgets import FilteredSelectMultiple
+from django.contrib.auth.forms import ReadOnlyPasswordHashField
+from django.contrib.auth.signals import user_logged_in
+from django.utils import timezone
+from django.contrib.contenttypes import generic
+from suit.widgets import LinkedSelect
+from core.admin import ServiceAppAdmin,SliceInline,ServiceAttrAsTabInline, ReadOnlyAwareAdmin, XOSTabularInline, ServicePrivilegeInline, TenantRootTenantInline, TenantRootPrivilegeInline
+from core.middleware import get_request
+
+from services.vtn.models import *
+
+from functools import update_wrapper
+from django.contrib.admin.views.main import ChangeList
+from django.core.urlresolvers import reverse
+from django.contrib.admin.utils import quote
+
+class VTNServiceForm(forms.ModelForm):
+    privateGatewayMac = forms.CharField(required=False)
+    localManagementIp = forms.CharField(required=False)
+    ovsdbPort = forms.CharField(required=False)
+    sshPort = forms.CharField(required=False)
+    sshUser = forms.CharField(required=False)
+    sshKeyFile = forms.CharField(required=False)
+    mgmtSubnetBits = forms.CharField(required=False)
+    xosEndpoint = forms.CharField(required=False)
+    xosUser = forms.CharField(required=False)
+    xosPassword = forms.CharField(required=False)
+
+    def __init__(self,*args,**kwargs):
+        super (VTNServiceForm,self ).__init__(*args,**kwargs)
+        if self.instance:
+            self.fields['privateGatewayMac'].initial = self.instance.privateGatewayMac
+            self.fields['localManagementIp'].initial = self.instance.localManagementIp
+            self.fields['ovsdbPort'].initial = self.instance.ovsdbPort
+            self.fields['sshPort'].initial = self.instance.sshPort
+            self.fields['sshUser'].initial = self.instance.sshUser
+            self.fields['sshKeyFile'].initial = self.instance.sshKeyFile
+            self.fields['mgmtSubnetBits'].initial = self.instance.mgmtSubnetBits
+            self.fields['xosEndpoint'].initial = self.instance.xosEndpoint
+            self.fields['xosUser'].initial = self.instance.xosUser
+            self.fields['xosPassword'].initial = self.instance.xosPassword
+
+    def save(self, commit=True):
+        self.instance.privateGatewayMac = self.cleaned_data.get("privateGatewayMac")
+        self.instance.localManagementIp = self.cleaned_data.get("localManagementIp")
+        self.instance.ovsdbPort = self.cleaned_data.get("ovsdbPort")
+        self.instance.sshPort = self.cleaned_data.get("sshPort")
+        self.instance.sshUser = self.cleaned_data.get("sshUser")
+        self.instance.sshKeyFile = self.cleaned_data.get("sshKeyFile")
+        self.instance.mgmtSubnetBits = self.cleaned_data.get("mgmtSubnetBits")
+        self.instance.xosEndpoint = self.cleaned_data.get("xosEndpoint")
+        self.instance.xosUser = self.cleaned_data.get("xosUser")
+        self.instance.xosPassword = self.cleaned_data.get("xosPassword")
+        return super(VTNServiceForm, self).save(commit=commit)
+
+    class Meta:
+        model = VTNService
+
+class VTNServiceAdmin(ReadOnlyAwareAdmin):
+    model = VTNService
+    form = VTNServiceForm
+    verbose_name = "VTN Service"
+    verbose_name_plural = "VTN Service"
+    list_display = ("backend_status_icon", "name", "enabled")
+    list_display_links = ('backend_status_icon', 'name', )
+    fieldsets = [(None, {'fields': ['backend_status_text', 'name','enabled','versionNumber','description',"view_url","icon_url",
+                                    'privateGatewayMac', 'localManagementIp', 'ovsdbPort', 'sshPort', 'sshUser', 'sshKeyFile', 'mgmtSubnetBits', 'xosEndpoint', 'xosUser', 'xosPassword' ], 'classes':['suit-tab suit-tab-general']})]
+    readonly_fields = ('backend_status_text', )
+    inlines = [SliceInline,ServiceAttrAsTabInline,ServicePrivilegeInline]
+
+    extracontext_registered_admins = True
+
+    user_readonly_fields = ["name", "enabled", "versionNumber", "description"]
+
+    suit_form_tabs =(('general', 'VTN Service Details'),
+#        ('administration', 'Administration'),
+        ('slices','Slices'),
+        ('serviceattrs','Additional Attributes'),
+        ('serviceprivileges','Privileges'),
+    )
+
+    suit_form_includes = ( # ('vtnadmin.html', 'top', 'administration'),
+                           ) #('hpctools.html', 'top', 'tools') )
+
+    def queryset(self, request):
+        return VTNService.get_service_objects_by_user(request.user)
+
+admin.site.register(VTNService, VTNServiceAdmin)
diff --git a/xos/api/service/vtn.py b/xos/api/service/vtn.py
new file mode 100644
index 0000000..6b02616
--- /dev/null
+++ b/xos/api/service/vtn.py
@@ -0,0 +1,96 @@
+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 viewsets
+from rest_framework.decorators import detail_route, list_route
+from rest_framework.views import APIView
+from core.models import *
+from services.vtn.models import VTNService
+from django.forms import widgets
+from django.conf.urls import patterns, url
+from api.xosapi_helpers import PlusModelSerializer, XOSViewSet, ReadOnlyField
+from django.shortcuts import get_object_or_404
+from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
+from xos.exceptions import *
+import json
+import subprocess
+
+class VTNServiceSerializer(PlusModelSerializer):
+    id = ReadOnlyField()
+
+    privateGatewayMac = serializers.CharField(required=False)
+    localManagementIp = serializers.CharField(required=False)
+    ovsdbPort = serializers.IntegerField(required=False)
+    sshPort = serializers.IntegerField(required=False)
+    sshUser = serializers.CharField(required=False)
+    sshKeyFile = serializers.CharField(required=False)
+    mgmtSubnetBits = serializers.IntegerField(required=False)
+    xosEndpoint = serializers.CharField(required=False)
+    xosUser = serializers.CharField(required=False)
+    xosPassword = serializers.CharField(required=False)
+
+
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    class Meta:
+        model = VTNService
+        fields = ('humanReadableName', 'id', 'privateGatewayMac', 'localManagementIp', 'ovsdbPort', 'sshPort', 'sshUser', 'sshKeyFile',
+                  'mgmtSubnetBits', 'xosEndpoint', 'xosUser', 'xosPassword')
+
+    def getHumanReadableName(self, obj):
+        return obj.__unicode__()
+
+class VTNViewSet(XOSViewSet):
+    base_name = "vtn"
+    method_name = "vtn"
+    method_kind = "viewset"
+
+    # these are just because ViewSet needs some queryset and model, even if we don't use the
+    # default endpoints
+    queryset = VTNService.get_service_objects().all()
+    model = VTNService
+    serializer_class = VTNServiceSerializer
+
+    @classmethod
+    def get_urlpatterns(self, api_path="^"):
+        patterns = []
+
+        patterns.append( self.detail_url("services/$", {"get": "get_services"}, "services") )
+        patterns.append( self.detail_url("services_names/$", {"get": "get_services_names"}, "services") )
+        patterns.append( self.detail_url("services/(?P<service>[a-zA-Z0-9\-_]+)/$", {"get": "get_service"}, "get_service") )
+
+        # Not as RESTful as it could be, but maintain these endpoints for compability
+        patterns.append( self.list_url("services/$", {"get": "get_services"}, "rootvtn_services") )
+        patterns.append( self.list_url("services_names/$", {"get": "get_services_names"}, "rootvtn_services") )
+        patterns.append( self.list_url("services/(?P<service>[a-zA-Z0-9\-_]+)/$", {"get": "get_service"}, "rootvtn_get_service") )
+
+        patterns = patterns + super(VTNViewSet,self).get_urlpatterns(api_path)
+
+        return patterns
+
+    def get_services_names(self, request, pk=None):
+        result = {}
+        for service in Service.objects.all():
+           for id in service.get_vtn_src_names():
+               dependencies = service.get_vtn_dependencies_names()
+               if dependencies:
+                   result[id] = dependencies
+        return Response(result)
+
+    def get_services(self, request, pk=None):
+        result = {}
+        for service in Service.objects.all():
+           for id in service.get_vtn_src_ids():
+               dependencies = service.get_vtn_dependencies_ids()
+               if dependencies:
+                   result[id] = dependencies
+        return Response(result)
+
+    def get_service(self, request, pk=None, service=None):
+        for xos_service in Service.objects.all():
+            if service in xos_service.get_vtn_src_ids():
+                return Response(xos_service.get_vtn_dependencies_ids())
+        return Response([])
+
+
diff --git a/xos/models.py b/xos/models.py
new file mode 100644
index 0000000..c805f24
--- /dev/null
+++ b/xos/models.py
@@ -0,0 +1,45 @@
+from django.db import models
+from core.models import Service, PlCoreBase, Slice, Instance, Tenant, TenantWithContainer, Node, Image, User, Flavor, Subscriber, NetworkParameter, NetworkParameterType, Port, AddressPool
+from core.models.plcorebase import StrippedCharField
+import os
+from django.db import models, transaction
+from django.forms.models import model_to_dict
+from django.db.models import Q
+from operator import itemgetter, attrgetter, methodcaller
+from core.models import Tag
+from core.models.service import LeastLoadedNodeScheduler
+import traceback
+from xos.exceptions import *
+from xos.config import Config
+
+class ConfigurationError(Exception):
+    pass
+
+VTN_KIND = "VTN"
+
+# -------------------------------------------
+# VTN
+# -------------------------------------------
+
+class VTNService(Service):
+    KIND = VTN_KIND
+
+    class Meta:
+        app_label = "vtn"
+        verbose_name = "VTN Service"
+        proxy = True
+
+    simple_attributes = ( ("privateGatewayMac", "00:00:00:00:00:01"),
+                          ("localManagementIp", "172.27.0.1/24"),
+                          ("ovsdbPort", "6641"),
+                          ("sshPort", "22"),
+                          ("sshUser", "root"),
+                          ("sshKeyFile", "/root/node_key") ,
+                          ("mgmtSubnetBits", "24"),
+                          ("xosEndpoint", "http://xos/"),
+                          ("xosUser", "padmin@vicci.org"),
+                          ("xosPassword", "letmein"),
+
+                         )
+
+VTNService.setup_simple_attributes()
diff --git a/xos/synchronizer/manifest b/xos/synchronizer/manifest
new file mode 100644
index 0000000..dccfcdc
--- /dev/null
+++ b/xos/synchronizer/manifest
@@ -0,0 +1,10 @@
+manifest
+vtn-synchronizer.py
+steps/sync_tenant.py
+steps/sync_port_addresses.py
+start.sh
+stop.sh
+model-deps
+supervisor/vtn-observer.conf
+run.sh
+vtn_synchronizer_config
diff --git a/xos/synchronizer/model-deps b/xos/synchronizer/model-deps
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/xos/synchronizer/model-deps
@@ -0,0 +1 @@
+{}
diff --git a/xos/synchronizer/run.sh b/xos/synchronizer/run.sh
new file mode 100755
index 0000000..000a563
--- /dev/null
+++ b/xos/synchronizer/run.sh
@@ -0,0 +1,2 @@
+export XOS_DIR=/opt/xos
+python vtn-synchronizer.py  -C $XOS_DIR/synchronizers/vtn/vtn_synchronizer_config
diff --git a/xos/synchronizer/start.sh b/xos/synchronizer/start.sh
new file mode 100755
index 0000000..2c43440
--- /dev/null
+++ b/xos/synchronizer/start.sh
@@ -0,0 +1,2 @@
+export XOS_DIR=/opt/xos
+nohup python vtn-synchronizer.py  -C $XOS_DIR/synchronizers/vtn/vtn_synchronizer_config > /dev/null 2>&1 &
diff --git a/xos/synchronizer/steps/sync_port_addresses.py b/xos/synchronizer/steps/sync_port_addresses.py
new file mode 100644
index 0000000..553df6f
--- /dev/null
+++ b/xos/synchronizer/steps/sync_port_addresses.py
@@ -0,0 +1,133 @@
+import os
+import requests
+import socket
+import sys
+import base64
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.syncstep import SyncStep
+from core.models import Service, Port, Controller, Tag, Tenant
+from core.models.service import COARSE_KIND
+from services.vsg.models import VSGTenant
+from xos.logger import Logger, logging
+from requests.auth import HTTPBasicAuth
+
+# hpclibrary will be in steps/..
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+logger = Logger(level=logging.INFO)
+
+# XXX should save and load this
+glo_saved_vtn_maps = []
+
+class SyncPortAddresses(SyncStep):
+    requested_interval = 0 # 3600
+    provides=[Port]
+    observes=Port
+
+    def __init__(self, **args):
+        SyncStep.__init__(self, **args)
+
+    def call(self, **args):
+        global glo_saved_vtn_maps
+
+        logger.info("sync'ing vsg tenant to port addresses")
+
+        # build up a dictionary of port-->[wan_addrs] mappings
+        port_addrs = {}
+        for vsg in VSGTenant.get_tenant_objects().all():
+            if not vsg.instance:
+                logger.info("skipping vsg %s because it has no instance" % vsg)
+
+            wan_ip = vsg.wan_container_ip
+            if not wan_ip:
+                logger.info("skipping vsg %s because it has no wan_container_ip" % vsg)
+
+            wan_mac = vsg.wan_container_mac
+            if not wan_mac:
+                logger.info("skipping vsg %s because it has no wan_container_mac" % vsg)
+
+            lan_network = vsg.get_lan_network(vsg.instance)
+            if not lan_network:
+                logger.info("skipping vsg %s because it has no lan_network" % vsg)
+
+            lan_port = Port.objects.filter(instance = vsg.instance, network=lan_network)
+            if not lan_port:
+                logger.info("skipping vsg %s because it has no lan_port" % vsg)
+            lan_port = lan_port[0]
+
+            if not lan_port.port_id:
+                logger.info("skipping vsg %s because its lan_port has no port_id" % vsg)
+
+            if not (lan_port.pk in port_addrs):
+                port_addrs[lan_port.pk] = []
+            entry = {"mac_address": wan_mac, "ip_address": wan_ip}
+            addr_pairs = port_addrs[lan_port.pk]
+            if not entry in addr_pairs:
+                 addr_pairs.append(entry)
+
+            # now do the VM_WAN_IP from the instance
+            if vsg.instance:
+                wan_vm_ip = vsg.wan_vm_ip
+                wan_vm_mac = vsg.wan_vm_mac
+                entry = {"mac_address": wan_vm_mac, "ip_address": wan_vm_ip}
+                if not entry in addr_pairs:
+                    addr_pairs.append(entry)
+
+        # Get all ports in all controllers
+        ports_by_id = {}
+        for controller in Controller.objects.all():
+            if not controller.admin_tenant:
+                logger.info("controller %s has no admin_tenant" % controller)
+                continue
+            try:
+                driver = self.driver.admin_driver(controller = controller)
+                ports = driver.shell.quantum.list_ports()["ports"]
+            except:
+                logger.log_exc("failed to get ports from controller %s" % controller)
+                continue
+
+            for port in ports:
+                ports_by_id[port["id"]] = port
+
+        for port_pk in port_addrs.keys():
+            port = Port.objects.get(pk=port_pk)
+            addr_pairs = port_addrs[port_pk]
+            neutron_port = ports_by_id.get(port.port_id,None)
+            if not neutron_port:
+                logger.info("failed to get neutron port for port %s" % port)
+                continue
+
+            ips = [x["ip_address"] for x in addr_pairs]
+
+            changed = False
+
+            # delete addresses in neutron that don't exist in XOS
+            aaps = neutron_port.get("allowed_address_pairs", [])
+            for aap in aaps[:]:
+                if not aap["ip_address"] in ips:
+                    logger.info("removing address %s from port %s" % (aap["ip_address"], port))
+                    aaps.remove(aap)
+                    changed = True
+
+            aaps_ips = [x["ip_address"] for x in aaps]
+
+            # add addresses in XOS that don't exist in neutron
+            for addr in addr_pairs:
+                if not addr["ip_address"] in aaps_ips:
+                    logger.info("adding address %s to port %s" % (addr, port))
+                    aaps.append( addr )
+                    aaps_ips.append(addr["ip_address"])
+                    changed = True
+
+            if changed:
+                logger.info("updating port %s" % port)
+                driver.shell.quantum.update_port(port.port_id, {"port": {"allowed_address_pairs": aaps}})
+
+
+
+
+
+
+
diff --git a/xos/synchronizer/steps/sync_tenant.py b/xos/synchronizer/steps/sync_tenant.py
new file mode 100644
index 0000000..a0e6cdb
--- /dev/null
+++ b/xos/synchronizer/steps/sync_tenant.py
@@ -0,0 +1,94 @@
+import os
+import requests
+import socket
+import sys
+import base64
+from django.db.models import F, Q
+from xos.config import Config
+from synchronizers.base.syncstep import SyncStep
+from core.models import Service, Tenant
+from core.models.service import COARSE_KIND
+from xos.logger import Logger, logging
+from requests.auth import HTTPBasicAuth
+
+# hpclibrary will be in steps/..
+parentdir = os.path.join(os.path.dirname(__file__),"..")
+sys.path.insert(0,parentdir)
+
+logger = Logger(level=logging.INFO)
+
+# XXX should save and load this
+glo_saved_vtn_maps = []
+
+class SyncTenant(SyncStep):
+    provides=[Tenant]
+    observes=Tenant
+    requested_interval=0
+
+    def __init__(self, **args):
+        SyncStep.__init__(self, **args)
+
+    def get_vtn_onos_service(self):
+#        vtn_tenant = Tenant.objects.filter(name="VTN_ONOS_app")   # XXX fixme - hardcoded
+#        if not vtn_tenant:
+#            raise "No VTN Onos App found"
+#        vtn_tenant = vtn_tenant[0]
+#
+#        vtn_service = vtn_tenant.provider_service
+        vtn_service = Service.objects.filter(name="service_ONOS_VTN")  # XXX fixme - harcoded
+        if not vtn_service:
+            raise "No VTN Onos Service"
+
+        return vtn_service[0]
+
+    def get_vtn_addr(self):
+        vtn_service = self.get_vtn_onos_service()
+
+        if not vtn_service.slices.exists():
+            raise "VTN Service has no slices"
+
+        vtn_slice = vtn_service.slices.all()[0]
+
+        if not vtn_slice.instances.exists():
+            raise "VTN Slice has no instances"
+
+        vtn_instance = vtn_slice.instances.all()[0]
+
+        return vtn_instance.node.name
+
+    def call(self, **args):
+        global glo_saved_vtn_maps
+
+        logger.info("sync'ing vtn services")
+
+        vtn_maps = []
+        for service in Service.objects.all():
+           for id in service.get_vtn_src_ids():
+               dependencies = service.get_vtn_dependencies_ids()
+               if dependencies:
+                   for dependency in dependencies:
+                       vtn_maps.append( (id, dependency) )
+
+        for vtn_map in vtn_maps:
+            if not (vtn_map in glo_saved_vtn_maps):
+                # call vtn rest api to add map
+                url = "http://" + self.get_vtn_addr() + ":8181/onos/cordvtn/service-dependency/%s/%s" % (vtn_map[0], vtn_map[1])
+
+                print "POST %s" % url
+                r = requests.post(url, auth=HTTPBasicAuth('karaf', 'karaf') )    # XXX fixme - hardcoded auth
+                if (r.status_code != 200):
+                    raise Exception("Received error from vtn service (%d)" % r.status_code)
+
+        for vtn_map in glo_saved_vtn_maps:
+            if not vtn_map in vtn_maps:
+                # call vtn rest api to delete map
+                url = "http://" + self.get_vtn_addr() + ":8181/onos/cordvtn/service-dependency/%s/%s" % (vtn_map[0],vtn_map[1])
+
+                print "DELETE %s" % url
+                r = requests.delete(url, auth=HTTPBasicAuth('karaf', 'karaf') )    # XXX fixme - hardcoded auth
+                if (r.status_code != 200):
+                    raise Exception("Received error from vtn service (%d)" % r.status_code)
+
+        glo_saved_vtn_maps = vtn_maps
+        # TODO: save this
+
diff --git a/xos/synchronizer/stop.sh b/xos/synchronizer/stop.sh
new file mode 100755
index 0000000..7ff2b06
--- /dev/null
+++ b/xos/synchronizer/stop.sh
@@ -0,0 +1 @@
+pkill -9 -f vtn-synchronizer.py
diff --git a/xos/synchronizer/supervisor/vtn-observer.conf b/xos/synchronizer/supervisor/vtn-observer.conf
new file mode 100644
index 0000000..714afa7
--- /dev/null
+++ b/xos/synchronizer/supervisor/vtn-observer.conf
@@ -0,0 +1,2 @@
+[program:vtn-observer]
+command=python /opt/xos/observers/vbng/vtn-observer.py -C /opt/xos/observers/vbng/vtn_observer_config
diff --git a/xos/synchronizer/vtn-synchronizer.py b/xos/synchronizer/vtn-synchronizer.py
new file mode 100755
index 0000000..84bec4f
--- /dev/null
+++ b/xos/synchronizer/vtn-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/synchronizer/vtn_synchronizer_config b/xos/synchronizer/vtn_synchronizer_config
new file mode 100644
index 0000000..d931839
--- /dev/null
+++ b/xos/synchronizer/vtn_synchronizer_config
@@ -0,0 +1,44 @@
+
+[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=vtn
+dependency_graph=/opt/xos/synchronizers/vtn/model-deps
+steps_dir=/opt/xos/synchronizers/vtn/steps
+sys_dir=/opt/xos/synchronizers/vtn/sys
+deleters_dir=/opt/xos/synchronizers/vtn/deleters
+log_file=console
+#/var/log/hpc.log
+driver=openstack
+pretend=False
+backoff_disabled=True
+
+[nova]
+ca_ssl_cert=/etc/ssl/certs/ca-certificates.crt
+
+[feefie]
+client_id='vicci_dev_central'
+user_id='pl'
+
+[networking]
+use_vtn=True
diff --git a/xos/templates/vtnadmin.html b/xos/templates/vtnadmin.html
new file mode 100644
index 0000000..a3a2a52
--- /dev/null
+++ b/xos/templates/vtnadmin.html
@@ -0,0 +1,5 @@
+<div class = "row text-center">
+    <div class="col-xs-12">
+        <a href="/admin/vtn/vnrtenant/">vTN Tenants</a>
+    </div>
+</div>
diff --git a/xos/tosca/resources/vtnservice.py b/xos/tosca/resources/vtnservice.py
new file mode 100644
index 0000000..2a5738f
--- /dev/null
+++ b/xos/tosca/resources/vtnservice.py
@@ -0,0 +1,15 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from services.vtn.models import VTNService
+
+from service import XOSService
+
+class XOSVTNService(XOSService):
+    provides = "tosca.nodes.VTNService"
+    xos_model = VTNService
+    copyin_props = ["view_url", "icon_url", "enabled", "published", "public_key", "versionNumber", 'privateGatewayMac', 'localManagementIp', 'ovsdbPort', 'sshPort', 'sshUser', 'sshKeyFile', 'mgmtSubnetBits', 'xosEndpoint', 'xosUser', 'xosPassword']
diff --git a/xos/vtn-onboard.yaml b/xos/vtn-onboard.yaml
new file mode 100644
index 0000000..9141dbd
--- /dev/null
+++ b/xos/vtn-onboard.yaml
@@ -0,0 +1,25 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Onboard the exampleservice
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+    servicecontroller#vtn:
+      type: tosca.nodes.ServiceController
+      properties:
+          base_url: file:///opt/xos_services/vtn/xos/
+          # The following will concatenate with base_url automatically, if
+          # base_url is non-null.
+          models: models.py
+          admin: admin.py
+          admin_template: templates/vtnadmin.html
+          synchronizer: synchronizer/manifest
+          synchronizer_run: vtn-synchronizer.py
+          tosca_resource: tosca/resources/vtnservice.py
+          rest_service: api/service/vtn.py
+          #private_key: file:///opt/xos/key_import/vsg_rsa
+          #public_key: file:///opt/xos/key_import/vsg_rsa.pub
+