blob: 4b794b486ef6ab37f67bc1cd4df6dccacb4196ed [file] [log] [blame]
Scott Bakere9ff7ce2015-04-14 17:19:16 -07001from django.db import models
Scott Baker839daa82015-11-16 22:53:49 -08002from core.models import Service, PlCoreBase, Slice, Instance, Tenant, TenantWithContainer, Node, Image, User, Flavor, Subscriber, NetworkParameter, NetworkParameterType, Port
Scott Bakere9ff7ce2015-04-14 17:19:16 -07003from core.models.plcorebase import StrippedCharField
4import os
Scott Baker192da222015-07-08 19:01:56 -07005from django.db import models, transaction
Scott Bakere9ff7ce2015-04-14 17:19:16 -07006from django.forms.models import model_to_dict
7from django.db.models import Q
8from operator import itemgetter, attrgetter, methodcaller
Scott Bakerfa5cdd62015-04-20 09:16:17 -07009import traceback
Scott Baker7f8ef8f2015-04-20 14:24:29 -070010from xos.exceptions import *
Scott Bakere9ff7ce2015-04-14 17:19:16 -070011
12"""
13import os
14import sys
15sys.path.append("/opt/xos")
16os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xos.settings")
17import django
Scott Bakerc749d622015-12-29 23:47:06 -080018from core.models import *
19from services.hpc.models import *
Scott Baker98f51552015-12-31 10:18:28 -080020from services.cord.models import *
Scott Bakere9ff7ce2015-04-14 17:19:16 -070021django.setup()
Scott Bakere9ff7ce2015-04-14 17:19:16 -070022
Scott Baker323eca92015-04-20 09:48:34 -070023t = VOLTTenant()
Scott Bakere9ff7ce2015-04-14 17:19:16 -070024t.caller = User.objects.all()[0]
25t.save()
26
Scott Bakerdfc0bef2015-05-11 08:31:24 -070027for v in VOLTTenant.get_tenant_objects().all():
Scott Bakerd4b48c02015-04-15 20:59:15 -070028 v.caller = User.objects.all()[0]
29 v.delete()
30
Scott Bakerdfc0bef2015-05-11 08:31:24 -070031for v in VCPETenant.get_tenant_objects().all():
Scott Bakere9ff7ce2015-04-14 17:19:16 -070032 v.caller = User.objects.all()[0]
33 v.delete()
Scott Bakerfa5cdd62015-04-20 09:16:17 -070034
Scott Bakerdfc0bef2015-05-11 08:31:24 -070035for v in VOLTTenant.get_tenant_objects().all():
Scott Bakerfa5cdd62015-04-20 09:16:17 -070036 v.caller = User.objects.all()[0]
37 v.delete()
Scott Bakerc633dc92015-05-05 17:49:46 -070038
Scott Bakerdfc0bef2015-05-11 08:31:24 -070039for v in VOLTTenant.get_tenant_objects().all():
Scott Bakerc633dc92015-05-05 17:49:46 -070040 if not v.creator:
41 v.creator= User.objects.all()[0]
42 v.save()
43
Scott Bakerdfc0bef2015-05-11 08:31:24 -070044for v in VCPETenant.get_tenant_objects().all():
Scott Bakerc633dc92015-05-05 17:49:46 -070045 if not v.creator:
46 v.creator= User.objects.all()[0]
47 v.save()
Scott Bakere9ff7ce2015-04-14 17:19:16 -070048"""
49
50class ConfigurationError(Exception):
51 pass
52
Scott Bakerd9133342015-07-06 14:38:02 -070053VOLT_KIND = "vOLT"
54VCPE_KIND = "vCPE"
55VBNG_KIND = "vBNG"
Scott Baker81de6402015-07-06 16:50:30 -070056CORD_SUBSCRIBER_KIND = "CordSubscriberRoot"
57
58# -------------------------------------------
59# CordSubscriberRoot
60# -------------------------------------------
61
62class CordSubscriberRoot(Subscriber):
Scott Bakere4364d12015-07-06 17:21:21 -070063 class Meta:
64 proxy = True
65
Scott Baker81de6402015-07-06 16:50:30 -070066 KIND = CORD_SUBSCRIBER_KIND
67
68 default_attributes = {"firewall_enable": False,
69 "firewall_rules": "accept all anywhere anywhere",
70 "url_filter_enable": False,
71 "url_filter_rules": "allow all",
72 "url_filter_level": "PG",
73 "cdn_enable": False,
Scott Baker126ad472015-07-07 17:59:44 -070074 "users": [],
75 "is_demo_user": False }
Scott Baker81de6402015-07-06 16:50:30 -070076
Scott Baker050f8b32015-07-07 12:15:03 -070077 sync_attributes = ("firewall_enable",
78 "firewall_rules",
79 "url_filter_enable",
80 "url_filter_rules",
81 "cdn_enable",)
82
Scott Baker81de6402015-07-06 16:50:30 -070083 def __init__(self, *args, **kwargs):
84 super(CordSubscriberRoot, self).__init__(*args, **kwargs)
85 self.cached_volt = None
Scott Baker050f8b32015-07-07 12:15:03 -070086 self._initial_url_filter_enable = self.url_filter_enable
Scott Baker81de6402015-07-06 16:50:30 -070087
88 @property
89 def volt(self):
90 volt = self.get_newest_subscribed_tenant(VOLTTenant)
91 if not volt:
92 return None
93
94 # always return the same object when possible
95 if (self.cached_volt) and (self.cached_volt.id == volt.id):
Scott Baker126ad472015-07-07 17:59:44 -070096 return self.cached_volt
Scott Baker81de6402015-07-06 16:50:30 -070097
Scott Bakere4364d12015-07-06 17:21:21 -070098 #volt.caller = self.creator
Scott Baker81de6402015-07-06 16:50:30 -070099 self.cached_volt = volt
100 return volt
101
102 @property
103 def firewall_enable(self):
104 return self.get_attribute("firewall_enable", self.default_attributes["firewall_enable"])
105
106 @firewall_enable.setter
107 def firewall_enable(self, value):
108 self.set_attribute("firewall_enable", value)
109
110 @property
111 def firewall_rules(self):
112 return self.get_attribute("firewall_rules", self.default_attributes["firewall_rules"])
113
114 @firewall_rules.setter
115 def firewall_rules(self, value):
116 self.set_attribute("firewall_rules", value)
117
118 @property
119 def url_filter_enable(self):
120 return self.get_attribute("url_filter_enable", self.default_attributes["url_filter_enable"])
121
122 @url_filter_enable.setter
123 def url_filter_enable(self, value):
124 self.set_attribute("url_filter_enable", value)
125
126 @property
127 def url_filter_level(self):
128 return self.get_attribute("url_filter_level", self.default_attributes["url_filter_level"])
129
130 @url_filter_level.setter
131 def url_filter_level(self, value):
132 self.set_attribute("url_filter_level", value)
133
134 @property
135 def url_filter_rules(self):
136 return self.get_attribute("url_filter_rules", self.default_attributes["url_filter_rules"])
137
138 @url_filter_rules.setter
139 def url_filter_rules(self, value):
140 self.set_attribute("url_filter_rules", value)
141
142 @property
143 def cdn_enable(self):
144 return self.get_attribute("cdn_enable", self.default_attributes["cdn_enable"])
145
146 @cdn_enable.setter
147 def cdn_enable(self, value):
148 self.set_attribute("cdn_enable", value)
149
150 @property
151 def users(self):
152 return self.get_attribute("users", self.default_attributes["users"])
153
154 @users.setter
155 def users(self, value):
156 self.set_attribute("users", value)
157
158 def find_user(self, uid):
159 uid = int(uid)
160 for user in self.users:
161 if user["id"] == uid:
162 return user
163 return None
164
165 def update_user(self, uid, **kwargs):
166 # kwargs may be "level" or "mac"
167 # Setting one of these to None will cause None to be stored in the db
168 uid = int(uid)
169 users = self.users
170 for user in users:
171 if user["id"] == uid:
172 for arg in kwargs.keys():
173 user[arg] = kwargs[arg]
174 self.users = users
175 return user
176 raise ValueError("User %d not found" % uid)
177
178 def create_user(self, **kwargs):
179 if "name" not in kwargs:
180 raise XOSMissingField("The name field is required")
181
182 for user in self.users:
183 if kwargs["name"] == user["name"]:
184 raise XOSDuplicateKey("User %s already exists" % kwargs["name"])
185
186 uids = [x["id"] for x in self.users]
187 if uids:
188 uid = max(uids)+1
189 else:
190 uid = 0
191 newuser = kwargs.copy()
192 newuser["id"] = uid
193
194 users = self.users
195 users.append(newuser)
196 self.users = users
197
198 return newuser
199
200 def delete_user(self, uid):
201 uid = int(uid)
202 users = self.users
203 for user in users:
204 if user["id"]==uid:
205 users.remove(user)
206 self.users = users
207 return
208
209 raise ValueError("Users %d not found" % uid)
210
211 @property
212 def services(self):
213 return {"cdn": self.cdn_enable,
214 "url_filter": self.url_filter_enable,
215 "firewall": self.firewall_enable}
216
217 @services.setter
218 def services(self, value):
219 pass
Scott Bakerd9133342015-07-06 14:38:02 -0700220
Scott Baker050f8b32015-07-07 12:15:03 -0700221 def save(self, *args, **kwargs):
Scott Bakerfe38c2a2015-07-24 18:56:57 -0700222 if (not hasattr(self, 'caller') or not self.caller.is_admin):
223 if (self.has_field_changed("service_specific_id")):
224 raise XOSPermissionDenied("You do not have permission to change service_specific_id")
Scott Baker050f8b32015-07-07 12:15:03 -0700225 super(CordSubscriberRoot, self).save(*args, **kwargs)
226 if (self.volt) and (self.volt.vcpe): # and (self._initial_url_filter_enabled != self.url_filter_enable):
227 # 1) trigger manage_bbs_account to run
228 # 2) trigger vcpe observer to wake up
229 self.volt.vcpe.save()
230
Scott Baker126ad472015-07-07 17:59:44 -0700231 @property
232 def is_demo_user(self):
233 return self.get_attribute("is_demo_user", self.default_attributes["is_demo_user"])
234
235 @is_demo_user.setter
236 def is_demo_user(self, value):
237 self.set_attribute("is_demo_user", value)
238
Scott Bakerd4b48c02015-04-15 20:59:15 -0700239# -------------------------------------------
240# VOLT
241# -------------------------------------------
242
243class VOLTService(Service):
Scott Bakerd9133342015-07-06 14:38:02 -0700244 KIND = VOLT_KIND
Scott Bakerd4b48c02015-04-15 20:59:15 -0700245
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700246 class Meta:
Scott Bakerd4b48c02015-04-15 20:59:15 -0700247 app_label = "cord"
248 verbose_name = "vOLT Service"
249 proxy = True
250
251class VOLTTenant(Tenant):
252 class Meta:
253 proxy = True
254
Scott Bakerd9133342015-07-06 14:38:02 -0700255 KIND = VOLT_KIND
Scott Bakerd4b48c02015-04-15 20:59:15 -0700256
Scott Bakerf1527cd2015-11-09 20:25:21 -0800257 default_attributes = {"vlan_id": None, "s_tag": None, "c_tag": None}
Scott Baker323eca92015-04-20 09:48:34 -0700258 def __init__(self, *args, **kwargs):
259 volt_services = VOLTService.get_service_objects().all()
260 if volt_services:
261 self._meta.get_field("provider_service").default = volt_services[0].id
262 super(VOLTTenant, self).__init__(*args, **kwargs)
Scott Bakerd9133342015-07-06 14:38:02 -0700263 self.cached_vcpe = None
Scott Baker868dabf2015-06-24 12:54:24 -0700264
Scott Bakerd4b48c02015-04-15 20:59:15 -0700265 @property
Scott Bakerf1527cd2015-11-09 20:25:21 -0800266 def s_tag(self):
267 return self.get_attribute("s_tag", self.default_attributes["s_tag"])
268
269 @s_tag.setter
270 def s_tag(self, value):
271 self.set_attribute("s_tag", value)
272
273 @property
274 def c_tag(self):
275 return self.get_attribute("c_tag", self.default_attributes["c_tag"])
276
277 @c_tag.setter
278 def c_tag(self, value):
279 self.set_attribute("c_tag", value)
280
281 # for now, vlan_id is a synonym for c_tag
282
283 @property
Scott Baker679f7022015-04-20 11:50:09 -0700284 def vlan_id(self):
Scott Bakerf1527cd2015-11-09 20:25:21 -0800285 return self.c_tag
Scott Baker679f7022015-04-20 11:50:09 -0700286
287 @vlan_id.setter
288 def vlan_id(self, value):
Scott Bakerf1527cd2015-11-09 20:25:21 -0800289 self.c_tag = value
Scott Baker679f7022015-04-20 11:50:09 -0700290
291 @property
Scott Bakerd4b48c02015-04-15 20:59:15 -0700292 def vcpe(self):
Scott Bakerd9133342015-07-06 14:38:02 -0700293 vcpe = self.get_newest_subscribed_tenant(VCPETenant)
294 if not vcpe:
295 return None
296
297 # always return the same object when possible
298 if (self.cached_vcpe) and (self.cached_vcpe.id == vcpe.id):
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700299 return self.cached_vcpe
Scott Bakerd9133342015-07-06 14:38:02 -0700300
Scott Bakerc633dc92015-05-05 17:49:46 -0700301 vcpe.caller = self.creator
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700302 self.cached_vcpe = vcpe
303 return vcpe
Scott Bakerd4b48c02015-04-15 20:59:15 -0700304
305 @vcpe.setter
306 def vcpe(self, value):
Scott Bakere4364d12015-07-06 17:21:21 -0700307 raise XOSConfigurationError("vOLT.vCPE cannot be set this way -- create a new vCPE object and set its subscriber_tenant instead")
308
309 @property
310 def subscriber(self):
311 if not self.subscriber_root:
312 return None
313 subs = CordSubscriberRoot.objects.filter(id=self.subscriber_root.id)
314 if not subs:
315 return None
316 return subs[0]
Scott Bakerd4b48c02015-04-15 20:59:15 -0700317
Scott Bakerc633dc92015-05-05 17:49:46 -0700318 @property
319 def creator(self):
320 if getattr(self, "cached_creator", None):
321 return self.cached_creator
322 creator_id=self.get_attribute("creator_id")
323 if not creator_id:
324 return None
325 users=User.objects.filter(id=creator_id)
326 if not users:
327 return None
328 user=users[0]
329 self.cached_creator = users[0]
330 return user
331
332 @creator.setter
333 def creator(self, value):
334 if value:
335 value = value.id
336 if (value != self.get_attribute("creator_id", None)):
337 self.cached_creator=None
338 self.set_attribute("creator_id", value)
339
Scott Bakerd4b48c02015-04-15 20:59:15 -0700340 def manage_vcpe(self):
341 # Each VOLT object owns exactly one VCPE object
342
343 if self.deleted:
344 return
345
346 if self.vcpe is None:
347 vcpeServices = VCPEService.get_service_objects().all()
348 if not vcpeServices:
Scott Baker7f8ef8f2015-04-20 14:24:29 -0700349 raise XOSConfigurationError("No VCPE Services available")
Scott Bakerd4b48c02015-04-15 20:59:15 -0700350
351 vcpe = VCPETenant(provider_service = vcpeServices[0],
352 subscriber_tenant = self)
Scott Bakerc633dc92015-05-05 17:49:46 -0700353 vcpe.caller = self.creator
Scott Bakerd4b48c02015-04-15 20:59:15 -0700354 vcpe.save()
355
Scott Baker050f8b32015-07-07 12:15:03 -0700356 def manage_subscriber(self):
357 if (self.subscriber_root is None):
358 # The vOLT is not connected to a Subscriber, so either find an
359 # existing subscriber with the same SSID, or autogenerate a new
360 # subscriber.
361 #
362 # TODO: This probably goes away when we rethink the ONOS-to-XOS
363 # vOLT API.
364
365 subs = CordSubscriberRoot.get_tenant_objects().filter(service_specific_id = self.service_specific_id)
366 if subs:
367 sub = subs[0]
368 else:
369 sub = CordSubscriberRoot(service_specific_id = self.service_specific_id,
370 name = "autogenerated-for-vOLT-%s" % self.id)
371 sub.save()
372 self.subscriber_root = sub
373 self.save()
374
Scott Bakerd4b48c02015-04-15 20:59:15 -0700375 def cleanup_vcpe(self):
376 if self.vcpe:
Scott Bakerd9133342015-07-06 14:38:02 -0700377 # print "XXX cleanup vcpe", self.vcpe
Scott Bakerd4b48c02015-04-15 20:59:15 -0700378 self.vcpe.delete()
Scott Bakerd4b48c02015-04-15 20:59:15 -0700379
Scott Baker868dabf2015-06-24 12:54:24 -0700380 def cleanup_orphans(self):
Scott Bakerd9133342015-07-06 14:38:02 -0700381 # ensure vOLT only has one vCPE
382 cur_vcpe = self.vcpe
383 for vcpe in list(self.get_subscribed_tenants(VCPETenant)):
384 if (not cur_vcpe) or (vcpe.id != cur_vcpe.id):
385 # print "XXX clean up orphaned vcpe", vcpe
386 vcpe.delete()
Scott Baker868dabf2015-06-24 12:54:24 -0700387
Scott Bakerd4b48c02015-04-15 20:59:15 -0700388 def save(self, *args, **kwargs):
Scott Baker7f8ef8f2015-04-20 14:24:29 -0700389 self.validate_unique_service_specific_id()
390
Scott Baker050f8b32015-07-07 12:15:03 -0700391 if (self.subscriber_root is not None):
392 subs = self.subscriber_root.get_subscribed_tenants(VOLTTenant)
393 if (subs) and (self not in subs):
394 raise XOSDuplicateKey("Subscriber should only be linked to one vOLT")
395
Scott Bakerc633dc92015-05-05 17:49:46 -0700396 if not self.creator:
397 if not getattr(self, "caller", None):
398 # caller must be set when creating a vCPE since it creates a slice
399 raise XOSProgrammingError("VOLTTenant's self.caller was not set")
400 self.creator = self.caller
401 if not self.creator:
402 raise XOSProgrammingError("VOLTTenant's self.creator was not set")
403
Scott Bakerd4b48c02015-04-15 20:59:15 -0700404 super(VOLTTenant, self).save(*args, **kwargs)
Scott Baker192da222015-07-08 19:01:56 -0700405 model_policy_volt(self.pk)
406 #self.manage_vcpe()
407 #self.manage_subscriber()
408 #self.cleanup_orphans()
Scott Bakerd4b48c02015-04-15 20:59:15 -0700409
410 def delete(self, *args, **kwargs):
411 self.cleanup_vcpe()
412 super(VOLTTenant, self).delete(*args, **kwargs)
413
Scott Baker192da222015-07-08 19:01:56 -0700414def model_policy_volt(pk):
415 # TODO: this should be made in to a real model_policy
416 with transaction.atomic():
417 volt = VOLTTenant.objects.select_for_update().filter(pk=pk)
418 if not volt:
419 return
420 volt = volt[0]
421 volt.manage_vcpe()
422 volt.manage_subscriber()
423 volt.cleanup_orphans()
424
Scott Bakerd4b48c02015-04-15 20:59:15 -0700425# -------------------------------------------
426# VCPE
427# -------------------------------------------
428
429class VCPEService(Service):
Scott Bakerd9133342015-07-06 14:38:02 -0700430 KIND = VCPE_KIND
Scott Bakerd4b48c02015-04-15 20:59:15 -0700431
Scott Baker2b56cf42015-07-15 18:08:06 -0700432 simple_attributes = ( ("bbs_api_hostname", None),
433 ("bbs_api_port", None),
Scott Baker80157da2015-07-15 17:42:43 -0700434 ("bbs_server", None),
Scott Bakerd4829ea2015-07-15 18:04:22 -0700435 ("backend_network_label", "hpc_client"), )
Scott Baker62312972015-07-13 14:30:25 -0700436
437 def __init__(self, *args, **kwargs):
438 super(VCPEService, self).__init__(*args, **kwargs)
439
Scott Bakerd4b48c02015-04-15 20:59:15 -0700440 class Meta:
441 app_label = "cord"
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700442 verbose_name = "vCPE Service"
Scott Bakerd4b48c02015-04-15 20:59:15 -0700443 proxy = True
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700444
Scott Baker4e6d60d2015-05-20 20:45:11 -0700445 def allocate_bbs_account(self):
446 vcpes = VCPETenant.get_tenant_objects().all()
447 bbs_accounts = [vcpe.bbs_account for vcpe in vcpes]
448
449 # There's a bit of a race here; some other user could be trying to
450 # allocate a bbs_account at the same time we are.
451
Scott Baker2f0b3462015-06-09 12:03:56 -0700452 for i in range(2,21):
Scott Baker4e6d60d2015-05-20 20:45:11 -0700453 account_name = "bbs%02d@onlab.us" % i
454 if (account_name not in bbs_accounts):
455 return account_name
456
457 raise XOSConfigurationError("We've run out of available broadbandshield accounts. Delete some vcpe and try again.")
458
Scott Baker80157da2015-07-15 17:42:43 -0700459 @property
460 def bbs_slice(self):
461 bbs_slice_id=self.get_attribute("bbs_slice_id")
462 if not bbs_slice_id:
463 return None
464 bbs_slices=Slice.objects.filter(id=bbs_slice_id)
465 if not bbs_slices:
466 return None
467 return bbs_slices[0]
468
469 @bbs_slice.setter
470 def bbs_slice(self, value):
471 if value:
472 value = value.id
473 self.set_attribute("bbs_slice_id", value)
474
Scott Baker62312972015-07-13 14:30:25 -0700475VCPEService.setup_simple_attributes()
476
477
Scott Bakerc1584b82015-09-09 16:36:06 -0700478class VCPETenant(TenantWithContainer):
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700479 class Meta:
480 proxy = True
481
Scott Bakerd9133342015-07-06 14:38:02 -0700482 KIND = VCPE_KIND
Scott Bakerd4b48c02015-04-15 20:59:15 -0700483
Scott Baker92a81d42015-09-09 10:57:16 -0700484 sync_attributes = ("nat_ip", "nat_mac",
485 "lan_ip", "lan_mac",
Andy Bavier733733d2015-10-29 14:01:47 -0400486 "wan_ip", "wan_mac", "wan_container_mac",
Scott Baker92a81d42015-09-09 10:57:16 -0700487 "private_ip", "private_mac",
488 "hpc_client_ip", "hpc_client_mac")
Scott Bakerc633dc92015-05-05 17:49:46 -0700489
Tony Mackd8515472015-08-19 11:58:18 -0400490 default_attributes = {"instance_id": None,
Scott Baker4b206972015-11-02 20:55:07 -0800491 "container_id": None,
Scott Baker4e6d60d2015-05-20 20:45:11 -0700492 "users": [],
Scott Baker4aa660e2015-06-09 12:22:29 -0700493 "bbs_account": None,
494 "last_ansible_hash": None}
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700495
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700496 def __init__(self, *args, **kwargs):
497 super(VCPETenant, self).__init__(*args, **kwargs)
498 self.cached_vbng=None
Scott Bakerc633dc92015-05-05 17:49:46 -0700499
500 @property
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700501 def vbng(self):
Scott Bakerd9133342015-07-06 14:38:02 -0700502 vbng = self.get_newest_subscribed_tenant(VBNGTenant)
503 if not vbng:
504 return None
505
506 # always return the same object when possible
507 if (self.cached_vbng) and (self.cached_vbng.id == vbng.id):
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700508 return self.cached_vbng
Scott Bakerd9133342015-07-06 14:38:02 -0700509
Scott Bakerc633dc92015-05-05 17:49:46 -0700510 vbng.caller = self.creator
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700511 self.cached_vbng = vbng
512 return vbng
513
514 @vbng.setter
515 def vbng(self, value):
Scott Bakerd9133342015-07-06 14:38:02 -0700516 raise XOSConfigurationError("vCPE.vBNG cannot be set this way -- create a new vBNG object and set it's subscriber_tenant instead")
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700517
Scott Bakere4364d12015-07-06 17:21:21 -0700518 @property
519 def volt(self):
520 if not self.subscriber_tenant:
521 return None
522 volts = VOLTTenant.objects.filter(id=self.subscriber_tenant.id)
523 if not volts:
524 return None
525 return volts[0]
526
Scott Baker81de6402015-07-06 16:50:30 -0700527 @property
528 def bbs_account(self):
529 return self.get_attribute("bbs_account", self.default_attributes["bbs_account"])
530
531 @bbs_account.setter
532 def bbs_account(self, value):
533 return self.set_attribute("bbs_account", value)
534
535 @property
536 def last_ansible_hash(self):
537 return self.get_attribute("last_ansible_hash", self.default_attributes["last_ansible_hash"])
538
539 @last_ansible_hash.setter
540 def last_ansible_hash(self, value):
541 return self.set_attribute("last_ansible_hash", value)
542
543 @property
544 def ssh_command(self):
Tony Mackd8515472015-08-19 11:58:18 -0400545 if self.instance:
546 return self.instance.get_ssh_command()
Scott Baker81de6402015-07-06 16:50:30 -0700547 else:
Tony Mackd8515472015-08-19 11:58:18 -0400548 return "no-instance"
Scott Baker81de6402015-07-06 16:50:30 -0700549
550 @ssh_command.setter
551 def ssh_command(self, value):
552 pass
553
Scott Baker5571c692015-05-20 08:19:25 -0700554 @property
555 def addresses(self):
Scott Baker4b206972015-11-02 20:55:07 -0800556 if self.instance:
557 ports = self.instance.ports.all()
558 elif self.container:
559 ports = self.container.ports.all()
560 else:
Scott Baker5571c692015-05-20 08:19:25 -0700561 return {}
562
563 addresses = {}
Scott Baker4b206972015-11-02 20:55:07 -0800564 for ns in ports:
Scott Baker5571c692015-05-20 08:19:25 -0700565 if "lan" in ns.network.name.lower():
Scott Baker92a81d42015-09-09 10:57:16 -0700566 addresses["lan"] = (ns.ip, ns.mac)
Scott Baker5571c692015-05-20 08:19:25 -0700567 elif "wan" in ns.network.name.lower():
Scott Baker92a81d42015-09-09 10:57:16 -0700568 addresses["wan"] = (ns.ip, ns.mac)
Scott Baker5571c692015-05-20 08:19:25 -0700569 elif "private" in ns.network.name.lower():
Scott Baker92a81d42015-09-09 10:57:16 -0700570 addresses["private"] = (ns.ip, ns.mac)
Scott Baker5571c692015-05-20 08:19:25 -0700571 elif "nat" in ns.network.name.lower():
Scott Baker92a81d42015-09-09 10:57:16 -0700572 addresses["nat"] = (ns.ip, ns.mac)
Scott Baker281b1af2015-06-04 10:26:44 -0700573 elif "hpc_client" in ns.network.name.lower():
Scott Baker92a81d42015-09-09 10:57:16 -0700574 addresses["hpc_client"] = (ns.ip, ns.mac)
Scott Baker5571c692015-05-20 08:19:25 -0700575 return addresses
576
Scott Baker432d1402015-05-20 08:25:29 -0700577 @property
578 def nat_ip(self):
Scott Baker92a81d42015-09-09 10:57:16 -0700579 return self.addresses.get("nat", (None,None) )[0]
580
581 @property
582 def nat_mac(self):
583 return self.addresses.get("nat", (None,None) )[1]
Scott Baker432d1402015-05-20 08:25:29 -0700584
585 @property
586 def lan_ip(self):
Scott Baker92a81d42015-09-09 10:57:16 -0700587 return self.addresses.get("lan", (None, None) )[0]
588
589 @property
590 def lan_mac(self):
591 return self.addresses.get("lan", (None, None) )[1]
Scott Baker432d1402015-05-20 08:25:29 -0700592
593 @property
594 def wan_ip(self):
Scott Baker92a81d42015-09-09 10:57:16 -0700595 return self.addresses.get("wan", (None, None) )[0]
Scott Baker432d1402015-05-20 08:25:29 -0700596
597 @property
Scott Baker4f972592015-06-05 12:08:34 -0700598 def wan_mac(self):
Andy Bavier4c7e76d2015-09-09 18:06:30 -0400599 return self.addresses.get("wan", (None, None) )[1]
Scott Baker4f972592015-06-05 12:08:34 -0700600
Andy Bavier733733d2015-10-29 14:01:47 -0400601 # Generate the MAC for the container interface connected to WAN
602 @property
603 def wan_container_mac(self):
604 (a, b, c, d) = self.wan_ip.split('.')
605 return "02:42:%02x:%02x:%02x:%02x" % (int(a), int(b), int(c), int(d))
606
Scott Baker4f972592015-06-05 12:08:34 -0700607 @property
Scott Baker432d1402015-05-20 08:25:29 -0700608 def private_ip(self):
Scott Baker92a81d42015-09-09 10:57:16 -0700609 return self.addresses.get("private", (None, None) )[0]
610
611 @property
612 def private_mac(self):
613 return self.addresses.get("private", (None, None) )[1]
Scott Baker432d1402015-05-20 08:25:29 -0700614
Scott Baker281b1af2015-06-04 10:26:44 -0700615 @property
616 def hpc_client_ip(self):
Scott Baker92a81d42015-09-09 10:57:16 -0700617 return self.addresses.get("hpc_client", (None, None) )[0]
618
619 @property
620 def hpc_client_mac(self):
621 return self.addresses.get("hpc_client", (None, None) )[1]
Scott Baker281b1af2015-06-04 10:26:44 -0700622
Scott Bakerd517a102015-06-09 12:30:30 -0700623 @property
624 def is_synced(self):
625 return (self.enacted is not None) and (self.enacted >= self.updated)
626
627 @is_synced.setter
628 def is_synced(self, value):
629 pass
630
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700631 def manage_vbng(self):
632 # Each vCPE object owns exactly one vBNG object
633
634 if self.deleted:
635 return
636
637 if self.vbng is None:
638 vbngServices = VBNGService.get_service_objects().all()
639 if not vbngServices:
Scott Baker7f8ef8f2015-04-20 14:24:29 -0700640 raise XOSConfigurationError("No VBNG Services available")
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700641
642 vbng = VBNGTenant(provider_service = vbngServices[0],
643 subscriber_tenant = self)
Scott Bakerc633dc92015-05-05 17:49:46 -0700644 vbng.caller = self.creator
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700645 vbng.save()
646
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700647 def cleanup_vbng(self):
648 if self.vbng:
Scott Bakerd9133342015-07-06 14:38:02 -0700649 # print "XXX cleanup vnbg", self.vbng
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700650 self.vbng.delete()
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700651
Scott Baker868dabf2015-06-24 12:54:24 -0700652 def cleanup_orphans(self):
Scott Bakerd9133342015-07-06 14:38:02 -0700653 # ensure vCPE only has one vBNG
654 cur_vbng = self.vbng
655 for vbng in list(self.get_subscribed_tenants(VBNGTenant)):
656 if (not cur_vbng) or (vbng.id != cur_vbng.id):
657 # print "XXX clean up orphaned vbng", vbng
658 vbng.delete()
Scott Baker868dabf2015-06-24 12:54:24 -0700659
Tony Mackd8515472015-08-19 11:58:18 -0400660 if self.orig_instance_id and (self.orig_instance_id != self.get_attribute("instance_id")):
661 instances=Instance.objects.filter(id=self.orig_instance_id)
662 if instances:
663 # print "XXX clean up orphaned instance", instances[0]
664 instances[0].delete()
Scott Baker868dabf2015-06-24 12:54:24 -0700665
Scott Baker4e6d60d2015-05-20 20:45:11 -0700666 def manage_bbs_account(self):
667 if self.deleted:
668 return
669
Scott Baker126ad472015-07-07 17:59:44 -0700670 if self.volt and self.volt.subscriber and self.volt.subscriber.url_filter_enable:
Scott Baker642126f2015-05-20 20:57:28 -0700671 if not self.bbs_account:
672 # make sure we use the proxied VCPEService object, not the generic Service object
673 vcpe_service = VCPEService.objects.get(id=self.provider_service.id)
Scott Baker050f8b32015-07-07 12:15:03 -0700674 self.bbs_account = vcpe_service.allocate_bbs_account()
Scott Baker642126f2015-05-20 20:57:28 -0700675 super(VCPETenant, self).save()
676 else:
677 if self.bbs_account:
678 self.bbs_account = None
679 super(VCPETenant, self).save()
Scott Baker4e6d60d2015-05-20 20:45:11 -0700680
Scott Baker839daa82015-11-16 22:53:49 -0800681 def find_or_make_port(self, instance, network, **kwargs):
682 port = Port.objects.filter(instance=instance, network=network)
683 if port:
684 port = port[0]
685 else:
686 port = Port(instance=instance, network=network, **kwargs)
687 port.save()
688 return port
689
690 def save_instance(self, instance):
691 with transaction.atomic():
Andy Bavier1aa49af2015-12-16 14:10:01 -0500692 instance.volumes = "/etc/dnsmasq.d,/etc/ufw"
Scott Baker839daa82015-11-16 22:53:49 -0800693 super(VCPETenant, self).save_instance(instance)
694
695 if instance.isolation in ["container", "container_vm"]:
696 lan_networks = [x for x in instance.slice.networks.all() if "lan" in x.name]
697 if not lan_networks:
698 raise XOSProgrammingError("No lan_network")
699 port = self.find_or_make_port(instance, lan_networks[0], ip="192.168.0.1", port_id="unmanaged")
700 port.set_parameter("c_tag", self.volt.c_tag)
701 port.set_parameter("s_tag", self.volt.s_tag)
702 port.set_parameter("device", "eth1")
Scott Bakere2920b22015-11-19 16:51:27 -0800703 port.set_parameter("bridge", "br-lan")
Scott Baker839daa82015-11-16 22:53:49 -0800704
705 wan_networks = [x for x in instance.slice.networks.all() if "wan" in x.name]
706 if not wan_networks:
707 raise XOSProgrammingError("No wan_network")
708 port = self.find_or_make_port(instance, wan_networks[0])
709 port.set_parameter("next_hop", value="10.0.1.253") # FIX ME
710 port.set_parameter("device", "eth0")
711
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700712 def save(self, *args, **kwargs):
Scott Bakerc633dc92015-05-05 17:49:46 -0700713 if not self.creator:
714 if not getattr(self, "caller", None):
715 # caller must be set when creating a vCPE since it creates a slice
Scott Bakerf6790db2015-05-06 15:46:34 -0700716 raise XOSProgrammingError("VCPETenant's self.caller was not set")
Scott Bakerc633dc92015-05-05 17:49:46 -0700717 self.creator = self.caller
718 if not self.creator:
Scott Bakerf6790db2015-05-06 15:46:34 -0700719 raise XOSProgrammingError("VCPETenant's self.creator was not set")
Scott Bakerc633dc92015-05-05 17:49:46 -0700720
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700721 super(VCPETenant, self).save(*args, **kwargs)
Scott Baker192da222015-07-08 19:01:56 -0700722 model_policy_vcpe(self.pk)
Tony Mackd8515472015-08-19 11:58:18 -0400723 #self.manage_instance()
Scott Baker192da222015-07-08 19:01:56 -0700724 #self.manage_vbng()
725 #self.manage_bbs_account()
726 #self.cleanup_orphans()
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700727
728 def delete(self, *args, **kwargs):
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700729 self.cleanup_vbng()
Scott Bakerc1584b82015-09-09 16:36:06 -0700730 self.cleanup_container()
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700731 super(VCPETenant, self).delete(*args, **kwargs)
732
Scott Baker192da222015-07-08 19:01:56 -0700733def model_policy_vcpe(pk):
734 # TODO: this should be made in to a real model_policy
735 with transaction.atomic():
736 vcpe = VCPETenant.objects.select_for_update().filter(pk=pk)
737 if not vcpe:
738 return
739 vcpe = vcpe[0]
Scott Bakerc1584b82015-09-09 16:36:06 -0700740 vcpe.manage_container()
Scott Baker192da222015-07-08 19:01:56 -0700741 vcpe.manage_vbng()
742 vcpe.manage_bbs_account()
743 vcpe.cleanup_orphans()
744
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700745#----------------------------------------------------------------------------
746# vBNG
747#----------------------------------------------------------------------------
748
749class VBNGService(Service):
Scott Bakerd9133342015-07-06 14:38:02 -0700750 KIND = VBNG_KIND
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700751
Scott Baker6667ddc2015-10-20 22:12:51 -0700752 simple_attributes = ( ("vbng_url", ""), ) # "http://10.0.3.136:8181/onos/virtualbng/"
Scott Baker21d18932015-07-21 18:24:21 -0700753
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700754 class Meta:
755 app_label = "cord"
756 verbose_name = "vBNG Service"
757 proxy = True
758
Scott Baker21d18932015-07-21 18:24:21 -0700759VBNGService.setup_simple_attributes()
760
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700761class VBNGTenant(Tenant):
762 class Meta:
763 proxy = True
764
Scott Bakerd9133342015-07-06 14:38:02 -0700765 KIND = VBNG_KIND
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700766
Scott Baker61c8e8d2015-06-02 14:34:04 -0700767 default_attributes = {"routeable_subnet": "",
Scott Bakercf155f42015-06-08 19:09:53 -0700768 "mapped_ip": "",
769 "mapped_mac": "",
770 "mapped_hostname": ""}
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700771
772 @property
773 def routeable_subnet(self):
774 return self.get_attribute("routeable_subnet", self.default_attributes["routeable_subnet"])
775
776 @routeable_subnet.setter
777 def routeable_subnet(self, value):
778 self.set_attribute("routeable_subnet", value)
Scott Baker61c8e8d2015-06-02 14:34:04 -0700779
780 @property
781 def mapped_ip(self):
782 return self.get_attribute("mapped_ip", self.default_attributes["mapped_ip"])
783
784 @mapped_ip.setter
785 def mapped_ip(self, value):
786 self.set_attribute("mapped_ip", value)
Scott Bakercf155f42015-06-08 19:09:53 -0700787
788 @property
789 def mapped_mac(self):
790 return self.get_attribute("mapped_mac", self.default_attributes["mapped_mac"])
791
792 @mapped_mac.setter
793 def mapped_mac(self, value):
794 self.set_attribute("mapped_mac", value)
795
796 @property
797 def mapped_hostname(self):
798 return self.get_attribute("mapped_hostname", self.default_attributes["mapped_hostname"])
799
800 @mapped_hostname.setter
801 def mapped_hostname(self, value):
802 self.set_attribute("mapped_hostname", value)