blob: 4a8a4cfcbbc386ad9445da5b976fb56dc36cb128 [file] [log] [blame]
Scott Bakera6c687c2018-07-16 15:08:49 -07001# Copyright 2017-present Open Networking Foundation
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15from synchronizers.new_base.syncstep import SyncStep, DeferredException
Scott Baker547dea02018-07-18 15:24:26 -070016from synchronizers.new_base.modelaccessor import model_accessor, FabricCrossconnectServiceInstance, ServiceInstance, BNGPortMapping
Scott Bakera6c687c2018-07-16 15:08:49 -070017
18from xosconfig import Config
19from multistructlog import create_logger
20import urllib
21import requests
22from requests.auth import HTTPBasicAuth
23
24
25class SyncFabricCrossconnectServiceInstance(SyncStep):
26 provides = [FabricCrossconnectServiceInstance]
27 log = create_logger(Config().get('logging'))
28
29 observes = FabricCrossconnectServiceInstance
30
31 @staticmethod
32 def format_url(url):
33 if 'http' in url:
34 return url
35 else:
36 return 'http://%s' % url
37
38 @staticmethod
39 def get_fabric_onos_info(si):
40
41 # get the fabric-crossconnect service
42 fabric_crossconnect = si.owner
43
44 # get the onos_fabric service
45 fabric_onos = [s.leaf_model for s in fabric_crossconnect.provider_services if "onos" in s.name.lower()]
46
47 if len(fabric_onos) == 0:
48 raise Exception('Cannot find ONOS service in provider_services of Fabric-Crossconnect')
49
50 fabric_onos = fabric_onos[0]
51
52 return {
53 'url': SyncFabricCrossconnectServiceInstance.format_url("%s:%s" % (fabric_onos.rest_hostname, fabric_onos.rest_port)),
54 'user': fabric_onos.rest_username,
55 'pass': fabric_onos.rest_password
56 }
57
Scott Baker547dea02018-07-18 15:24:26 -070058 def make_handle(self, s_tag, west_dpid):
59 # Generate a backend_handle that uniquely identifies the cross connect. ONOS doesn't provide us a handle, so
60 # we make up our own. This helps us to detect other FabricCrossconnectServiceInstance using the same
61 # entry, as well as to be able to extract the necessary information to delete the entry later.
62 return "%d/%s" % (s_tag, west_dpid)
63
64 def extract_handle(self, backend_handle):
65 (s_tag, dpid) = backend_handle.split("/",1)
66 s_tag = int(s_tag)
67 return (s_tag, dpid)
Scott Bakera6c687c2018-07-16 15:08:49 -070068
69 def sync_record(self, o):
70 self.log.info("Sync'ing Fabric Crossconnect Service Instance", service_instance=o)
71
72 onos = self.get_fabric_onos_info(o)
73
74 si = ServiceInstance.objects.get(id=o.id)
75
76 s_tag = si.get_westbound_service_instance_properties("s_tag")
Scott Baker547dea02018-07-18 15:24:26 -070077 dpid = si.get_westbound_service_instance_properties("switch_datapath_id")
Scott Bakera6c687c2018-07-16 15:08:49 -070078 west_port = si.get_westbound_service_instance_properties("switch_port")
Scott Bakera6c687c2018-07-16 15:08:49 -070079
Scott Baker547dea02018-07-18 15:24:26 -070080 bng_mappings = BNGPortMapping.objects.filter(s_tag = s_tag)
81 if not bng_mappings:
82 raise Exception("Unable to determine BNG port for s_tag %s" % s_tag)
83 east_port = bng_mappings[0].switch_port
84
85 data = { "deviceId": dpid,
Scott Bakera6c687c2018-07-16 15:08:49 -070086 "vlanId": s_tag,
Matteo Scandolo77943112018-07-25 17:06:58 -070087 "ports": [ int(west_port), int(east_port) ] }
Scott Bakera6c687c2018-07-16 15:08:49 -070088
Scott Baker547dea02018-07-18 15:24:26 -070089 url = onos['url'] + '/onos/segmentrouting/xconnect'
Scott Bakera6c687c2018-07-16 15:08:49 -070090
91 self.log.info("Sending request to ONOS", url=url, body=data)
92
93 r = requests.post(url, json=data, auth=HTTPBasicAuth(onos['user'], onos['pass']))
94
95 if r.status_code != 200:
96 raise Exception("Failed to create fabric crossconnect in ONOS: %s" % r.text)
97
Scott Baker547dea02018-07-18 15:24:26 -070098 o.backend_handle = self.make_handle(s_tag, dpid)
99 o.save(update_fields=["backend_handle"])
100
Scott Bakera6c687c2018-07-16 15:08:49 -0700101 self.log.info("ONOS response", res=r.text)
102
103 def delete_record(self, o):
104 self.log.info("Deleting Fabric Crossconnect Service Instance", service_instance=o)
105
Scott Baker547dea02018-07-18 15:24:26 -0700106 if o.backend_handle:
Scott Bakera6c687c2018-07-16 15:08:49 -0700107 onos = self.get_fabric_onos_info(o)
108
Scott Baker547dea02018-07-18 15:24:26 -0700109 # If some other subscriber is using the same entry, then we shouldn't delete it
110 other_subscribers = FabricCrossconnectServiceInstance.objects.filter(backend_handle=o.backend_handle)
111 other_subscribers = [x for x in other_subscribers if x.id != o.id]
112 if other_subscribers:
113 self.log.info("Other subscribers exist using same fabric crossconnect entry. Not deleting.")
114 return
Scott Bakera6c687c2018-07-16 15:08:49 -0700115
Scott Baker547dea02018-07-18 15:24:26 -0700116 # backend_handle has everything we need in it to delete this entry.
117 (s_tag, dpid) = self.extract_handle(o.backend_handle)
Scott Bakera6c687c2018-07-16 15:08:49 -0700118
Scott Baker547dea02018-07-18 15:24:26 -0700119 data = { "deviceId": dpid,
120 "vlanId": s_tag }
Scott Bakera6c687c2018-07-16 15:08:49 -0700121
122 url = onos['url'] + '/onos/segmentrouting/xconnect'
123
124 r = requests.delete(url, json=data, auth=HTTPBasicAuth(onos['user'], onos['pass']))
125
126 if r.status_code != 204:
127 raise Exception("Failed to remove fabric crossconnect in ONOS: %s" % r.text)
128
129 self.log.info("ONOS response", res=r.text)