blob: 863f40c55cdf3fd23d8af95d8365d69e4a7f2e61 [file] [log] [blame]
Scott Baker252f6922018-08-22 16:57:23 -07001
2# Copyright 2017-present Open Networking Foundation
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16
Scott Bakere7b55e42019-04-01 17:18:03 -070017from xosapi.orm import register_convenience_wrapper
Scott Baker252f6922018-08-22 16:57:23 -070018from xosapi.convenience.service import ORMWrapperService
19
Scott Bakere7b55e42019-04-01 17:18:03 -070020
Scott Baker252f6922018-08-22 16:57:23 -070021class ORMWrapperFabricCrossconnectService(ORMWrapperService):
22
23 """ Calling convention. Assume the subscribing service does approximately (needs some checks to see
24 if the methods exist before calling them) the following in its model_policy:
25
26 if not eastbound_service.validate_links(self):
27 eastbound_service.acquire_service_instance(self)
28 """
29
30 def acquire_service_instance(self, subscriber_service_instance):
31 """ Given a subscriber_service_instance:
32 1) If there is an eligible provider_service_instance that can be used, then link to it
33 2) Otherwise, create a new provider_service_instance and link to it.
34 """
35 (s_tag, switch_datapath_id, source_port) = self._get_west_fields(subscriber_service_instance)
36
37 FabricCrossconnectServiceInstance = self.stub.FabricCrossconnectServiceInstance
38 ServiceInstanceLink = self.stub.ServiceInstanceLink
39
40 candidates = FabricCrossconnectServiceInstance.objects.filter(owner_id=self.id,
41 s_tag=s_tag,
42 switch_datapath_id=switch_datapath_id,
43 source_port=source_port)
44
45 if candidates:
46 provider_service_instance = candidates[0]
47 else:
48 provider_service_instance = FabricCrossconnectServiceInstance(owner=self,
Scott Bakere7b55e42019-04-01 17:18:03 -070049 s_tag=s_tag,
50 switch_datapath_id=switch_datapath_id,
51 source_port=source_port)
Scott Baker252f6922018-08-22 16:57:23 -070052 provider_service_instance.save()
53
54 # NOTE: Lack-of-atomicity vulnerability -- provider_service_instance could be deleted before we created the
55 # link.
56
57 link = ServiceInstanceLink(provider_service_instance=provider_service_instance,
58 subscriber_service_instance=subscriber_service_instance)
59 link.save()
60
61 return provider_service_instance
62
63 def validate_links(self, subscriber_service_instance):
64 """ Validate existing links between the provider and subscriber service instances. If a valid link exists,
65 then return it. Return [] otherwise.
66
67 As a side-effect, delete any invalid links.
68 """
69
70 # Short-cut -- if there are no subscriber links then we can skip getting all the properties.
71 if not subscriber_service_instance.subscribed_links.exists():
72 return None
73
74 (s_tag, switch_datapath_id, source_port) = self._get_west_fields(subscriber_service_instance)
75
76 matched = []
77 for link in subscriber_service_instance.subscribed_links.all():
78 if link.provider_service_instance.owner.id == self.id:
79 fcsi = link.provider_service_instance.leaf_model
80 if (fcsi.s_tag == s_tag) and (fcsi.switch_datapath_id == switch_datapath_id) and \
Scott Bakere7b55e42019-04-01 17:18:03 -070081 (fcsi.source_port == source_port):
Scott Baker252f6922018-08-22 16:57:23 -070082 matched.append(fcsi)
83 else:
84 link.delete()
85 return matched
86
87 def _get_west_fields(self, subscriber_si):
88 """ _get_west_fields()
89
90 Helper function to inspect westbound service instance for fields that will be used inside of
91 FabricCrossconnectServiceInstance.
92 """
93
94 s_tag = subscriber_si.get_westbound_service_instance_properties("s_tag", include_self=True)
Scott Bakere7b55e42019-04-01 17:18:03 -070095 switch_datapath_id = subscriber_si.get_westbound_service_instance_properties(
96 "switch_datapath_id", include_self=True)
Scott Baker252f6922018-08-22 16:57:23 -070097 source_port = subscriber_si.get_westbound_service_instance_properties("switch_port", include_self=True)
98
99 if (s_tag is None):
100 raise Exception("Subscriber ServiceInstance %s s-tag is None" % subscriber_si.id)
101
102 if (not switch_datapath_id):
103 raise Exception("Subscriber ServiceInstance %s switch_datapath_id is unset" % subscriber_si.id)
104
105 if (source_port is None):
106 raise Exception("Subscriber ServiceInstance %s switch_port is None" % subscriber_si.id)
107
108 s_tag = int(s_tag)
109 source_port = int(source_port)
110
111 return (s_tag, switch_datapath_id, source_port)
112
Scott Bakere7b55e42019-04-01 17:18:03 -0700113
Scott Baker252f6922018-08-22 16:57:23 -0700114register_convenience_wrapper("FabricCrossconnectService", ORMWrapperFabricCrossconnectService)