Andy Bavier | 7b321c5 | 2017-08-30 15:33:59 -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 | |
| 17 | from synchronizers.new_base.modelaccessor import * |
| 18 | in_synchronizer = True |
| 19 | |
| 20 | class VTNNetwork(object): |
| 21 | def __init__(self, xos_network=None): |
| 22 | self.xos_network = xos_network |
| 23 | |
| 24 | def get_controller_network(self): |
| 25 | for cn in self.xos_network.controllernetworks.all(): |
| 26 | # TODO: find the right one |
| 27 | return cn |
| 28 | return None |
| 29 | |
| 30 | def get_cn_field(self, fieldname): |
| 31 | cn=self.get_controller_network() |
| 32 | if not cn: |
| 33 | return None |
| 34 | return getattr(cn, fieldname) |
| 35 | |
| 36 | @property |
| 37 | def id(self): |
| 38 | return self.get_cn_field("net_id") |
| 39 | |
| 40 | @property |
| 41 | def name(self): |
| 42 | return self.xos_network.name |
| 43 | |
| 44 | @property |
| 45 | def subnet(self): |
| 46 | return self.get_cn_field("subnet") |
| 47 | |
| 48 | @property |
| 49 | def gateway(self): |
| 50 | return self.get_cn_field("gateway") |
| 51 | |
| 52 | @property |
| 53 | def segmentation_id(self): |
| 54 | return self.get_cn_field("segmentation_id") |
| 55 | |
| 56 | @property |
| 57 | def type(self): |
| 58 | return self.xos_network.template.vtn_kind |
| 59 | |
| 60 | @property |
| 61 | def providerNetworks(self): |
| 62 | slice = self.xos_network.owner |
| 63 | service = slice.service |
| 64 | if not service: |
| 65 | return [] |
| 66 | |
| 67 | nets=[] |
| 68 | for dep in service.subscribed_dependencies.all(): |
| 69 | if dep.provider_service: |
| 70 | bidirectional = dep.connect_method!="private-unidirectional" |
| 71 | for net in dep.provider_service.get_composable_networks(): |
| 72 | if not net.controllernetworks.exists(): |
| 73 | continue |
| 74 | |
| 75 | cn = net.controllernetworks.all()[0] |
| 76 | |
| 77 | if not cn.net_id: |
| 78 | continue |
| 79 | |
| 80 | nets.append({"id": cn.net_id, |
| 81 | "name": net.name, |
| 82 | "bidirectional": bidirectional}) |
| 83 | return nets |
| 84 | |
| 85 | @property |
| 86 | def subscriberNetworks(self): |
| 87 | slice = self.xos_network.owner |
| 88 | service = slice.service |
| 89 | if not service: |
| 90 | return [] |
| 91 | |
| 92 | nets=[] |
| 93 | for dep in service.provided_dependencies.all(): |
| 94 | if dep.subscriber_service: |
| 95 | bidirectional = dep.connect_method!="private-unidirectional" |
| 96 | for net in dep.subscriber_service.get_composable_networks(): |
| 97 | if not net.controllernetworks.exists(): |
| 98 | continue |
| 99 | |
| 100 | cn = net.controllernetworks.all()[0] |
| 101 | |
| 102 | if not cn.net_id: |
| 103 | continue |
| 104 | |
| 105 | nets.append({"id": cn.net_id, |
| 106 | "name": net.name, |
| 107 | "bidirectional": bidirectional}) |
| 108 | return nets |
| 109 | |
| 110 | @property |
| 111 | def ownerSliceName(self): |
| 112 | if self.xos_network.owner: |
| 113 | return self.xos_network.owner.name |
| 114 | return None |
| 115 | |
| 116 | @property |
| 117 | def ownerServiceName(self): |
| 118 | if self.xos_network.owner and self.xos_network.owner.service: |
| 119 | return self.xos_network.owner.service.name |
| 120 | return None |
| 121 | |
| 122 | def to_dict(self): |
| 123 | return {"id": self.id, |
| 124 | "name": self.name, |
| 125 | "subnet": self.subnet, |
| 126 | "gateway": self.gateway, |
| 127 | "segmentation_id": self.segmentation_id, |
| 128 | "type": self.type, |
| 129 | "providerNetworks": self.providerNetworks, |
| 130 | "subscriberNetworks": self.subscriberNetworks, |
| 131 | "ownerSliceName": self.ownerSliceName, |
| 132 | "ownerServiceName": self.ownerServiceName} |
| 133 | |
| 134 | def __eq__(self, other): |
| 135 | return self.to_dict() == other.to_dict() |
| 136 | |
| 137 | class VTNPort(object): |
| 138 | def __init__(self, xos_port=None): |
| 139 | self.xos_port = xos_port |
| 140 | |
| 141 | def get_controller_network(self): |
| 142 | for cn in self.xos_port.network.controllernetworks.all(): |
| 143 | # TODO: find the right one |
| 144 | return cn |
| 145 | return None |
| 146 | |
| 147 | def is_access_network(self): |
| 148 | """ Determines whether this port is attached to an access network. Currently we do this by examining the |
| 149 | network template's vtn_kind field. See if there is a better way... |
| 150 | """ |
| 151 | return self.xos_port.network.template.vtn_kind in ["VSG", ] |
| 152 | |
| 153 | def get_vm_addresses(self): |
| 154 | if not self.is_access_network(): |
| 155 | # If not an access network, do not apply any addresses |
| 156 | return [] |
| 157 | |
| 158 | if not self.xos_port.instance: |
| 159 | return [] |
| 160 | |
| 161 | # See if the Instance has any public address (aka "VrouterTenant) service instances associated with it. |
| 162 | # If so, then add each of those to the set of address pairs. |
| 163 | |
| 164 | # TODO: Perhaps this should be implemented as a link instead of a tag... |
| 165 | |
| 166 | tags = Tag.objects.filter(name="vm_public_service_instance", object_id=self.xos_port.instance.id, |
| 167 | content_type=self.xos_port.instance.self_content_type_id) |
| 168 | |
| 169 | if not tags: |
| 170 | # DEPRECATED |
| 171 | # Historically, VSG instances are tagged with "vm_vrouter_tenant" instead of "vm_public_service_instance" |
| 172 | tags = Tag.objects.filter(name="vm_vrouter_tenant", object_id=self.xos_port.instance.id, |
| 173 | content_type=self.xos_port.instance.self_content_type_id) |
| 174 | |
| 175 | address_pairs = [] |
| 176 | for tag in tags: |
| 177 | si = ServiceInstance.objects.get(id = int(tag.value)) |
| 178 | |
| 179 | # cast from Tenant to descendant class (VRouterTenant, etc) |
| 180 | si = si.leaf_model |
| 181 | |
| 182 | if (not hasattr(si, "public_ip")) or (not hasattr(si, "public_mac")): |
| 183 | raise Exception("Object %s does not have public_ip and/or public_mac fields" % si) |
| 184 | address_pairs.append({"ip_address": si.public_ip, |
| 185 | "mac_address": si.public_mac}) |
| 186 | |
| 187 | return address_pairs |
| 188 | |
| 189 | def get_container_addresses(self): |
| 190 | if not self.is_access_network(): |
| 191 | # If not an access network, do not apply any addresses |
| 192 | return [] |
| 193 | |
| 194 | if not self.xos_port.instance: |
| 195 | return [] |
| 196 | |
| 197 | addrs = [] |
| 198 | for si in ServiceInstance.objects.all(): |
| 199 | # cast from tenant to its descendant class (VSGTenant, etc) |
| 200 | si = si.leaf_model |
| 201 | |
| 202 | if not hasattr(si, "instance_id"): |
| 203 | # ignore ServiceInstance that don't have instances |
| 204 | continue |
| 205 | |
| 206 | if si.instance_id != self.xos_port.instance.id: |
| 207 | # ignore ServiceInstances that don't relate to our instance |
| 208 | continue |
| 209 | |
| 210 | # Check to see if there is a link public address (aka VRouterTenant) |
| 211 | links = si.subscribed_links.all() |
| 212 | for link in links: |
| 213 | # cast from ServiceInstance to descendant class (VRouterTenant, etc) |
| 214 | pubaddr_si = link.provider_service_instance.leaf_model |
| 215 | if hasattr(pubaddr_si, "public_ip") and hasattr(pubaddr_si, "public_mac"): |
| 216 | addrs.append({"ip_address": pubaddr_si.public_ip, |
| 217 | "mac_address": pubaddr_si.public_mac}) |
| 218 | return addrs |
| 219 | |
| 220 | @property |
| 221 | def vlan_id(self): |
| 222 | """ Return the vlan_id associated with this instance. This assumes the instance was tagged with either a |
| 223 | vlan_id or s_tag tag. |
| 224 | """ |
| 225 | |
| 226 | if not self.is_access_network(): |
| 227 | # If not an access network, do not apply any tags |
| 228 | return [] |
| 229 | |
| 230 | if not self.xos_port.instance: |
| 231 | return None |
| 232 | |
| 233 | tags = Tag.objects.filter(content_type=model_accessor.get_content_type_id(self.xos_port.instance), |
| 234 | object_id=self.xos_port.instance.id, |
| 235 | name="vlan_id") |
| 236 | |
| 237 | if not tags: |
| 238 | # DEPRECATED |
| 239 | # Historically, VSG instances are tagged with "s_tag" instead of "vlan_id" |
| 240 | tags = Tag.objects.filter(content_type=model_accessor.get_content_type_id(self.xos_port.instance), |
| 241 | object_id=self.xos_port.instance.id, |
| 242 | name="s_tag") |
| 243 | |
| 244 | if not tags: |
| 245 | return None |
| 246 | |
| 247 | return tags[0].value |
| 248 | |
| 249 | @property |
| 250 | def floating_address_pairs(self): |
| 251 | # Floating_address_pairs is the set of WAN addresses that should be |
| 252 | # applied to this port. |
| 253 | |
| 254 | # We only want to apply these addresses to an "access" network. |
| 255 | |
| 256 | |
| 257 | address_pairs = self.get_vm_addresses() + self.get_container_addresses() |
| 258 | |
| 259 | return address_pairs |
| 260 | |
| 261 | @property |
| 262 | def id(self): |
| 263 | return self.xos_port.port_id |
| 264 | |
| 265 | @property |
| 266 | def name(self): |
| 267 | return "port-%s" % self.xos_port.id |
| 268 | |
| 269 | @property |
| 270 | def network_id(self): |
| 271 | cn = self.get_controller_network() |
| 272 | if not cn: |
| 273 | return None |
| 274 | return cn.net_id |
| 275 | |
| 276 | @property |
| 277 | def network_name(self): |
| 278 | return self.xos_port.network.name |
| 279 | |
| 280 | @property |
| 281 | def mac_address(self): |
| 282 | return self.xos_port.mac |
| 283 | |
| 284 | @property |
| 285 | def ip_address(self): |
| 286 | return self.xos_port.ip |
| 287 | |
| 288 | def to_dict(self): |
| 289 | return {"id": self.id, |
| 290 | "name": self.name, |
| 291 | "network_id": self.network_id, |
| 292 | "mac_address": self.mac_address, |
| 293 | "ip_address": self.ip_address, |
| 294 | "floating_address_pairs": self.floating_address_pairs, |
| 295 | "vlan_id": self.vlan_id} |
| 296 | |
| 297 | def __eq__(self, other): |
| 298 | return self.to_dict() == other.to_dict() |
| 299 | |