blob: e4d4b4f9f5a3f24e8da4249c2817c4e5f9e531c2 [file] [log] [blame]
Matteo Scandolo0e7912c2017-08-08 13:05:24 -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 Bakerb3a80de2016-09-06 16:51:27 -070017import os
18import requests
19import socket
20import sys
21import base64
Scott Bakerd2439532017-08-11 09:55:50 -070022from synchronizers.vtn.vtnnetport import VTNNetwork, VTNPort
Scott Baker61b41a92017-03-14 13:04:57 -070023from synchronizers.new_base.syncstep import SyncStep
24from synchronizers.new_base.modelaccessor import *
Scott Bakerb3a80de2016-09-06 16:51:27 -070025from xos.logger import Logger, logging
26from requests.auth import HTTPBasicAuth
27
Scott Bakerb3a80de2016-09-06 16:51:27 -070028logger = Logger(level=logging.INFO)
29
30# XXX should save and load this
Scott Bakerb3a80de2016-09-06 16:51:27 -070031glo_saved_networks = {}
32glo_saved_ports = {}
33
34class SyncVTNService(SyncStep):
35 provides=[Service]
36 observes=Service
37 requested_interval=0
38
39 def __init__(self, **args):
40 SyncStep.__init__(self, **args)
41
Scott Bakerd2439532017-08-11 09:55:50 -070042 def get_vtn_onos_app(self, vtn_service):
43 links = vtn_service.subscribed_links.all()
44 for link in links:
45 # We're looking for an ONOS App. It's the only ServiceInstance that VTN can be implemented on.
46 if link.provider_service_instance.leaf_model_name != "ONOSApp":
47 continue
Scott Bakerb3a80de2016-09-06 16:51:27 -070048
Scott Bakerd2439532017-08-11 09:55:50 -070049 # TODO: Rather than checking model name, check for the right interface
50 # NOTE: Deferred until new Tosca engine is in place.
Scott Bakerb3a80de2016-09-06 16:51:27 -070051
Scott Bakerd2439532017-08-11 09:55:50 -070052 #if not link.provider_service_interface:
53 # logger.warning("Link %s does not have a provider_service_interface. Skipping" % link)
54 # continue
55 #
56 #if link.provider_service_interface.interface_type.name != "onos_app_interface":
57 # logger.warning("Link %s provider_service_interface type is not equal to onos_app_interface" % link)
58 # continue
Scott Bakerb3a80de2016-09-06 16:51:27 -070059
Scott Bakerd2439532017-08-11 09:55:50 -070060 # cast from ServiceInstance to ONOSApp
61 app = link.provider_service_instance.leaf_model
62 return app
Scott Bakerb3a80de2016-09-06 16:51:27 -070063
Scott Bakerd2439532017-08-11 09:55:50 -070064 raise Exception("No ServiceInstanceLink from VTN Service to VTN ONOS App")
Scott Bakerb3a80de2016-09-06 16:51:27 -070065
Scott Bakerd2439532017-08-11 09:55:50 -070066 def get_vtn_endpoint(self, vtn_service):
67 """ Get connection info for the ONOS that is hosting the VTN ONOS App.
Scott Bakerff016682016-11-28 09:53:13 -080068
Scott Bakerd2439532017-08-11 09:55:50 -070069 returns (hostname, port, auth)
70 """
71 app = self.get_vtn_onos_app(vtn_service)
72 # cast from Service to ONOSService
73 onos = app.owner.leaf_model
74 if not (onos.rest_hostname):
75 raise Exception("onos.rest_hostname is not set")
76 if not (onos.rest_port):
77 raise Exception("onos.rest_port is not set")
78 if not (onos.rest_password):
79 raise Exception("onos.rest_password is not set")
80 if not (onos.rest_username):
81 raise Exception("onos.rest_username is not set")
82 auth = HTTPBasicAuth(onos.rest_username, onos.rest_password)
83 return (onos.rest_hostname, onos.rest_port, auth)
Scott Bakerb3a80de2016-09-06 16:51:27 -070084
Scott Bakerd2439532017-08-11 09:55:50 -070085 def get_method(self, auth, url, id):
Scott Baker90f780d2016-09-07 22:57:28 -070086 url_with_id = "%s/%s" % (url, id)
Scott Bakerd2439532017-08-11 09:55:50 -070087 r = requests.get(url_with_id, auth=auth)
Scott Baker90f780d2016-09-07 22:57:28 -070088 if (r.status_code==200):
89 method="PUT"
90 url = url_with_id
91 req_func = requests.put
92 exists=True
93 else:
94 method="POST"
95 req_func = requests.post
96 exists=False
97 return (exists, url, method, req_func)
98
Scott Bakerd2439532017-08-11 09:55:50 -070099 def sync_service_networks(self, vtn_service):
100 (onos_hostname, onos_port, onos_auth) = self.get_vtn_endpoint(vtn_service)
101
Scott Bakerb3a80de2016-09-06 16:51:27 -0700102 valid_ids = []
103 for network in Network.objects.all():
104 network = VTNNetwork(network)
Scott Bakerf2291012016-09-08 13:19:45 -0700105
106 if not network.id:
107 continue
108
Scott Baker52563812017-02-13 08:33:27 -0800109 if (network.type=="PRIVATE") and (not network.providerNetworks):
110 logger.info("Skipping network %s because it has no relevant state" % network.id)
111 continue
112
Scott Bakerb3a80de2016-09-06 16:51:27 -0700113 valid_ids.append(network.id)
Scott Bakerf2291012016-09-08 13:19:45 -0700114
Scott Bakerb3a80de2016-09-06 16:51:27 -0700115 if (glo_saved_networks.get(network.id, None) != network.to_dict()):
Scott Bakerd2439532017-08-11 09:55:50 -0700116 (exists, url, method, req_func) = self.get_method(onos_auth, "http://%s:%d/onos/cordvtn/serviceNetworks" % (onos_hostname, onos_port), network.id)
Scott Bakerb3a80de2016-09-06 16:51:27 -0700117
Scott Baker90f780d2016-09-07 22:57:28 -0700118 logger.info("%sing VTN API for network %s" % (method, network.id))
119
Scott Bakerb3a80de2016-09-06 16:51:27 -0700120 logger.info("URL: %s" % url)
121
Scott Baker90f780d2016-09-07 22:57:28 -0700122 # clean the providerNetworks list
123 providerNetworks = [{"id": x["id"], "bidirectional": x["bidirectional"]} for x in network.providerNetworks]
124
125 data = {"ServiceNetwork": {"id": network.id,
Scott Bakerb3a80de2016-09-06 16:51:27 -0700126 "type": network.type,
Scott Baker90f780d2016-09-07 22:57:28 -0700127 "providerNetworks": providerNetworks} }
Scott Bakerb3a80de2016-09-06 16:51:27 -0700128 logger.info("DATA: %s" % str(data))
129
Scott Bakerd2439532017-08-11 09:55:50 -0700130 r=req_func(url, json=data, auth=onos_auth )
Scott Baker90f780d2016-09-07 22:57:28 -0700131 if (r.status_code in [200,201]):
Scott Bakerb3a80de2016-09-06 16:51:27 -0700132 glo_saved_networks[network.id] = network.to_dict()
133 else:
134 logger.error("Received error from vtn service (%d)" % r.status_code)
135
Scott Baker90f780d2016-09-07 22:57:28 -0700136
Scott Bakerb3a80de2016-09-06 16:51:27 -0700137 for network_id in glo_saved_networks.keys():
138 if network_id not in valid_ids:
139 logger.info("DELETEing VTN API for network %s" % network_id)
140
Scott Bakerd2439532017-08-11 09:55:50 -0700141 url = "http://%s:%d/onos/cordvtn/serviceNetworks/%s" % (onos_hostname, onos_port, network_id)
Scott Bakerb3a80de2016-09-06 16:51:27 -0700142 logger.info("URL: %s" % url)
143
Scott Bakerd2439532017-08-11 09:55:50 -0700144 r = requests.delete(url, auth=onos_auth )
Scott Bakerb3a80de2016-09-06 16:51:27 -0700145 if (r.status_code in [200,204]):
146 del glo_saved_networks[network_id]
147 else:
148 logger.error("Received error from vtn service (%d)" % r.status_code)
149
Scott Bakerd2439532017-08-11 09:55:50 -0700150 def sync_service_ports(self, vtn_service):
151 (onos_hostname, onos_port, onos_auth) = self.get_vtn_endpoint(vtn_service)
152
Scott Bakerb3a80de2016-09-06 16:51:27 -0700153 valid_ids = []
154 for port in Port.objects.all():
155 port = VTNPort(port)
Scott Bakerf2291012016-09-08 13:19:45 -0700156
157 if not port.id:
158 continue
159
Scott Baker29067002016-09-28 17:14:45 -0700160 if (not port.vlan_id) and (not port.floating_address_pairs):
161 logger.info("Skipping port %s because it has no relevant state" % port.id)
162 continue
163
Scott Bakerb3a80de2016-09-06 16:51:27 -0700164 valid_ids.append(port.id)
Scott Bakerf2291012016-09-08 13:19:45 -0700165
Scott Bakerb3a80de2016-09-06 16:51:27 -0700166 if (glo_saved_ports.get(port.id, None) != port.to_dict()):
Scott Bakerd2439532017-08-11 09:55:50 -0700167 (exists, url, method, req_func) = self.get_method(onos_auth, "http://%s:%d/onos/cordvtn/servicePorts" % (onos_hostname, onos_port), port.id)
Scott Bakerb3a80de2016-09-06 16:51:27 -0700168
Scott Baker90f780d2016-09-07 22:57:28 -0700169 logger.info("%sing VTN API for port %s" % (method, port.id))
170
Scott Bakerb3a80de2016-09-06 16:51:27 -0700171 logger.info("URL: %s" % url)
172
Scott Baker90f780d2016-09-07 22:57:28 -0700173 data = {"ServicePort": {"id": port.id,
Scott Bakerb3a80de2016-09-06 16:51:27 -0700174 "vlan_id": port.vlan_id,
Scott Baker90f780d2016-09-07 22:57:28 -0700175 "floating_address_pairs": port.floating_address_pairs} }
Scott Bakerb3a80de2016-09-06 16:51:27 -0700176 logger.info("DATA: %s" % str(data))
177
Scott Bakerd2439532017-08-11 09:55:50 -0700178 r=req_func(url, json=data, auth=onos_auth )
Scott Bakerf2291012016-09-08 13:19:45 -0700179 if (r.status_code in [200,201]):
Scott Bakerb3a80de2016-09-06 16:51:27 -0700180 glo_saved_ports[port.id] = port.to_dict()
181 else:
182 logger.error("Received error from vtn service (%d)" % r.status_code)
183
184 for port_id in glo_saved_ports.keys():
185 if port_id not in valid_ids:
186 logger.info("DELETEing VTN API for port %s" % port_id)
187
Scott Bakerd2439532017-08-11 09:55:50 -0700188 url = "http://%s:%d/onos/cordvtn/servicePorts/%s" % (onos_hostname, onos_port, port_id)
Scott Bakerb3a80de2016-09-06 16:51:27 -0700189 logger.info("URL: %s" % url)
190
Scott Bakerd2439532017-08-11 09:55:50 -0700191 r = requests.delete(url, auth=onos_auth )
Scott Bakerb3a80de2016-09-06 16:51:27 -0700192 if (r.status_code in [200,204]):
193 del glo_saved_ports[port_id]
194 else:
195 logger.error("Received error from vtn service (%d)" % r.status_code)
196
197 def call(self, **args):
Jonathan Hart19dcbae2017-07-12 09:52:59 -0700198 global glo_saved_networks
199 global glo_saved_ports
200
Scott Baker08a4df32017-03-15 14:13:59 -0700201 vtn_service = VTNService.objects.all()
Scott Bakerb3a80de2016-09-06 16:51:27 -0700202 if not vtn_service:
203 raise Exception("No VTN Service")
204
205 vtn_service = vtn_service[0]
206
Scott Bakerd2439532017-08-11 09:55:50 -0700207 # TODO: We should check get_vtn_onos_app() and make sure that it has been synced, and that any necessary
208 # attributes (netcfg, etc) is filled out.
209
Jonathan Hart19dcbae2017-07-12 09:52:59 -0700210 if (vtn_service.resync):
211 # If the VTN app requested a full resync, clear our saved network
212 # so we will resync everything, then reset the 'resync' flag
213 glo_saved_networks = {}
214 glo_saved_ports = {}
215
216 vtn_service.resync = False
217 vtn_service.save()
218
Scott Baker855a9df2016-09-09 09:23:50 -0700219 if vtn_service.vtnAPIVersion>=2:
Scott Bakerb3a80de2016-09-06 16:51:27 -0700220 # version 2 means use new API
221 logger.info("Using New API")
Scott Bakerd2439532017-08-11 09:55:50 -0700222 self.sync_service_networks(vtn_service)
223 self.sync_service_ports(vtn_service)
Scott Bakerb3a80de2016-09-06 16:51:27 -0700224 else:
Scott Bakercdbb71e2016-10-26 15:50:03 -0700225 raise Exception("VTN API Version 1 is no longer supported by VTN Synchronizer")
Scott Bakerb3a80de2016-09-06 16:51:27 -0700226
227