add coarse tenancy support
diff --git a/xos/core/admin.py b/xos/core/admin.py
index b3cee88..50f3f53 100644
--- a/xos/core/admin.py
+++ b/xos/core/admin.py
@@ -721,6 +721,32 @@
 
         return tabs
 
+class ProviderTenantInline(XOSTabularInline):
+    model = CoarseTenant
+    fields = ['provider_service', 'subscriber_service', 'connect_method']
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-servicetenants'
+    fk_name = 'provider_service'
+    verbose_name = 'provided tenant'
+    verbose_name_plural = 'provided tenants'
+
+    def queryset(self, request):
+        qs = super(ProviderTenantInline, self).queryset(request)
+        return qs.filter(kind="coarse")
+
+class SubscriberTenantInline(XOSTabularInline):
+    model = CoarseTenant
+    fields = ['provider_service', 'subscriber_service', 'connect_method']
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-servicetenants'
+    fk_name = 'subscriber_service'
+    verbose_name = 'subscribed tenant'
+    verbose_name_plural = 'subscribed tenants'
+
+    def queryset(self, request):
+        qs = super(SubscriberTenantInline, self).queryset(request)
+        return qs.filter(kind="coarse")
+
 class ServiceAttrAsTabInline(XOSTabularInline):
     model = ServiceAttribute
     fields = ['name','value']
@@ -732,7 +758,7 @@
     list_display_links = ('backend_status_icon', 'name', )
     fieldList = ["backend_status_text","name","kind","description","versionNumber","enabled","published","view_url","icon_url"]
     fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']})]
-    inlines = [ServiceAttrAsTabInline,SliceInline]
+    inlines = [ServiceAttrAsTabInline,SliceInline,ProviderTenantInline,SubscriberTenantInline]
     readonly_fields = ('backend_status_text', )
 
     user_readonly_fields = fieldList
@@ -740,6 +766,7 @@
     suit_form_tabs =(('general', 'Service Details'),
         ('slices','Slices'),
         ('serviceattrs','Additional Attributes'),
+        ('servicetenants','Tenancy'),
     )
 
 class SiteNodeInline(XOSTabularInline):
diff --git a/xos/core/models/__init__.py b/xos/core/models/__init__.py
index 928679b..81bf4cc 100644
--- a/xos/core/models/__init__.py
+++ b/xos/core/models/__init__.py
@@ -1,7 +1,7 @@
 from .plcorebase import PlCoreBase,PlCoreBaseManager,PlCoreBaseDeletionManager,PlModelMixIn
 from .project import Project
 from .singletonmodel import SingletonModel
-from .service import Service, Tenant
+from .service import Service, Tenant, CoarseTenant
 from .service import ServiceAttribute
 from .tag import Tag
 from .role import Role
diff --git a/xos/core/models/service.py b/xos/core/models/service.py
index afb4949..f7259ae 100644
--- a/xos/core/models/service.py
+++ b/xos/core/models/service.py
@@ -42,16 +42,19 @@
         The provider is always a Service.
     """
 
+    CONNECTIVITY_CHOICES = (('public', 'Public'), ('private', 'Private'), ('na', 'Not Applicable'))
+
     # when subclassing a service, redefine KIND to describe the new service
     KIND = "generic"
 
     kind = StrippedCharField(max_length=30, default=KIND)
     provider_service = models.ForeignKey(Service, related_name='tenants')
-    subscriber_service = models.ForeignKey(Service, related_name='subscriptions', blank=True, null=True)
+    subscriber_service = models.ForeignKey(Service, related_name='subscriptions', blank=True, null=True)      # can we drop this ?
     subscriber_tenant = models.ForeignKey("Tenant", related_name='subscriptions', blank=True, null=True)
     subscriber_user = models.ForeignKey("User", related_name='subscriptions', blank=True, null=True)
     service_specific_id = StrippedCharField(max_length=30)
     service_specific_attribute = models.TextField()
+    connect_method = models.CharField(null=False, blank=False, max_length=30, choices=CONNECTIVITY_CHOICES, default="na")
 
     def __init__(self, *args, **kwargs):
         # for subclasses, set the default kind appropriately
@@ -103,4 +106,16 @@
             if conflicts:
                 raise XOSDuplicateKey("service_specific_id %s already exists" % self.service_specific_id, fields={"service_specific_id": "duplicate key"})
 
+class CoarseTenant(Tenant):
+    class Meta:
+        proxy = True
 
+    KIND = "coarse"
+
+    def save(self, *args, **kwargs):
+        if (not self.subscriber_service):
+            raise XOSValidationError("subscriber_service cannot be null")
+        if (self.subscriber_tenant or self.subscriber_user):
+            raise XOSValidationError("subscriber_tenant and subscriber_user must be null")
+
+        super(CoarseTenant,self).save()