blob: 44e29d732be89b3a52b4139902ed653072d82907 [file] [log] [blame]
Scott Bakerb3a80de2016-09-06 16:51:27 -07001import os
2import requests
3import socket
4import sys
5import base64
Scott Bakerb3a80de2016-09-06 16:51:27 -07006from xos.config import Config
Scott Bakerb3a80de2016-09-06 16:51:27 -07007from services.vtn.vtnnetport import VTNNetwork, VTNPort
Scott Baker61b41a92017-03-14 13:04:57 -07008from synchronizers.new_base.syncstep import SyncStep
9from synchronizers.new_base.modelaccessor import *
Scott Bakerb3a80de2016-09-06 16:51:27 -070010from xos.logger import Logger, logging
11from requests.auth import HTTPBasicAuth
12
Scott Bakerb3a80de2016-09-06 16:51:27 -070013logger = Logger(level=logging.INFO)
14
15# XXX should save and load this
16glo_saved_vtn_maps = []
17glo_saved_networks = {}
18glo_saved_ports = {}
19
20class SyncVTNService(SyncStep):
21 provides=[Service]
22 observes=Service
23 requested_interval=0
24
25 def __init__(self, **args):
26 SyncStep.__init__(self, **args)
27
28 def get_vtn_onos_service(self):
Scott Baker61b41a92017-03-14 13:04:57 -070029 vtn_service = ONOSService.objects.filter(name="ONOS_CORD") # XXX fixme - harcoded
Scott Bakerb3a80de2016-09-06 16:51:27 -070030 if not vtn_service:
31 raise "No VTN Onos Service"
32
33 return vtn_service[0]
34
35 def get_vtn_auth(self):
36 return HTTPBasicAuth('karaf', 'karaf') # XXX fixme - hardcoded auth
37
38 def get_vtn_addr(self):
39 vtn_service = self.get_vtn_onos_service()
40
41 if vtn_service.rest_hostname:
42 return vtn_service.rest_hostname
43
Scott Bakerff016682016-11-28 09:53:13 -080044 # code below this point is for ONOS running in a slice, and is
45 # probably outdated
46
Scott Bakerb3a80de2016-09-06 16:51:27 -070047 if not vtn_service.slices.exists():
48 raise "VTN Service has no slices"
49
50 vtn_slice = vtn_service.slices.all()[0]
51
52 if not vtn_slice.instances.exists():
53 raise "VTN Slice has no instances"
54
55 vtn_instance = vtn_slice.instances.all()[0]
56
57 return vtn_instance.node.name
58
Scott Bakerff016682016-11-28 09:53:13 -080059 def get_vtn_port(self):
60 vtn_service = self.get_vtn_onos_service()
61
62 if vtn_service.rest_port:
63 return vtn_service.rest_port
64
65 # code below this point is for ONOS running in a slice, and is
66 # probably outdated
67
68 raise Exception("Must set rest_port")
69
Scott Bakerb3a80de2016-09-06 16:51:27 -070070 def sync_legacy_vtn_api(self):
71 global glo_saved_vtn_maps
72
73 logger.info("sync'ing vtn services")
74
75 vtn_maps = []
76 for service in Service.objects.all():
77 for id in service.get_vtn_src_ids():
78 dependencies = service.get_vtn_dependencies_ids()
79 if dependencies:
80 for dependency in dependencies:
81 vtn_maps.append( (id, dependency) )
82
83 for vtn_map in vtn_maps:
84 if not (vtn_map in glo_saved_vtn_maps):
85 # call vtn rest api to add map
Scott Baker62918292017-03-13 16:23:46 -070086 url = "http://" + self.get_vtn_addr() + ":" + str(self.get_vtn_port()) + "/onos/cordvtn/service-dependency/%s/%s" % (vtn_map[0], vtn_map[1])
Scott Bakerb3a80de2016-09-06 16:51:27 -070087
88 print "POST %s" % url
89 r = requests.post(url, auth=self.get_vtn_auth() )
90 if (r.status_code != 200):
91 raise Exception("Received error from vtn service (%d)" % r.status_code)
92
93 for vtn_map in glo_saved_vtn_maps:
94 if not vtn_map in vtn_maps:
95 # call vtn rest api to delete map
Scott Baker62918292017-03-13 16:23:46 -070096 url = "http://" + self.get_vtn_addr() + ":" + str(self.get_vtn_port()) + "/onos/cordvtn/service-dependency/%s/%s" % (vtn_map[0],vtn_map[1])
Scott Bakerb3a80de2016-09-06 16:51:27 -070097
98 print "DELETE %s" % url
99 r = requests.delete(url, auth=self.get_vtn_auth() )
100 if (r.status_code != 200):
101 raise Exception("Received error from vtn service (%d)" % r.status_code)
102
103 glo_saved_vtn_maps = vtn_maps
104 # TODO: save this
105
Scott Baker90f780d2016-09-07 22:57:28 -0700106 def get_method(self, url, id):
107 url_with_id = "%s/%s" % (url, id)
108 r = requests.get(url_with_id, auth=self.get_vtn_auth())
109 if (r.status_code==200):
110 method="PUT"
111 url = url_with_id
112 req_func = requests.put
113 exists=True
114 else:
115 method="POST"
116 req_func = requests.post
117 exists=False
118 return (exists, url, method, req_func)
119
Scott Bakerb3a80de2016-09-06 16:51:27 -0700120 def sync_service_networks(self):
121 valid_ids = []
122 for network in Network.objects.all():
123 network = VTNNetwork(network)
Scott Bakerf2291012016-09-08 13:19:45 -0700124
125 if not network.id:
126 continue
127
Scott Baker52563812017-02-13 08:33:27 -0800128 if (network.type=="PRIVATE") and (not network.providerNetworks):
129 logger.info("Skipping network %s because it has no relevant state" % network.id)
130 continue
131
Scott Bakerb3a80de2016-09-06 16:51:27 -0700132 valid_ids.append(network.id)
Scott Bakerf2291012016-09-08 13:19:45 -0700133
Scott Bakerb3a80de2016-09-06 16:51:27 -0700134 if (glo_saved_networks.get(network.id, None) != network.to_dict()):
Scott Baker62918292017-03-13 16:23:46 -0700135 (exists, url, method, req_func) = self.get_method("http://" + self.get_vtn_addr() + ":" + str(self.get_vtn_port()) + "/onos/cordvtn/serviceNetworks", network.id)
Scott Bakerb3a80de2016-09-06 16:51:27 -0700136
Scott Baker90f780d2016-09-07 22:57:28 -0700137 logger.info("%sing VTN API for network %s" % (method, network.id))
138
Scott Bakerb3a80de2016-09-06 16:51:27 -0700139 logger.info("URL: %s" % url)
140
Scott Baker90f780d2016-09-07 22:57:28 -0700141 # clean the providerNetworks list
142 providerNetworks = [{"id": x["id"], "bidirectional": x["bidirectional"]} for x in network.providerNetworks]
143
144 data = {"ServiceNetwork": {"id": network.id,
Scott Bakerb3a80de2016-09-06 16:51:27 -0700145 "type": network.type,
Scott Baker90f780d2016-09-07 22:57:28 -0700146 "providerNetworks": providerNetworks} }
Scott Bakerb3a80de2016-09-06 16:51:27 -0700147 logger.info("DATA: %s" % str(data))
148
Scott Baker90f780d2016-09-07 22:57:28 -0700149 r=req_func(url, json=data, auth=self.get_vtn_auth() )
150 if (r.status_code in [200,201]):
Scott Bakerb3a80de2016-09-06 16:51:27 -0700151 glo_saved_networks[network.id] = network.to_dict()
152 else:
153 logger.error("Received error from vtn service (%d)" % r.status_code)
154
Scott Baker90f780d2016-09-07 22:57:28 -0700155
Scott Bakerb3a80de2016-09-06 16:51:27 -0700156 for network_id in glo_saved_networks.keys():
157 if network_id not in valid_ids:
158 logger.info("DELETEing VTN API for network %s" % network_id)
159
Scott Baker62918292017-03-13 16:23:46 -0700160 url = "http://" + self.get_vtn_addr() + ":" + str(self.get_vtn_port()) + "/onos/cordvtn/serviceNetworks/%s" % network_id
Scott Bakerb3a80de2016-09-06 16:51:27 -0700161 logger.info("URL: %s" % url)
162
163 r = requests.delete(url, auth=self.get_vtn_auth() )
164 if (r.status_code in [200,204]):
165 del glo_saved_networks[network_id]
166 else:
167 logger.error("Received error from vtn service (%d)" % r.status_code)
168
169 def sync_service_ports(self):
170 valid_ids = []
171 for port in Port.objects.all():
172 port = VTNPort(port)
Scott Bakerf2291012016-09-08 13:19:45 -0700173
174 if not port.id:
175 continue
176
Scott Baker29067002016-09-28 17:14:45 -0700177 if (not port.vlan_id) and (not port.floating_address_pairs):
178 logger.info("Skipping port %s because it has no relevant state" % port.id)
179 continue
180
Scott Bakerb3a80de2016-09-06 16:51:27 -0700181 valid_ids.append(port.id)
Scott Bakerf2291012016-09-08 13:19:45 -0700182
Scott Bakerb3a80de2016-09-06 16:51:27 -0700183 if (glo_saved_ports.get(port.id, None) != port.to_dict()):
Scott Baker62918292017-03-13 16:23:46 -0700184 (exists, url, method, req_func) = self.get_method("http://" + self.get_vtn_addr() + ":" + str(self.get_vtn_port()) + "/onos/cordvtn/servicePorts", port.id)
Scott Bakerb3a80de2016-09-06 16:51:27 -0700185
Scott Baker90f780d2016-09-07 22:57:28 -0700186 logger.info("%sing VTN API for port %s" % (method, port.id))
187
Scott Bakerb3a80de2016-09-06 16:51:27 -0700188 logger.info("URL: %s" % url)
189
Scott Baker90f780d2016-09-07 22:57:28 -0700190 data = {"ServicePort": {"id": port.id,
Scott Bakerb3a80de2016-09-06 16:51:27 -0700191 "vlan_id": port.vlan_id,
Scott Baker90f780d2016-09-07 22:57:28 -0700192 "floating_address_pairs": port.floating_address_pairs} }
Scott Bakerb3a80de2016-09-06 16:51:27 -0700193 logger.info("DATA: %s" % str(data))
194
Scott Baker90f780d2016-09-07 22:57:28 -0700195 r=req_func(url, json=data, auth=self.get_vtn_auth() )
Scott Bakerf2291012016-09-08 13:19:45 -0700196 if (r.status_code in [200,201]):
Scott Bakerb3a80de2016-09-06 16:51:27 -0700197 glo_saved_ports[port.id] = port.to_dict()
198 else:
199 logger.error("Received error from vtn service (%d)" % r.status_code)
200
201 for port_id in glo_saved_ports.keys():
202 if port_id not in valid_ids:
203 logger.info("DELETEing VTN API for port %s" % port_id)
204
Scott Baker62918292017-03-13 16:23:46 -0700205 url = "http://" + self.get_vtn_addr() + ":" + str(self.get_vtn_port()) + "/onos/cordvtn/servicePorts/%s" % port_id
Scott Bakerb3a80de2016-09-06 16:51:27 -0700206 logger.info("URL: %s" % url)
207
208 r = requests.delete(url, auth=self.get_vtn_auth() )
209 if (r.status_code in [200,204]):
210 del glo_saved_ports[port_id]
211 else:
212 logger.error("Received error from vtn service (%d)" % r.status_code)
213
214 def call(self, **args):
215 vtn_service = VTNService.get_service_objects().all()
216 if not vtn_service:
217 raise Exception("No VTN Service")
218
219 vtn_service = vtn_service[0]
220
Scott Baker855a9df2016-09-09 09:23:50 -0700221 if vtn_service.vtnAPIVersion>=2:
Scott Bakerb3a80de2016-09-06 16:51:27 -0700222 # version 2 means use new API
223 logger.info("Using New API")
224 self.sync_service_networks()
225 self.sync_service_ports()
226 else:
227 # default to legacy
228 logger.info("Using Old API")
Scott Bakercdbb71e2016-10-26 15:50:03 -0700229 raise Exception("VTN API Version 1 is no longer supported by VTN Synchronizer")
230 #self.sync_legacy_vtn_api()
Scott Bakerb3a80de2016-09-06 16:51:27 -0700231
232