Scott Baker | 08a4df3 | 2017-03-15 14:13:59 -0700 | [diff] [blame^] | 1 | # This library can be used in two different contexts: |
| 2 | # 1) From the VTN synchronizer |
| 3 | # 2) From the handcrafted VTN API endpoint |
| 4 | # |
| 5 | # If (1) then the modelaccessor module can provide us with models from the API |
| 6 | # or django as appropriate. If (2) then we must use django, until we can |
| 7 | # reconcile what to do about handcrafted API endpoints |
| 8 | |
| 9 | import __main__ as main_program |
| 10 | |
| 11 | if "synchronizer" in main_program.__file__: |
| 12 | from synchronizers.new_base.modelaccessor import * |
| 13 | in_synchronizer = True |
| 14 | else: |
| 15 | from core.models import * |
| 16 | in_synchronizer = False |
Scott Baker | 2342903 | 2016-09-06 12:02:39 -0700 | [diff] [blame] | 17 | |
| 18 | VTN_SERVCOMP_KINDS=["PRIVATE","VSG"] |
| 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 tenant in service.subscribed_tenants.all(): |
| 69 | if tenant.provider_service: |
| 70 | bidirectional = tenant.connect_method!="private-unidirectional" |
Srikanth Vavilapalli | 9c1c66f | 2016-12-03 23:52:16 +0000 | [diff] [blame] | 71 | for net in tenant.provider_service.get_composable_networks(): |
| 72 | if not net.controllernetworks.exists(): |
| 73 | continue |
Scott Baker | 2342903 | 2016-09-06 12:02:39 -0700 | [diff] [blame] | 74 | |
Srikanth Vavilapalli | 9c1c66f | 2016-12-03 23:52:16 +0000 | [diff] [blame] | 75 | cn = net.controllernetworks.all()[0] |
Scott Baker | 43da8a1 | 2017-01-18 08:28:49 -0800 | [diff] [blame] | 76 | |
| 77 | if not cn.net_id: |
| 78 | continue |
| 79 | |
Srikanth Vavilapalli | 9c1c66f | 2016-12-03 23:52:16 +0000 | [diff] [blame] | 80 | nets.append({"id": cn.net_id, |
| 81 | "name": net.name, |
| 82 | "bidirectional": bidirectional}) |
Scott Baker | 2342903 | 2016-09-06 12:02:39 -0700 | [diff] [blame] | 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 tenant in service.provided_tenants.all(): |
| 94 | if tenant.subscriber_service: |
| 95 | bidirectional = tenant.connect_method!="private-unidirectional" |
Srikanth Vavilapalli | 9c1c66f | 2016-12-03 23:52:16 +0000 | [diff] [blame] | 96 | for net in tenant.subscriber_service.get_composable_networks(): |
| 97 | if not net.controllernetworks.exists(): |
| 98 | continue |
Scott Baker | 2342903 | 2016-09-06 12:02:39 -0700 | [diff] [blame] | 99 | |
Srikanth Vavilapalli | 9c1c66f | 2016-12-03 23:52:16 +0000 | [diff] [blame] | 100 | cn = net.controllernetworks.all()[0] |
Scott Baker | 43da8a1 | 2017-01-18 08:28:49 -0800 | [diff] [blame] | 101 | |
| 102 | if not cn.net_id: |
| 103 | continue |
| 104 | |
Srikanth Vavilapalli | 9c1c66f | 2016-12-03 23:52:16 +0000 | [diff] [blame] | 105 | nets.append({"id": cn.net_id, |
| 106 | "name": net.name, |
| 107 | "bidirectional": bidirectional}) |
Scott Baker | 2342903 | 2016-09-06 12:02:39 -0700 | [diff] [blame] | 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 | |
Scott Baker | b3a80de | 2016-09-06 16:51:27 -0700 | [diff] [blame] | 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 | |
Scott Baker | 2342903 | 2016-09-06 12:02:39 -0700 | [diff] [blame] | 137 | class VTNPort(object): |
Scott Baker | b8bd7fc | 2017-01-24 17:09:13 -0800 | [diff] [blame] | 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 get_vsg_tenants(self): |
Scott Baker | 3af3448 | 2017-02-21 08:48:23 -0800 | [diff] [blame] | 148 | # If the VSG service isn't onboarded, then return an empty list. |
Scott Baker | 08a4df3 | 2017-03-15 14:13:59 -0700 | [diff] [blame^] | 149 | if (in_synchronizer): |
| 150 | if not model_accessor.has_model_class("VSGTenant"): |
| 151 | print "VSGTenant model does not exist. Returning no tenants" |
| 152 | return [] |
| 153 | VSGTenant = model_accessor.get_model_class("VSGTenant") # suppress undefined local variable error |
| 154 | else: |
| 155 | try: |
| 156 | from services.vsg.models import VSGTenant |
| 157 | except ImportError: |
| 158 | # TODO: Set up logging for this library... |
| 159 | print "Failed to import VSG, returning no tenants" |
| 160 | return [] |
| 161 | |
| 162 | vsg_tenants=[] |
| 163 | for tenant in VSGTenant.objects.all(): |
| 164 | if tenant.instance.id == self.xos_port.instance.id: |
| 165 | vsg_tenants.append(tenant) |
| 166 | return vsg_tenants |
Scott Baker | b8bd7fc | 2017-01-24 17:09:13 -0800 | [diff] [blame] | 167 | |
| 168 | @property |
| 169 | def vlan_id(self): |
| 170 | if not self.xos_port.instance: |
| 171 | return None |
Scott Baker | 08a4df3 | 2017-03-15 14:13:59 -0700 | [diff] [blame^] | 172 | |
Scott Baker | b8bd7fc | 2017-01-24 17:09:13 -0800 | [diff] [blame] | 173 | # Only some kinds of networks can have s-tags associated with them. |
| 174 | # Currently, only VSG access networks qualify. |
| 175 | if not self.xos_port.network.template.vtn_kind in ["VSG",]: |
| 176 | return None |
Scott Baker | 08a4df3 | 2017-03-15 14:13:59 -0700 | [diff] [blame^] | 177 | |
| 178 | if (in_synchronizer): |
| 179 | tags = Tag.objects.filter(content_type=model_accessor.get_content_type_id(self.xos_port.instance), |
| 180 | object_id=self.xos_port.instance.id, |
| 181 | name="s_tag") |
| 182 | else: |
| 183 | tags = Tag.select_by_content_object(self.xos_port.instance).filter(name="s_tag") |
| 184 | |
Scott Baker | b8bd7fc | 2017-01-24 17:09:13 -0800 | [diff] [blame] | 185 | if not tags: |
| 186 | return None |
Scott Baker | 08a4df3 | 2017-03-15 14:13:59 -0700 | [diff] [blame^] | 187 | |
Scott Baker | b8bd7fc | 2017-01-24 17:09:13 -0800 | [diff] [blame] | 188 | return tags[0].value |
| 189 | |
| 190 | @property |
| 191 | def floating_address_pairs(self): |
| 192 | # Floating_address_pairs is the set of WAN addresses that should be |
| 193 | # applied to this port. |
| 194 | |
| 195 | address_pairs = [] |
| 196 | |
| 197 | # only look apply the VSG addresses if the Network is of the VSG vtn_kind |
| 198 | if self.xos_port.network.template.vtn_kind in ["VSG", ]: |
| 199 | for vsg in self.get_vsg_tenants(): |
| 200 | if vsg.wan_container_ip and vsg.wan_container_mac: |
| 201 | address_pairs.append({"ip_address": vsg.wan_container_ip, |
| 202 | "mac_address": vsg.wan_container_mac}) |
| 203 | |
| 204 | if vsg.wan_vm_ip and vsg.wan_vm_mac: |
| 205 | address_pairs.append({"ip_address": vsg.wan_vm_ip, |
| 206 | "mac_address": vsg.wan_vm_mac}) |
| 207 | |
| 208 | return address_pairs |
| 209 | |
| 210 | @property |
| 211 | def id(self): |
| 212 | return self.xos_port.port_id |
| 213 | |
| 214 | @property |
| 215 | def name(self): |
| 216 | return "port-%s" % self.xos_port.id |
| 217 | |
| 218 | @property |
| 219 | def network_id(self): |
| 220 | cn = self.get_controller_network() |
| 221 | if not cn: |
| 222 | return None |
| 223 | return cn.net_id |
| 224 | |
| 225 | @property |
| 226 | def network_name(self): |
| 227 | return self.xos_port.network.name |
| 228 | |
| 229 | @property |
| 230 | def mac_address(self): |
| 231 | return self.xos_port.mac |
| 232 | |
| 233 | @property |
| 234 | def ip_address(self): |
Scott Baker | 2342903 | 2016-09-06 12:02:39 -0700 | [diff] [blame] | 235 | return self.xos_port.ip |
| 236 | |
Scott Baker | b3a80de | 2016-09-06 16:51:27 -0700 | [diff] [blame] | 237 | def to_dict(self): |
| 238 | return {"id": self.id, |
| 239 | "name": self.name, |
| 240 | "network_id": self.network_id, |
| 241 | "mac_address": self.mac_address, |
| 242 | "ip_address": self.ip_address, |
| 243 | "floating_address_pairs": self.floating_address_pairs, |
| 244 | "vlan_id": self.vlan_id} |
| 245 | |
| 246 | def __eq__(self, other): |
| 247 | return self.to_dict() == other.to_dict() |
| 248 | |