Matteo Scandolo | 0e7912c | 2017-08-08 13:05:24 -0700 | [diff] [blame] | 1 | |
| 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 Baker | 08a4df3 | 2017-03-15 14:13:59 -0700 | [diff] [blame] | 17 | # This library can be used in two different contexts: |
| 18 | # 1) From the VTN synchronizer |
| 19 | # 2) From the handcrafted VTN API endpoint |
| 20 | # |
| 21 | # If (1) then the modelaccessor module can provide us with models from the API |
| 22 | # or django as appropriate. If (2) then we must use django, until we can |
| 23 | # reconcile what to do about handcrafted API endpoints |
| 24 | |
| 25 | import __main__ as main_program |
| 26 | |
| 27 | if "synchronizer" in main_program.__file__: |
| 28 | from synchronizers.new_base.modelaccessor import * |
| 29 | in_synchronizer = True |
| 30 | else: |
| 31 | from core.models import * |
| 32 | in_synchronizer = False |
Scott Baker | 2342903 | 2016-09-06 12:02:39 -0700 | [diff] [blame] | 33 | |
| 34 | VTN_SERVCOMP_KINDS=["PRIVATE","VSG"] |
| 35 | |
| 36 | class VTNNetwork(object): |
| 37 | def __init__(self, xos_network=None): |
| 38 | self.xos_network = xos_network |
| 39 | |
| 40 | def get_controller_network(self): |
| 41 | for cn in self.xos_network.controllernetworks.all(): |
| 42 | # TODO: find the right one |
| 43 | return cn |
| 44 | return None |
| 45 | |
| 46 | def get_cn_field(self, fieldname): |
| 47 | cn=self.get_controller_network() |
| 48 | if not cn: |
| 49 | return None |
| 50 | return getattr(cn, fieldname) |
| 51 | |
| 52 | @property |
| 53 | def id(self): |
| 54 | return self.get_cn_field("net_id") |
| 55 | |
| 56 | @property |
| 57 | def name(self): |
| 58 | return self.xos_network.name |
| 59 | |
| 60 | @property |
| 61 | def subnet(self): |
| 62 | return self.get_cn_field("subnet") |
| 63 | |
| 64 | @property |
| 65 | def gateway(self): |
| 66 | return self.get_cn_field("gateway") |
| 67 | |
| 68 | @property |
| 69 | def segmentation_id(self): |
| 70 | return self.get_cn_field("segmentation_id") |
| 71 | |
| 72 | @property |
| 73 | def type(self): |
| 74 | return self.xos_network.template.vtn_kind |
| 75 | |
| 76 | @property |
| 77 | def providerNetworks(self): |
| 78 | slice = self.xos_network.owner |
| 79 | service = slice.service |
| 80 | if not service: |
| 81 | return [] |
| 82 | |
| 83 | nets=[] |
Scott Baker | d949b62 | 2017-07-18 12:10:35 -0700 | [diff] [blame] | 84 | for dep in service.subscribed_dependencies.all(): |
| 85 | if dep.provider_service: |
| 86 | bidirectional = dep.connect_method!="private-unidirectional" |
| 87 | for net in dep.provider_service.get_composable_networks(): |
Srikanth Vavilapalli | 9c1c66f | 2016-12-03 23:52:16 +0000 | [diff] [blame] | 88 | if not net.controllernetworks.exists(): |
| 89 | continue |
Scott Baker | 2342903 | 2016-09-06 12:02:39 -0700 | [diff] [blame] | 90 | |
Srikanth Vavilapalli | 9c1c66f | 2016-12-03 23:52:16 +0000 | [diff] [blame] | 91 | cn = net.controllernetworks.all()[0] |
Scott Baker | 43da8a1 | 2017-01-18 08:28:49 -0800 | [diff] [blame] | 92 | |
| 93 | if not cn.net_id: |
| 94 | continue |
| 95 | |
Srikanth Vavilapalli | 9c1c66f | 2016-12-03 23:52:16 +0000 | [diff] [blame] | 96 | nets.append({"id": cn.net_id, |
| 97 | "name": net.name, |
| 98 | "bidirectional": bidirectional}) |
Scott Baker | 2342903 | 2016-09-06 12:02:39 -0700 | [diff] [blame] | 99 | return nets |
| 100 | |
| 101 | @property |
| 102 | def subscriberNetworks(self): |
| 103 | slice = self.xos_network.owner |
| 104 | service = slice.service |
| 105 | if not service: |
| 106 | return [] |
| 107 | |
| 108 | nets=[] |
Scott Baker | d949b62 | 2017-07-18 12:10:35 -0700 | [diff] [blame] | 109 | for dep in service.provided_dependencies.all(): |
| 110 | if dep.subscriber_service: |
| 111 | bidirectional = dep.connect_method!="private-unidirectional" |
| 112 | for net in dep.subscriber_service.get_composable_networks(): |
Srikanth Vavilapalli | 9c1c66f | 2016-12-03 23:52:16 +0000 | [diff] [blame] | 113 | if not net.controllernetworks.exists(): |
| 114 | continue |
Scott Baker | 2342903 | 2016-09-06 12:02:39 -0700 | [diff] [blame] | 115 | |
Srikanth Vavilapalli | 9c1c66f | 2016-12-03 23:52:16 +0000 | [diff] [blame] | 116 | cn = net.controllernetworks.all()[0] |
Scott Baker | 43da8a1 | 2017-01-18 08:28:49 -0800 | [diff] [blame] | 117 | |
| 118 | if not cn.net_id: |
| 119 | continue |
| 120 | |
Srikanth Vavilapalli | 9c1c66f | 2016-12-03 23:52:16 +0000 | [diff] [blame] | 121 | nets.append({"id": cn.net_id, |
| 122 | "name": net.name, |
| 123 | "bidirectional": bidirectional}) |
Scott Baker | 2342903 | 2016-09-06 12:02:39 -0700 | [diff] [blame] | 124 | return nets |
| 125 | |
| 126 | @property |
| 127 | def ownerSliceName(self): |
| 128 | if self.xos_network.owner: |
| 129 | return self.xos_network.owner.name |
| 130 | return None |
| 131 | |
| 132 | @property |
| 133 | def ownerServiceName(self): |
| 134 | if self.xos_network.owner and self.xos_network.owner.service: |
| 135 | return self.xos_network.owner.service.name |
| 136 | return None |
| 137 | |
Scott Baker | b3a80de | 2016-09-06 16:51:27 -0700 | [diff] [blame] | 138 | def to_dict(self): |
| 139 | return {"id": self.id, |
| 140 | "name": self.name, |
| 141 | "subnet": self.subnet, |
| 142 | "gateway": self.gateway, |
| 143 | "segmentation_id": self.segmentation_id, |
| 144 | "type": self.type, |
| 145 | "providerNetworks": self.providerNetworks, |
| 146 | "subscriberNetworks": self.subscriberNetworks, |
| 147 | "ownerSliceName": self.ownerSliceName, |
| 148 | "ownerServiceName": self.ownerServiceName} |
| 149 | |
| 150 | def __eq__(self, other): |
| 151 | return self.to_dict() == other.to_dict() |
| 152 | |
Scott Baker | 2342903 | 2016-09-06 12:02:39 -0700 | [diff] [blame] | 153 | class VTNPort(object): |
Scott Baker | b8bd7fc | 2017-01-24 17:09:13 -0800 | [diff] [blame] | 154 | def __init__(self, xos_port=None): |
| 155 | self.xos_port = xos_port |
| 156 | |
| 157 | def get_controller_network(self): |
| 158 | for cn in self.xos_port.network.controllernetworks.all(): |
| 159 | # TODO: find the right one |
| 160 | return cn |
| 161 | return None |
| 162 | |
| 163 | def get_vsg_tenants(self): |
Scott Baker | 3af3448 | 2017-02-21 08:48:23 -0800 | [diff] [blame] | 164 | # If the VSG service isn't onboarded, then return an empty list. |
Scott Baker | 08a4df3 | 2017-03-15 14:13:59 -0700 | [diff] [blame] | 165 | if (in_synchronizer): |
| 166 | if not model_accessor.has_model_class("VSGTenant"): |
| 167 | print "VSGTenant model does not exist. Returning no tenants" |
| 168 | return [] |
| 169 | VSGTenant = model_accessor.get_model_class("VSGTenant") # suppress undefined local variable error |
| 170 | else: |
| 171 | try: |
| 172 | from services.vsg.models import VSGTenant |
| 173 | except ImportError: |
| 174 | # TODO: Set up logging for this library... |
| 175 | print "Failed to import VSG, returning no tenants" |
| 176 | return [] |
| 177 | |
| 178 | vsg_tenants=[] |
| 179 | for tenant in VSGTenant.objects.all(): |
| 180 | if tenant.instance.id == self.xos_port.instance.id: |
| 181 | vsg_tenants.append(tenant) |
| 182 | return vsg_tenants |
Scott Baker | b8bd7fc | 2017-01-24 17:09:13 -0800 | [diff] [blame] | 183 | |
| 184 | @property |
| 185 | def vlan_id(self): |
| 186 | if not self.xos_port.instance: |
| 187 | return None |
Scott Baker | 08a4df3 | 2017-03-15 14:13:59 -0700 | [diff] [blame] | 188 | |
Scott Baker | b8bd7fc | 2017-01-24 17:09:13 -0800 | [diff] [blame] | 189 | # Only some kinds of networks can have s-tags associated with them. |
| 190 | # Currently, only VSG access networks qualify. |
| 191 | if not self.xos_port.network.template.vtn_kind in ["VSG",]: |
| 192 | return None |
Scott Baker | 08a4df3 | 2017-03-15 14:13:59 -0700 | [diff] [blame] | 193 | |
| 194 | if (in_synchronizer): |
| 195 | tags = Tag.objects.filter(content_type=model_accessor.get_content_type_id(self.xos_port.instance), |
| 196 | object_id=self.xos_port.instance.id, |
| 197 | name="s_tag") |
| 198 | else: |
| 199 | tags = Tag.select_by_content_object(self.xos_port.instance).filter(name="s_tag") |
| 200 | |
Scott Baker | b8bd7fc | 2017-01-24 17:09:13 -0800 | [diff] [blame] | 201 | if not tags: |
| 202 | return None |
Scott Baker | 08a4df3 | 2017-03-15 14:13:59 -0700 | [diff] [blame] | 203 | |
Scott Baker | b8bd7fc | 2017-01-24 17:09:13 -0800 | [diff] [blame] | 204 | return tags[0].value |
| 205 | |
| 206 | @property |
| 207 | def floating_address_pairs(self): |
| 208 | # Floating_address_pairs is the set of WAN addresses that should be |
| 209 | # applied to this port. |
| 210 | |
| 211 | address_pairs = [] |
| 212 | |
| 213 | # only look apply the VSG addresses if the Network is of the VSG vtn_kind |
| 214 | if self.xos_port.network.template.vtn_kind in ["VSG", ]: |
| 215 | for vsg in self.get_vsg_tenants(): |
| 216 | if vsg.wan_container_ip and vsg.wan_container_mac: |
| 217 | address_pairs.append({"ip_address": vsg.wan_container_ip, |
| 218 | "mac_address": vsg.wan_container_mac}) |
| 219 | |
| 220 | if vsg.wan_vm_ip and vsg.wan_vm_mac: |
| 221 | address_pairs.append({"ip_address": vsg.wan_vm_ip, |
| 222 | "mac_address": vsg.wan_vm_mac}) |
| 223 | |
| 224 | return address_pairs |
| 225 | |
| 226 | @property |
| 227 | def id(self): |
| 228 | return self.xos_port.port_id |
| 229 | |
| 230 | @property |
| 231 | def name(self): |
| 232 | return "port-%s" % self.xos_port.id |
| 233 | |
| 234 | @property |
| 235 | def network_id(self): |
| 236 | cn = self.get_controller_network() |
| 237 | if not cn: |
| 238 | return None |
| 239 | return cn.net_id |
| 240 | |
| 241 | @property |
| 242 | def network_name(self): |
| 243 | return self.xos_port.network.name |
| 244 | |
| 245 | @property |
| 246 | def mac_address(self): |
| 247 | return self.xos_port.mac |
| 248 | |
| 249 | @property |
| 250 | def ip_address(self): |
Scott Baker | 2342903 | 2016-09-06 12:02:39 -0700 | [diff] [blame] | 251 | return self.xos_port.ip |
| 252 | |
Scott Baker | b3a80de | 2016-09-06 16:51:27 -0700 | [diff] [blame] | 253 | def to_dict(self): |
| 254 | return {"id": self.id, |
| 255 | "name": self.name, |
| 256 | "network_id": self.network_id, |
| 257 | "mac_address": self.mac_address, |
| 258 | "ip_address": self.ip_address, |
| 259 | "floating_address_pairs": self.floating_address_pairs, |
| 260 | "vlan_id": self.vlan_id} |
| 261 | |
| 262 | def __eq__(self, other): |
| 263 | return self.to_dict() == other.to_dict() |
| 264 | |