CORD-4.0 Service Migration Guide
Service/Tenancy Model Migration
CORD-4.0 makes the following changes:
- Renames
Tenant
toServiceInstance
. - Replaces CORD-3.0's many-to-one tenancy links with a new many-to-many link object called
ServiceInstanceLink
. - Introduces the concept of service interfaces using the
InterfaceType
andServiceInterface
models. - Makes
ServiceDependency
a separate model not directly related to Tenancy models.
Note that for the purposes of this document, we still refer to some R-CORD models using the suffix "Tenant" rather than "ServiceInstance". As time permits, those R-CORD models will be renamed. New services are recommended to use the suffix ServiceInstance rather than Tenant.
Migrating existing Tenants
The base class has been changed from Tenant
to ServiceInstance
. This may require an xproto
change, for example:
- message VTRTenant (Tenant){
+ message VTRTenant (ServiceInstance){
Note that TenantWithContainer
has not yet been renamed (at some point in the future it may become ServiceInstanceWithContainer
), so models inheriting from TenantWithContainer
are fine for now.
Differences in ServiceInstance fields
A few fields in ServiceInstance have been changed from what they were in Tenant
:
Tenant.provider_service
-->ServiceInstance.owner
Creating links between Service Instances (ServiceInstanceLink
objects)
A common pattern in CORD-3.0 model policies is to create a new Tenant and link it to an existing model. For example,
t = VRouterTenant(provider_service=vrouter_service,
subscriber_tenant=some_vsg_tenant)
t.save()
In the above example, the relationship between the new VRouterTenant and some_vsg_tenant
was captured by the field subscriber_tenant
. This field no longer exists in CORD-4.0 and needs to be replaced with a link:
t = VRouterTenant(owner=vrouter_service)
t.save()
l = ServiceInstanceLink(provider_service_instance = t,
subscriber_service_interface=some_vsg_tenant)
l.save()
Traversing links between Service Instances
In CORD-3.0, it was possible to determine the subscriber of a Tenant by looking at the Tenant's subscriber_*
properties. For example,
subscriber = some_vrouter_tenant.subscriber_tenant
vsg_tenant = VSGTenant.objects.get(id = subscriber.id)
# now, do something with vsg_tenant
In CORD-4.0 you will need to traverse ServiceInstanceLink
objects instead:
for link in some_vrouter_tenant.provided_links.all():
if link.subscriber_service_instance:
subscriber = link.subscriber_service_instance
vsg_tenant = subscriber.leaf_model
# now, do something with vsg_tenant
You can also walk in the opposite direction:
for link in some_vsg_tenant.subscribed_links.all():
if link.subscriber_service_instance:
provider = link.provider_service_instance
vrouter_tenant = provider.leaf_model
# now, do something with vrouter_tenant
Note that since the service instance graph now supports true many-to-many relations, it's common to have to use for loops as described above to cover cases where an object may be linked to many providers or many subscribers. If it's a known constraint that only one object may be linked, then it may be reasonable to omit the for loop and use provided_links.first()
or subscribed_links.first()
instead of .all()
.
Also note that leaf_model
is a property that will automatically cast any base object to its descendant class. For example, if you have a generic ServiceInstance
object, and that ServiceInstance
is really a VSGTenant
, then leaf_model
will perform that conversion for you automatically.
Removing links between Service Instances
Links are removed by deleting the ServiceInstanceLink
object. For example,
# delete all links between some_vsg_tenant and some_vrouter_tenant
for link in ServiceInstanceLink.objects.filter(provider_service_instance_id=some_vsg_tenant.id, subscriber_service_instance_id=some_vrouter_instance.id):
link.delete()
Creating ServiceInterfaces
ServiceInterfaces
allow you to type the links between ServiceInstances
. For example, if one ServiceInstance
provides a WAN
interface and another ServiceInstance
uses a LAN
interface, you can explicitly connect those two interfaces. These are currently created in Tosca. For example,
in#lanside:
type: tosca.nodes.InterfaceType
properties:
direction: in
out#lanside:
type: tosca.nodes.InterfaceType
properties:
direction: out
volt_lanside:
type: tosca.nodes.ServiceInterface
requirements:
- service:
node: service#volt
relationship: tosca.relationships.MemberOfService
- interface:
node: out#lanside
relationship: tosca.relationships.IsType
vsg_lanside:
type: tosca.nodes.ServiceInterface
requirements:
- service:
node: service#vsg
relationship: tosca.relationships.MemberOfService
- interface:
node: in#lanside
relationship: tosca.relationships.IsType
This example creates a lanside
interface that is present in both the VOLT
and VSG
services.
Interfaces are currently optional, but may become mandatory in the next release. Until then, you can optionally associate links with interfaces. For example,
interface_type = InterfaceType.objects.get(name="lanside", direction="in")
interface = VSGService.Interfaces.get(interface_type=interface_type)
t = VSGTenant(owner=vsg_service)
t.save()
l = ServiceInstanceLink(provider_service_instance = t,
provider_service_interface = interface,
subscriber_service_interface=some_volt_tenant)
l.save()
As ServiceInterface
are not mandatory, it's suggested that you perform the other migration steps, and leave ServiceInterfaces
until everything else is working.