CORD-1337 change content_type from ids to strings
Change-Id: Id26e4205c87297a8e173109a57b5578cc254b5e4
diff --git a/xos/core/admin.py b/xos/core/admin.py
index af24612..8752f24 100644
--- a/xos/core/admin.py
+++ b/xos/core/admin.py
@@ -848,8 +848,7 @@
fieldsets = [
(None, {'fields': fieldList, 'classes': ['suit-tab suit-tab-general']})]
# node no longer directly connected to deployment
- #inlines = [DeploymentPrivilegeInline,NodeInline,TagInline,ImageDeploymentsInline]
- inlines = [DeploymentPrivilegeInline, TagInline,
+ inlines = [DeploymentPrivilegeInline,
ImageDeploymentsInline, SiteDeploymentInline]
list_display = ['backend_status_icon', 'name']
list_display_links = ('backend_status_icon', 'name', )
@@ -1129,7 +1128,7 @@
'login_base', 'site_url', 'enabled')
list_display_links = ('backend_status_icon', 'name', )
filter_horizontal = ('deployments',)
- inlines = [SliceInline, UserInline, TagInline,
+ inlines = [SliceInline, UserInline,
SitePrivilegeInline, SiteNodeInline]
admin_inlines = [ControllerSiteInline]
search_fields = ['name']
@@ -1279,7 +1278,7 @@
'serviceClass', 'slice_url', 'max_instances')
list_display_links = ('backend_status_icon', 'name', )
normal_inlines = [SlicePrivilegeInline, InstanceInline,
- TagInline, SliceNetworkInline]
+ SliceNetworkInline]
inlines = normal_inlines
admin_inlines = [ControllerSliceInline]
suit_form_includes = (('slice_instance_tab.html', 'bottom', 'instances'),)
@@ -1292,7 +1291,6 @@
('slicenetworks', 'Networks'),
('sliceprivileges', 'Privileges'),
('instances', 'Instances'),
- ('tags', 'Tags'),
]
request = getattr(_thread_locals, "request", None)
@@ -1380,7 +1378,7 @@
# try to make this work post-demo.
if (obj is not None) and (obj.name == "mysite_vcpe"):
cord_vcpe_inlines = [SlicePrivilegeInline, CordInstanceInline,
- TagInline, SliceNetworkInline]
+ SliceNetworkInline]
inlines = []
for inline_class in cord_vcpe_inlines:
@@ -1499,16 +1497,16 @@
list_display_links = ('backend_status_icon', 'name', )
list_filter = ('site_deployment',)
- inlines = [TagInline, InstanceInline]
+ inlines = [InstanceInline]
fieldsets = [('Node Details', {'fields': ['backend_status_text', 'name', 'site_deployment'], 'classes':['suit-tab suit-tab-details']}),
('Labels', {'fields': ['nodelabels'], 'classes':['suit-tab suit-tab-labels']})]
readonly_fields = ('backend_status_text', )
user_readonly_fields = ['name', 'site_deployment']
- user_readonly_inlines = [TagInline, InstanceInline]
+ user_readonly_inlines = [InstanceInline]
suit_form_tabs = (('details', 'Node Details'), ('instances',
- 'Instances'), ('labels', 'Labels'), ('tags', 'Tags'))
+ 'Instances'), ('labels', 'Labels'))
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == 'site':
@@ -1538,13 +1536,12 @@
}
fields = '__all__'
-
class TagAdmin(XOSBaseAdmin):
list_display = ['backend_status_icon', 'service',
- 'name', 'value', 'content_type', 'content_object', ]
+ 'name', 'value', 'content_type', 'object_id', ]
list_display_links = list_display
user_readonly_fields = ['service', 'name',
- 'value', 'content_type', 'content_object', ]
+ 'value', 'content_type', 'object_id', ]
user_readonly_inlines = []
@@ -1574,9 +1571,9 @@
'all_ips_string', 'instance_id', )
suit_form_tabs = (('general', 'Instance Details'), ('ports', 'Ports'),
- ('container', 'Container Settings'), ('tags', 'Tags'))
+ ('container', 'Container Settings'),)
- inlines = [TagInline, InstancePortInline]
+ inlines = [InstancePortInline]
user_readonly_fields = ['slice', 'deployment',
'node', 'ip', 'instance_name', 'flavor', 'image']
@@ -1655,40 +1652,6 @@
return field
-# class ContainerPortInline(XOSTabularInline):
-# fields = ['backend_status_icon', 'network', 'container', 'ip', 'mac', 'segmentation_id']
-# readonly_fields = ("backend_status_icon", "ip", "mac", "segmentation_id")
-# model = Port
-# selflink_fieldname = "network"
-# extra = 0
-# verbose_name_plural = "Ports"
-# verbose_name = "Port"
-# suit_classes = 'suit-tab suit-tab-ports'
-
-# class ContainerAdmin(XOSBaseAdmin):
-# fieldsets = [
-# ('Container Details', {'fields': ['backend_status_text', 'slice', 'node', 'docker_image', 'volumes', 'no_sync'], 'classes': ['suit-tab suit-tab-general'], })
-# ]
-# readonly_fields = ('backend_status_text', )
-# list_display = ['backend_status_icon', 'id']
-# list_display_links = ('backend_status_icon', 'id', )
-#
-# suit_form_tabs =(('general', 'Container Details'), ('ports', 'Ports'))
-#
-# inlines = [TagInline, ContainerPortInline]
-#
-# def formfield_for_foreignkey(self, db_field, request, **kwargs):
-# if db_field.name == 'slice':
-# kwargs['queryset'] = Slice.select_by_user(request.user)
-#
-# return super(ContainerAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
-#
-# def queryset(self, request):
-# # admins can see all instances. Users can only see instances of
-# # the slices they belong to.
-# return Container.select_by_user(request.user)
-
-
class UserCreationForm(forms.ModelForm):
"""A form for creating new users. Includes all the required
fields, plus a repeated password."""
diff --git a/xos/core/models/attic/networkparameter_model.py b/xos/core/models/attic/networkparameter_model.py
index 2bbfbe7..d2e301ba 100644
--- a/xos/core/models/attic/networkparameter_model.py
+++ b/xos/core/models/attic/networkparameter_model.py
@@ -1,5 +1,3 @@
-content_object = GenericForeignKey('content_type', 'object_id')
-
def __unicode__(self):
return self.parameter.name
diff --git a/xos/core/models/attic/port_top.py b/xos/core/models/attic/port_top.py
index 67dabf0..5fa8ca9 100644
--- a/xos/core/models/attic/port_top.py
+++ b/xos/core/models/attic/port_top.py
@@ -8,15 +8,15 @@
def get_parameters(self):
parameter_dict = {}
- instance_type = ContentType.objects.get_for_model(self)
- for param in NetworkParameter.objects.filter(content_type__pk=instance_type.id, object_id=self.id):
+ instance_type = self.get_content_type_key()
+ for param in NetworkParameter.objects.filter(content_type=instance_type, object_id=self.id):
parameter_dict[param.parameter.name] = param.value
return parameter_dict
def set_parameter(self, name, value):
- instance_type = ContentType.objects.get_for_model(self)
- existing_params = NetworkParameter.objects.filter(parameter__name=name, content_type__pk=instance_type.id, object_id=self.id)
+ instance_type = self.get_content_type_key()
+ existing_params = NetworkParameter.objects.filter(parameter__name=name, content_type=instance_type, object_id=self.id)
if existing_params:
p=existing_params[0]
p.value = value
@@ -27,8 +27,8 @@
p.save()
def unset_parameter(self, name):
- instance_type = ContentType.objects.get_for_model(self)
- existing_params = NetworkParameter.objects.filter(parameter__name=name, content_type__pk=instance_type.id, object_id=self.id)
+ instance_type = self.get_content_type_key()
+ existing_params = NetworkParameter.objects.filter(parameter__name=name, content_type=instance_type, object_id=self.id)
for p in existing_params:
p.delete()
diff --git a/xos/core/models/attic/tag_model.py b/xos/core/models/attic/tag_model.py
index c6437e8..7872679 100644
--- a/xos/core/models/attic/tag_model.py
+++ b/xos/core/models/attic/tag_model.py
@@ -1,5 +1,3 @@
-content_object = GenericForeignKey('content_type', 'object_id') # Not generated by xproto
-
def __unicode__(self):
return self.name
@@ -8,7 +6,7 @@
@classmethod
def select_by_content_object(cls, obj):
- return cls.objects.filter(content_type=ContentType.objects.get_for_model(obj), object_id=obj.id)
+ return cls.objects.filter(content_type=obj.get_content_type_key(), object_id=obj.id)
@staticmethod
def select_by_user(user):
diff --git a/xos/core/models/instance.xproto b/xos/core/models/instance.xproto
index b411bd4..bc86813 100644
--- a/xos/core/models/instance.xproto
+++ b/xos/core/models/instance.xproto
@@ -17,5 +17,4 @@
required string isolation = 14 [default = "vm", choices = "(('vm', 'Virtual Machine'), ('container', 'Container'), ('container_vm', 'Container In VM'))", max_length = 30, blank = False, null = False, db_index = False];
optional string volumes = 15 [help_text = "Comma-separated list of directories to expose to parent context", null = True, db_index = False, blank = True];
optional manytoone parent->Instance:instance = 16 [help_text = "Parent Instance for containers nested inside of VMs", null = True, db_index = True, blank = True];
- required manytomany tags->Tag = 17 [db_index = False, null = False, blank = True];
}
diff --git a/xos/core/models/networkparameter.xproto b/xos/core/models/networkparameter.xproto
index 81585ee..a162d9a 100644
--- a/xos/core/models/networkparameter.xproto
+++ b/xos/core/models/networkparameter.xproto
@@ -3,6 +3,6 @@
message NetworkParameter (PlCoreBase){
required manytoone parameter->NetworkParameterType:networkparameters = 1 [help_text = "The type of the parameter", null = False, db_index = True, blank = False];
required string value = 2 [help_text = "The value of this parameter", max_length = 1024, null = False, db_index = False, blank = False];
- required manytoone content_type->ContentType:networkparameter = 3 [db_index = True, null = False, blank = False];
- required uint32 object_id = 4 [db_index = False, null = False, blank = False];
+ required string content_type = 4 [max_length = 1024, content_type = "stripped", blank = False, help_text = "Content type id linked to this network parameter", null = False, db_index = False];
+ required uint32 object_id = 4 [db_index = False, null = False, blank = False, help_text = "Object linked to this NetworkParameter"];
}
diff --git a/xos/core/models/node.xproto b/xos/core/models/node.xproto
index 3a88b6a..9000fbb 100644
--- a/xos/core/models/node.xproto
+++ b/xos/core/models/node.xproto
@@ -4,5 +4,4 @@
required string name = 1 [max_length = 200, content_type = "stripped", blank = False, help_text = "Name of the Node", null = False, db_index = False];
required manytoone site_deployment->SiteDeployment:nodes = 2 [db_index = True, null = False, blank = False];
optional manytoone site->Site:nodes = 3 [db_index = True, null = True, blank = True];
- required manytomany tags->Tag = 4 [db_index = False, null = False, blank = True];
}
diff --git a/xos/core/models/plcorebase.py b/xos/core/models/plcorebase.py
index dd86bac..a99fd15 100644
--- a/xos/core/models/plcorebase.py
+++ b/xos/core/models/plcorebase.py
@@ -13,6 +13,7 @@
from journal import journal_object
from django.db.models.deletion import Collector
from django.db import router
+from django.contrib.contenttypes.models import ContentType
import redis
from redis import ConnectionError
@@ -430,9 +431,25 @@
return d
+ def get_content_type_key(self):
+ ct = ContentType.objects.get_for_model(self.__class__)
+ return "%s.%s" % (ct.app_label, ct.model)
+
+ @staticmethod
+ def get_content_type_from_key(key):
+ (app_name, model_name) = key.split(".")
+ return ContentType.objects.get_by_natural_key(app_name, model_name)
+
+ @staticmethod
+ def get_content_object(content_type, object_id):
+ ct = PlCoreBase.get_content_type_from_key(content_type)
+ cls = ct.model_class()
+ return cls.objects.get(id=object_id)
+
class ModelLink:
def __init__(self,dest,via,into=None):
self.dest=dest
self.via=via
self.into=into
+
diff --git a/xos/core/models/role.xproto b/xos/core/models/role.xproto
index 2ebde68..cb36794 100644
--- a/xos/core/models/role.xproto
+++ b/xos/core/models/role.xproto
@@ -4,5 +4,5 @@
required string role_type = 1 [db_index = False, max_length = 80, null = False, content_type = "stripped", blank = False];
optional string role = 2 [db_index = False, max_length = 80, null = True, content_type = "stripped", blank = True];
required string description = 3 [db_index = False, max_length = 120, null = False, content_type = "stripped", blank = False];
- required manytoone content_type->ContentType:role = 4 [db_index = True, null = False, blank = False];
+ required string content_type = 4 [max_length = 1024, content_type = "stripped", blank = False, help_text = "Content type id linked to this role", null = False, db_index = False];
}
diff --git a/xos/core/models/site.xproto b/xos/core/models/site.xproto
index fe3f9f5..ce2fbd1 100644
--- a/xos/core/models/site.xproto
+++ b/xos/core/models/site.xproto
@@ -12,5 +12,4 @@
required bool is_public = 9 [help_text = "Indicates the visibility of this site to other members", default = True, null = False, db_index = False, blank = True];
required string abbreviated_name = 10 [db_index = False, max_length = 80, null = False, content_type = "stripped", blank = False];
required manytomany deployments->Deployment/SiteDeployment:sites = 11 [help_text = "Select which sites are allowed to host nodes in this deployment", null = False, db_index = False, blank = True];
- required manytomany tags->Tag = 12 [db_index = False, null = False, blank = True];
}
diff --git a/xos/core/models/slice.xproto b/xos/core/models/slice.xproto
index 5b1acaa..fde818f 100644
--- a/xos/core/models/slice.xproto
+++ b/xos/core/models/slice.xproto
@@ -16,5 +16,4 @@
optional manytoone default_node->Node:slices = 15 [db_index = True, null = True, blank = True];
optional string mount_data_sets = 16 [default = "GenBank", max_length = 256, content_type = "stripped", blank = True, null = True, db_index = False];
required string default_isolation = 17 [default = "vm", choices = "(('vm', 'Virtual Machine'), ('container', 'Container'), ('container_vm', 'Container In VM'))", max_length = 30, blank = False, null = False, db_index = False];
- required manytomany tags->Tag = 18 [db_index = False, null = False, blank = True];
}
diff --git a/xos/core/models/tag.xproto b/xos/core/models/tag.xproto
index 45662a8..6e5daef 100644
--- a/xos/core/models/tag.xproto
+++ b/xos/core/models/tag.xproto
@@ -4,6 +4,6 @@
required manytoone service->Service:tags = 1 [help_text = "The Service this Tag is associated with", null = False, db_index = True, blank = False];
required string name = 2 [help_text = "The name of this tag", max_length = 128, null = False, db_index = True, blank = False];
required string value = 3 [max_length = 1024, content_type = "stripped", blank = False, help_text = "The value of this tag", null = False, db_index = False];
- required manytoone content_type->ContentType:tag = 4 [db_index = True, null = False, blank = False];
- required uint32 object_id = 5 [db_index = False, null = False, blank = False];
+ required string content_type = 4 [max_length = 1024, content_type = "stripped", blank = False, help_text = "Content type id linked to this tag", null = False, db_index = False];
+ required uint32 object_id = 5 [db_index = False, null = False, blank = False, help_text = "Object linked to this tag"];
}
diff --git a/xos/core/models/user.py b/xos/core/models/user.py
index ff7bece..eb11c18 100644
--- a/xos/core/models/user.py
+++ b/xos/core/models/user.py
@@ -20,6 +20,7 @@
from django.utils import timezone
from timezones.fields import TimeZoneField
from journal import journal_object
+from django.contrib.contenttypes.models import ContentType
import redis
from redis import ConnectionError
@@ -608,6 +609,21 @@
for db in self.userdashboardviews.all():
db.delete()
+ def get_content_type_key(self):
+ ct = ContentType.objects.get_for_model(self.__class__)
+ return "%s.%s" % (ct.app_label, ct.model)
+
+ @staticmethod
+ def get_content_type_from_key(key):
+ (app_name, model_name) = key.split(".")
+ return ContentType.objects.get_by_natural_key(app_name, model_name)
+
+ @staticmethod
+ def get_content_object(content_type, object_id):
+ ct = User.get_content_type_from_key(content_type)
+ cls = ct.model_class()
+ return cls.objects.get(id=object_id)
+
class UserDashboardView(PlCoreBase):
user = models.ForeignKey(User, related_name='userdashboardviews')
diff --git a/xos/coreapi/apihelper.py b/xos/coreapi/apihelper.py
index 6503f12..875c89f 100644
--- a/xos/coreapi/apihelper.py
+++ b/xos/coreapi/apihelper.py
@@ -192,7 +192,7 @@
bases = [x for x in bases if issubclass(x, PlCoreBase) or issubclass(x, User)]
p_obj.class_names = ",".join( [x.__name__ for x in bases] )
- p_obj.self_content_type_id = ContentType.objects.get_for_model(obj).id
+ p_obj.self_content_type_id = obj.get_content_type_key()
return p_obj
diff --git a/xos/coreapi/protos/xosoptions.proto b/xos/coreapi/protos/xosoptions.proto
index 40e8017..7602c95 100644
--- a/xos/coreapi/protos/xosoptions.proto
+++ b/xos/coreapi/protos/xosoptions.proto
@@ -25,6 +25,6 @@
}
extend google.protobuf.MessageOptions {
- int32 contentTypeId = 1001;
+ string contentTypeId = 1001;
}
diff --git a/xos/tools/apigen/protobuf.template.txt b/xos/tools/apigen/protobuf.template.txt
index 4df40ac..26034e5 100644
--- a/xos/tools/apigen/protobuf.template.txt
+++ b/xos/tools/apigen/protobuf.template.txt
@@ -32,7 +32,7 @@
{% for object in generator.all() %}
message {{ object.camel() }} {
- option (contentTypeId) = {{ object.content_type_id }};
+ option (contentTypeId) = "{{ object.app_name }}.{{ object|string() }}";
{%- for field in object.all_fields %}
oneof {{ field.name }}_present {
{%- if (field.get_internal_type() == "CharField") or (field.get_internal_type() == "TextField") or (field.get_internal_type() == "SlugField") %}
@@ -66,7 +66,7 @@
repeated int32 {{ ref.related_name }}_ids = {{ loop.index+100 }} [(reverseForeignKey).modelName = "{{ ref.camel() }}"];
{%- endfor %}
string class_names = 201;
- int32 self_content_type_id = 202;
+ string self_content_type_id = 202;
}
message {{ object.camel() }}s {
diff --git a/xos/tosca/resources/tag.py b/xos/tosca/resources/tag.py
index 955fabf..ab7ec30 100644
--- a/xos/tosca/resources/tag.py
+++ b/xos/tosca/resources/tag.py
@@ -18,7 +18,7 @@
target_name = self.get_requirement("tosca.relationships.TagsObject", throw_exception=throw_exception)
if target_name:
target_model = self.engine.name_to_xos_model(self.user, target_name)
- args["content_type"] = ContentType.objects.get_for_model(target_model)
+ args["content_type"] = target_model.get_content_type_key()
args["object_id"] = target_model.id
service_name = self.get_requirement("tosca.relationships.MemberOfService", throw_exception=throw_exception)
diff --git a/xos/xos/xosapi.py b/xos/xos/xosapi.py
index 2ebcd41..ba0281b 100644
--- a/xos/xos/xosapi.py
+++ b/xos/xos/xosapi.py
@@ -788,7 +788,7 @@
return None
class Meta:
model = NetworkParameter
- fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_need_delete','backend_need_reap','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','value','object_id','parameter','content_type',)
+ fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_need_delete','backend_need_reap','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','value','content_type','object_id','parameter',)
class NetworkParameterIdSerializer(XOSModelSerializer):
id = IdField()
@@ -804,7 +804,7 @@
return None
class Meta:
model = NetworkParameter
- fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_need_delete','backend_need_reap','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','value','object_id','parameter','content_type',)
+ fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_need_delete','backend_need_reap','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','value','content_type','object_id','parameter',)
@@ -1006,7 +1006,7 @@
return None
class Meta:
model = Tag
- fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_need_delete','backend_need_reap','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','value','object_id','service','content_type',)
+ fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_need_delete','backend_need_reap','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','value','content_type','object_id','service',)
class TagIdSerializer(XOSModelSerializer):
id = IdField()
@@ -1022,7 +1022,7 @@
return None
class Meta:
model = Tag
- fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_need_delete','backend_need_reap','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','value','object_id','service','content_type',)
+ fields = ('humanReadableName', 'validators', 'id','created','updated','enacted','policed','backend_register','backend_need_delete','backend_need_reap','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','value','content_type','object_id','service',)
@@ -3371,7 +3371,7 @@
serializer_class = NetworkParameterSerializer
id_serializer_class = NetworkParameterIdSerializer
filter_backends = (filters.DjangoFilterBackend,)
- filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_need_delete','backend_need_reap','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','value','object_id','parameter','content_type',)
+ filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_need_delete','backend_need_reap','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','value','content_type','object_id','parameter',)
def get_serializer_class(self):
no_hyperlinks=False
@@ -3653,7 +3653,7 @@
serializer_class = TagSerializer
id_serializer_class = TagIdSerializer
filter_backends = (filters.DjangoFilterBackend,)
- filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_need_delete','backend_need_reap','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','value','object_id','service','content_type',)
+ filter_fields = ('id','created','updated','enacted','policed','backend_register','backend_need_delete','backend_need_reap','backend_status','deleted','write_protect','lazy_blocked','no_sync','no_policy','name','value','content_type','object_id','service',)
def get_serializer_class(self):
no_hyperlinks=False
diff --git a/xos/xos_client/xosapi/convenience/port.py b/xos/xos_client/xosapi/convenience/port.py
index e6d56ed..c74a58b 100644
--- a/xos/xos_client/xosapi/convenience/port.py
+++ b/xos/xos_client/xosapi/convenience/port.py
@@ -5,7 +5,7 @@
def get_parameters(self):
parameter_dict = {}
- for param in self.stub.NetworkParameter.objects.filter(content_type_id=self.self_content_type_id, object_id=self.id):
+ for param in self.stub.NetworkParameter.objects.filter(content_type=self.self_content_type_id, object_id=self.id):
parameter_dict[param.parameter.name] = param.value
return parameter_dict
diff --git a/xos/xos_client/xosapi/convenience/tag.py b/xos/xos_client/xosapi/convenience/tag.py
new file mode 100644
index 0000000..19338ce
--- /dev/null
+++ b/xos/xos_client/xosapi/convenience/tag.py
@@ -0,0 +1,7 @@
+from xosapi.orm import ORMWrapper, register_convenience_wrapper
+
+class ORMWrapperTag(ORMWrapper):
+ def get_generic_foreignkeys(self):
+ return [{"name": "content_object", "content_type": "content_type", "id": "object_id"}]
+
+register_convenience_wrapper("Tag", ORMWrapperTag)
diff --git a/xos/xos_client/xosapi/convenience/vsgtenant.py b/xos/xos_client/xosapi/convenience/vsgtenant.py
index d58c757..0d3fa90 100644
--- a/xos/xos_client/xosapi/convenience/vsgtenant.py
+++ b/xos/xos_client/xosapi/convenience/vsgtenant.py
@@ -50,7 +50,7 @@
@property
def wan_vm_ip(self):
- tags = self.stub.Tag.objects.filter(name="vm_vrouter_tenant", object_id=self.instance.id, content_type_id=self.instance.self_content_type_id)
+ tags = self.stub.Tag.objects.filter(name="vm_vrouter_tenant", object_id=self.instance.id, content_type=self.instance.self_content_type_id)
if tags:
tenant = self.stub.VRouterTenant.objects.get(id=int(tags[0].value))
return tenant.public_ip
@@ -59,7 +59,7 @@
@property
def wan_vm_mac(self):
- tags = self.stub.Tag.objects.filter(name="vm_vrouter_tenant", object_id=self.instance.id, content_type_id=self.instance.self_content_type_id)
+ tags = self.stub.Tag.objects.filter(name="vm_vrouter_tenant", object_id=self.instance.id, content_type=self.instance.self_content_type_id)
if tags:
tenant = self.stub.VRouterTenant.objects.get(id=int(tags[0].value))
return tenant.public_mac
diff --git a/xos/xos_client/xosapi/convenience/vtrtenant.py b/xos/xos_client/xosapi/convenience/vtrtenant.py
new file mode 100644
index 0000000..62856c1
--- /dev/null
+++ b/xos/xos_client/xosapi/convenience/vtrtenant.py
@@ -0,0 +1,7 @@
+from xosapi.orm import ORMWrapper, register_convenience_wrapper
+
+class ORMWrapperVTRTenant(ORMWrapper):
+ def get_generic_foreignkeys(self):
+ return [{"name": "target", "content_type": "target_type", "id": "target_id"}]
+
+register_convenience_wrapper("VTRTenant", ORMWrapperVTRTenant)
diff --git a/xos/xos_client/xosapi/fake_stub.py b/xos/xos_client/xosapi/fake_stub.py
index 6cfce8a..dc56178 100644
--- a/xos/xos_client/xosapi/fake_stub.py
+++ b/xos/xos_client/xosapi/fake_stub.py
@@ -9,13 +9,14 @@
ContentTypeMap = {}
class FakeObj(object):
- def __init__(self, defaults={"id": 0}, **kwargs):
+ def __init__(self, fields=[], **kwargs):
super(FakeObj, self).__setattr__("is_set", {})
super(FakeObj, self).__setattr__("fields", [])
- for (k,v) in defaults.items():
- self.fields.append(k)
- setattr(self, k, v)
+ for f in fields:
+ name = f["name"]
+ self.fields.append(name)
+ setattr(self, name, f["default"])
super(FakeObj, self).__setattr__("is_set", {})
for (k,v) in kwargs.items():
@@ -48,10 +49,32 @@
return self.extensions[name]
return default
+class FakeFieldOption(object):
+ def __init__(self, modelName=None):
+ self.modelName = modelName
+
+class FakeField(object):
+ def __init__(self, field):
+ extensions = {}
+
+ fk_model = field.get("fk_model", None)
+ if fk_model:
+ extensions["xos.foreignKey"] = FakeFieldOption(modelName=fk_model)
+
+ fk_reverse = field.get("fk_reverse", None)
+ if fk_reverse:
+ extensions["xos.reverseForeignKey"] = FakeFieldOption(modelName=fk_reverse)
+
+ self.Extensions = FakeExtensionManager(self, extensions)
+
+ def GetOptions(self):
+ return self
+
class FakeDescriptor(object):
def __init__(self, objName):
global ContentTypeIdCounter
global ContentTypeMap
+ self.objName = objName
if objName in ContentTypeMap:
ct = ContentTypeMap[objName]
else:
@@ -65,21 +88,38 @@
@property
def fields_by_name(self):
- # TODO: everything
- return {}
+ cls = globals()[self.objName]
+ fbn = {}
+ for field in cls.FIELDS:
+ fake_field = FakeField(field)
+ fbn[ field["name"] ] = fake_field
+
+ return fbn
class Slice(FakeObj):
+ FIELDS = ( {"name": "id", "default": 0},
+ {"name": "name", "default": ""},
+ {"name": "site_id", "default": 0, "fk_model": "Site"} )
+
def __init__(self, **kwargs):
- defaults = {"id": 0,
- "name": ""}
- return super(Slice, self).__init__(defaults, **kwargs)
+ return super(Slice, self).__init__(self.FIELDS, **kwargs)
DESCRIPTOR = FakeDescriptor("Slice")
+class Site(FakeObj):
+ FIELDS = ( {"name": "id", "default": 0},
+ {"name": "name", "default": ""},
+ {"name": "slice_ids", "default": 0, "fk_reverse": "Slice"} )
+
+ def __init__(self, **kwargs):
+ return super(Site, self).__init__(self.FIELDS, **kwargs)
+
+ DESCRIPTOR = FakeDescriptor("Site")
+
class FakeStub(object):
def __init__(self):
self.objs = {}
- for name in ["Slice"]:
+ for name in ["Slice", "Site"]:
setattr(self, "Get%s" % name, functools.partial(self.get, name))
setattr(self, "List%s" % name, functools.partial(self.list, name))
setattr(self, "Create%s" % name, functools.partial(self.create, name))
@@ -118,7 +158,7 @@
class FakeSymDb(object):
def __init__(self):
self._classes = {}
- for name in ["Slice"]:
+ for name in ["Slice", "Site"]:
self._classes["xos.%s" % name] = globals()[name]
diff --git a/xos/xos_client/xosapi/orm.py b/xos/xos_client/xosapi/orm.py
index a030b6a..35f7a3f 100644
--- a/xos/xos_client/xosapi/orm.py
+++ b/xos/xos_client/xosapi/orm.py
@@ -47,6 +47,12 @@
"""
super(ORMWrapper, self).__setattr__(name, value)
+ def get_generic_foreignkeys(self):
+ """ this is a placeholder until generic foreign key support is added
+ to xproto.
+ """
+ return []
+
def gen_fkmap(self):
fkmap = {}
@@ -65,6 +71,9 @@
if type_name in all_field_names:
fkmap[name[:-3]] = {"src_fieldName": name, "ct_fieldName": type_name, "kind": "generic_fk"}
+ for gfk in self.get_generic_foreignkeys():
+ fkmap[gfk["name"]] = {"src_fieldName": gfk["id"], "ct_fieldName": gfk["content_type"], "kind": "generic_fk"}
+
return fkmap
def gen_reverse_fkmap(self):
@@ -495,4 +504,5 @@
import convenience.user
import convenience.slice
import convenience.port
-
+import convenience.tag
+import convenience.vtrtenant