SEBA-108 Allow get_westbound method to get fields directly from si;
Use base class convenience wrapper if no descendant is available
Change-Id: I087465a5694bd73b67493710678266df3dd6c8e3
diff --git a/xos/xos_client/xosapi/convenience/serviceinstance.py b/xos/xos_client/xosapi/convenience/serviceinstance.py
index ffb6bc3..76beb7b 100644
--- a/xos/xos_client/xosapi/convenience/serviceinstance.py
+++ b/xos/xos_client/xosapi/convenience/serviceinstance.py
@@ -74,7 +74,10 @@
link = ServiceInstanceLink(provider_service_instance=eastbound_si, subscriber_service_instance=si)
link.save()
- def get_westbound_service_instance_properties(self, prop_name):
+ def get_westbound_service_instance_properties(self, prop_name, include_self=False):
+ if include_self and hasattr(self, prop_name):
+ return getattr(self, prop_name)
+
wi = self.westbound_service_instances
if len(wi) == 0:
diff --git a/xos/xos_client/xosapi/fake_stub.py b/xos/xos_client/xosapi/fake_stub.py
index ac35805..88a54b7 100644
--- a/xos/xos_client/xosapi/fake_stub.py
+++ b/xos/xos_client/xosapi/fake_stub.py
@@ -142,7 +142,8 @@
class Controller(FakeObj):
FIELDS = ( {"name": "id", "default": 0},
{"name": "name", "default": ""},
- {"name": "deployment_id", "default": 0, "fk_model": "Deployment"}
+ {"name": "deployment_id", "default": 0, "fk_model": "Deployment"},
+ {"name": "class_names", "default": "Controller"}
)
def __init__(self, **kwargs):
@@ -153,6 +154,7 @@
class Deployment(FakeObj):
FIELDS = ( {"name": "id", "default": 0},
{"name": "name", "default": ""},
+ {"name": "class_names", "default": "Deployment"}
)
def __init__(self, **kwargs):
@@ -163,7 +165,8 @@
class User(FakeObj):
FIELDS = ( {"name": "id", "default": 0},
{"name": "email", "default": ""},
- {"name": "site_id", "default": 0, "fk_model": "Site"}, )
+ {"name": "site_id", "default": 0, "fk_model": "Site"},
+ {"name": "class_names", "default": "User"} )
def __init__(self, **kwargs):
return super(User, self).__init__(self.FIELDS, **kwargs)
@@ -178,7 +181,8 @@
{"name": "creator_id", "default": 0, "fk_model": "User"},
{"name": "networks_ids", "default": [], "fk_reverse": "Network"},
{"name": "network", "default": ""},
- {"name": "leaf_model_name", "default": "Slice"} )
+ {"name": "leaf_model_name", "default": "Slice"},
+ {"name": "class_names", "default": "Slice"} )
def __init__(self, **kwargs):
return super(Slice, self).__init__(self.FIELDS, **kwargs)
@@ -189,7 +193,8 @@
FIELDS = ( {"name": "id", "default": 0},
{"name": "name", "default": ""},
{"name": "slices_ids", "default": [], "fk_reverse": "Slice"},
- {"name": "leaf_model_name", "default": "Site"})
+ {"name": "leaf_model_name", "default": "Site"},
+ {"name": "class_names", "default": "Site"})
def __init__(self, **kwargs):
return super(Site, self).__init__(self.FIELDS, **kwargs)
@@ -200,7 +205,8 @@
FIELDS = ( {"name": "id", "default": 0},
{"name": "name", "default": ""},
{"name": "slices_ids", "default": [], "fk_reverse": "Slice"},
- {"name": "leaf_model_name", "default": "Service"})
+ {"name": "leaf_model_name", "default": "Service"},
+ {"name": "class_names", "default": "Service"})
def __init__(self, **kwargs):
return super(Service, self).__init__(self.FIELDS, **kwargs)
@@ -210,7 +216,8 @@
class ServiceInstance(FakeObj):
FIELDS = ( {"name": "id", "default": 0},
{"name": "owher", "default": 0, "fk_model": "Service"},
- {"name": "leaf_model_name", "default": "ServiceInstance"})
+ {"name": "leaf_model_name", "default": "ServiceInstance"},
+ {"name": "class_names", "default": "ServiceInstance"})
def __init__(self, **kwargs):
return super(ServiceInstance, self).__init__(self.FIELDS, **kwargs)
@@ -220,7 +227,8 @@
class ONOSService(FakeObj):
FIELDS = ( {"name": "id", "default": 0},
{"name": "name", "default": ""},
- {"name": "leaf_model_name", "default": "ONOSService"})
+ {"name": "leaf_model_name", "default": "ONOSService"},
+ {"name": "class_names", "default": "ONOSService,Service"})
BASES = ["Service"]
@@ -235,7 +243,8 @@
{"name": "owner_id", "default": 0, "fk_model": "Slice"},
{"name": "template_id", "default": 0, "fk_model": "NetworkTemplate"},
{"name": "controllernetworks_ids", "default": [], "fk_reverse": "ControllerNetwork"},
- {"name": "leaf_model_name", "default": "Network"})
+ {"name": "leaf_model_name", "default": "Network"},
+ {"name": "class_names", "default": "Network"})
def __init__(self, **kwargs):
return super(Network, self).__init__(self.FIELDS, **kwargs)
@@ -246,7 +255,8 @@
FIELDS = ( {"name": "id", "default": 0},
{"name": "name", "default": ""},
{"name": "vtn_kind", "default": ""},
- {"name": "leaf_model_name", "default": "NetworkTemplate"})
+ {"name": "leaf_model_name", "default": "NetworkTemplate"},
+ {"name": "class_names", "default": "NetworkTemplate"})
def __init__(self, **kwargs):
return super(NetworkTemplate, self).__init__(self.FIELDS, **kwargs)
@@ -257,7 +267,8 @@
FIELDS = ( {"name": "id", "default": 0},
{"name": "network_id", "default": 0, "fk_model": "Network"},
{"name": "controller_id", "default": 0, "fk_model": "Controller"},
- {"name": "leaf_model_name", "default": "ControllerNetwork"})
+ {"name": "leaf_model_name", "default": "ControllerNetwork"},
+ {"name": "class_names", "default": "ControllerNetwork"})
def __init__(self, **kwargs):
return super(ControllerNetwork, self).__init__(self.FIELDS, **kwargs)
@@ -268,7 +279,8 @@
FIELDS = ( {"name": "id", "default": 0},
{"name": "network_id", "default": 0, "fk_model": "Network"},
{"name": "slice_id", "default": 0, "fk_model": "Slice"},
- {"name": "leaf_model_name", "default": "ControllerNetwork"})
+ {"name": "leaf_model_name", "default": "NetworkSlice"},
+ {"name": "class_names", "default": "NetworkSlice"})
def __init__(self, **kwargs):
return super(NetworkSlice, self).__init__(self.FIELDS, **kwargs)
@@ -282,7 +294,8 @@
{"name": "value", "default": ""},
{"name": "content_type", "default": None},
{"name": "object_id", "default": None},
- {"name": "leaf_model_name", "default": "Tag"})
+ {"name": "leaf_model_name", "default": "Tag"},
+ {"name": "class_names", "default": "Tag"})
def __init__(self, **kwargs):
return super(Tag, self).__init__(self.FIELDS, **kwargs)
@@ -291,7 +304,8 @@
class TestModel(FakeObj):
FIELDS = ( {"name": "id", "default": 0},
- {"name": "intfield", "default": 0} )
+ {"name": "intfield", "default": 0},
+ {"name": "class_names", "default": "TestModel"} )
def __init__(self, **kwargs):
return super(TestModel, self).__init__(self.FIELDS, **kwargs)
diff --git a/xos/xos_client/xosapi/orm.py b/xos/xos_client/xosapi/orm.py
index 7d6d263..40af7dd 100644
--- a/xos/xos_client/xosapi/orm.py
+++ b/xos/xos_client/xosapi/orm.py
@@ -644,9 +644,26 @@
convenience_wrappers[class_name] = wrapper
def make_ORMWrapper(wrapped_class, *args, **kwargs):
- if wrapped_class.__class__.__name__ in convenience_wrappers:
+ cls = None
+
+ if (not cls) and wrapped_class.__class__.__name__ in convenience_wrappers:
cls = convenience_wrappers[wrapped_class.__class__.__name__]
- else:
+
+ if (not cls):
+ # Search the list of class names for this model to see if we have any applicable wrappers. The list is always
+ # sorted from most specific to least specific, so the first one we find will automatically be the most relevant
+ # one. If we don't find any, then default to ORMWrapper
+
+ # Note: Only works on objects that have been fetched from the server, not objects that are created on the
+ # client. This is because wrapped_class.class_names is filled in by the server.
+
+ # TODO(smbaker): Ought to be able to make this work with newly created objects after they are saved.
+
+ for name in wrapped_class.class_names.split(","):
+ if name in convenience_wrappers:
+ cls = convenience_wrappers[name]
+
+ if (not cls):
cls = ORMWrapper
return cls(wrapped_class, *args, **kwargs)
diff --git a/xos/xos_client/xosapi/test_wrapper.py b/xos/xos_client/xosapi/test_wrapper.py
index 6eef1f3..cd185a7 100644
--- a/xos/xos_client/xosapi/test_wrapper.py
+++ b/xos/xos_client/xosapi/test_wrapper.py
@@ -132,6 +132,22 @@
self.assertEqual(service_one.get_service_instance_class().model_name, "ServiceInstance")
+ def test_wrapper_from__class__dot_name(self):
+ """ The Service model has a wrapper, so it should be returned when make_ORMWrapper looks for a wrapper based
+ on the class name.
+ """
+ orm = self.make_coreapi()
+ obj = orm.Service()
+ self.assertEqual(obj.__class__.__name__, "ORMWrapperService")
+
+ def test_wrapper_from_class_names(self):
+ """ ONOSService._wrapped_class.class_names is "ONOSService, Service" so we should fall back to getting the
+ Service wrapper.
+ """
+ orm = self.make_coreapi()
+ obj = orm.ONOSService()
+ self.assertEqual(obj.__class__.__name__, "ORMWrapperService")
+
def main():
global USE_FAKE_STUB
global xos_grpc_client