blob: 37b29a5be23cfefb804a3f4e51529e89e734a24f [file] [log] [blame]
Scott Bakere9ff7ce2015-04-14 17:19:16 -07001from django.db import models
Scott Baker81de6402015-07-06 16:50:30 -07002from core.models import Service, PlCoreBase, Slice, Sliver, Tenant, Node, Image, User, Flavor, Subscriber
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
18from core.models import *
19from hpc.models import *
20from cord.models import *
21django.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 Baker126ad472015-07-07 17:59:44 -0700257 default_attributes = {"vlan_id": 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 Baker679f7022015-04-20 11:50:09 -0700266 def vlan_id(self):
267 return self.get_attribute("vlan_id", self.default_attributes["vlan_id"])
268
269 @vlan_id.setter
270 def vlan_id(self, value):
271 self.set_attribute("vlan_id", value)
272
273 @property
Scott Bakerd4b48c02015-04-15 20:59:15 -0700274 def vcpe(self):
Scott Bakerd9133342015-07-06 14:38:02 -0700275 vcpe = self.get_newest_subscribed_tenant(VCPETenant)
276 if not vcpe:
277 return None
278
279 # always return the same object when possible
280 if (self.cached_vcpe) and (self.cached_vcpe.id == vcpe.id):
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700281 return self.cached_vcpe
Scott Bakerd9133342015-07-06 14:38:02 -0700282
Scott Bakerc633dc92015-05-05 17:49:46 -0700283 vcpe.caller = self.creator
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700284 self.cached_vcpe = vcpe
285 return vcpe
Scott Bakerd4b48c02015-04-15 20:59:15 -0700286
287 @vcpe.setter
288 def vcpe(self, value):
Scott Bakere4364d12015-07-06 17:21:21 -0700289 raise XOSConfigurationError("vOLT.vCPE cannot be set this way -- create a new vCPE object and set its subscriber_tenant instead")
290
291 @property
292 def subscriber(self):
293 if not self.subscriber_root:
294 return None
295 subs = CordSubscriberRoot.objects.filter(id=self.subscriber_root.id)
296 if not subs:
297 return None
298 return subs[0]
Scott Bakerd4b48c02015-04-15 20:59:15 -0700299
Scott Bakerc633dc92015-05-05 17:49:46 -0700300 @property
301 def creator(self):
302 if getattr(self, "cached_creator", None):
303 return self.cached_creator
304 creator_id=self.get_attribute("creator_id")
305 if not creator_id:
306 return None
307 users=User.objects.filter(id=creator_id)
308 if not users:
309 return None
310 user=users[0]
311 self.cached_creator = users[0]
312 return user
313
314 @creator.setter
315 def creator(self, value):
316 if value:
317 value = value.id
318 if (value != self.get_attribute("creator_id", None)):
319 self.cached_creator=None
320 self.set_attribute("creator_id", value)
321
Scott Bakerd4b48c02015-04-15 20:59:15 -0700322 def manage_vcpe(self):
323 # Each VOLT object owns exactly one VCPE object
324
325 if self.deleted:
326 return
327
328 if self.vcpe is None:
329 vcpeServices = VCPEService.get_service_objects().all()
330 if not vcpeServices:
Scott Baker7f8ef8f2015-04-20 14:24:29 -0700331 raise XOSConfigurationError("No VCPE Services available")
Scott Bakerd4b48c02015-04-15 20:59:15 -0700332
333 vcpe = VCPETenant(provider_service = vcpeServices[0],
334 subscriber_tenant = self)
Scott Bakerc633dc92015-05-05 17:49:46 -0700335 vcpe.caller = self.creator
Scott Bakerd4b48c02015-04-15 20:59:15 -0700336 vcpe.save()
337
Scott Baker050f8b32015-07-07 12:15:03 -0700338 def manage_subscriber(self):
339 if (self.subscriber_root is None):
340 # The vOLT is not connected to a Subscriber, so either find an
341 # existing subscriber with the same SSID, or autogenerate a new
342 # subscriber.
343 #
344 # TODO: This probably goes away when we rethink the ONOS-to-XOS
345 # vOLT API.
346
347 subs = CordSubscriberRoot.get_tenant_objects().filter(service_specific_id = self.service_specific_id)
348 if subs:
349 sub = subs[0]
350 else:
351 sub = CordSubscriberRoot(service_specific_id = self.service_specific_id,
352 name = "autogenerated-for-vOLT-%s" % self.id)
353 sub.save()
354 self.subscriber_root = sub
355 self.save()
356
Scott Bakerd4b48c02015-04-15 20:59:15 -0700357 def cleanup_vcpe(self):
358 if self.vcpe:
Scott Bakerd9133342015-07-06 14:38:02 -0700359 # print "XXX cleanup vcpe", self.vcpe
Scott Bakerd4b48c02015-04-15 20:59:15 -0700360 self.vcpe.delete()
Scott Bakerd4b48c02015-04-15 20:59:15 -0700361
Scott Baker868dabf2015-06-24 12:54:24 -0700362 def cleanup_orphans(self):
Scott Bakerd9133342015-07-06 14:38:02 -0700363 # ensure vOLT only has one vCPE
364 cur_vcpe = self.vcpe
365 for vcpe in list(self.get_subscribed_tenants(VCPETenant)):
366 if (not cur_vcpe) or (vcpe.id != cur_vcpe.id):
367 # print "XXX clean up orphaned vcpe", vcpe
368 vcpe.delete()
Scott Baker868dabf2015-06-24 12:54:24 -0700369
Scott Bakerd4b48c02015-04-15 20:59:15 -0700370 def save(self, *args, **kwargs):
Scott Baker7f8ef8f2015-04-20 14:24:29 -0700371 self.validate_unique_service_specific_id()
372
Scott Baker050f8b32015-07-07 12:15:03 -0700373 if (self.subscriber_root is not None):
374 subs = self.subscriber_root.get_subscribed_tenants(VOLTTenant)
375 if (subs) and (self not in subs):
376 raise XOSDuplicateKey("Subscriber should only be linked to one vOLT")
377
Scott Bakerc633dc92015-05-05 17:49:46 -0700378 if not self.creator:
379 if not getattr(self, "caller", None):
380 # caller must be set when creating a vCPE since it creates a slice
381 raise XOSProgrammingError("VOLTTenant's self.caller was not set")
382 self.creator = self.caller
383 if not self.creator:
384 raise XOSProgrammingError("VOLTTenant's self.creator was not set")
385
Scott Bakerd4b48c02015-04-15 20:59:15 -0700386 super(VOLTTenant, self).save(*args, **kwargs)
Scott Baker192da222015-07-08 19:01:56 -0700387 model_policy_volt(self.pk)
388 #self.manage_vcpe()
389 #self.manage_subscriber()
390 #self.cleanup_orphans()
Scott Bakerd4b48c02015-04-15 20:59:15 -0700391
392 def delete(self, *args, **kwargs):
393 self.cleanup_vcpe()
394 super(VOLTTenant, self).delete(*args, **kwargs)
395
Scott Baker192da222015-07-08 19:01:56 -0700396def model_policy_volt(pk):
397 # TODO: this should be made in to a real model_policy
398 with transaction.atomic():
399 volt = VOLTTenant.objects.select_for_update().filter(pk=pk)
400 if not volt:
401 return
402 volt = volt[0]
403 volt.manage_vcpe()
404 volt.manage_subscriber()
405 volt.cleanup_orphans()
406
Scott Bakerd4b48c02015-04-15 20:59:15 -0700407# -------------------------------------------
408# VCPE
409# -------------------------------------------
410
411class VCPEService(Service):
Scott Bakerd9133342015-07-06 14:38:02 -0700412 KIND = VCPE_KIND
Scott Bakerd4b48c02015-04-15 20:59:15 -0700413
Scott Baker2b56cf42015-07-15 18:08:06 -0700414 simple_attributes = ( ("bbs_api_hostname", None),
415 ("bbs_api_port", None),
Scott Baker80157da2015-07-15 17:42:43 -0700416 ("bbs_server", None),
Scott Bakerd4829ea2015-07-15 18:04:22 -0700417 ("backend_network_label", "hpc_client"), )
Scott Baker62312972015-07-13 14:30:25 -0700418
419 def __init__(self, *args, **kwargs):
420 super(VCPEService, self).__init__(*args, **kwargs)
421
Scott Bakerd4b48c02015-04-15 20:59:15 -0700422 class Meta:
423 app_label = "cord"
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700424 verbose_name = "vCPE Service"
Scott Bakerd4b48c02015-04-15 20:59:15 -0700425 proxy = True
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700426
Scott Baker4e6d60d2015-05-20 20:45:11 -0700427 def allocate_bbs_account(self):
428 vcpes = VCPETenant.get_tenant_objects().all()
429 bbs_accounts = [vcpe.bbs_account for vcpe in vcpes]
430
431 # There's a bit of a race here; some other user could be trying to
432 # allocate a bbs_account at the same time we are.
433
Scott Baker2f0b3462015-06-09 12:03:56 -0700434 for i in range(2,21):
Scott Baker4e6d60d2015-05-20 20:45:11 -0700435 account_name = "bbs%02d@onlab.us" % i
436 if (account_name not in bbs_accounts):
437 return account_name
438
439 raise XOSConfigurationError("We've run out of available broadbandshield accounts. Delete some vcpe and try again.")
440
Scott Baker80157da2015-07-15 17:42:43 -0700441 @property
442 def bbs_slice(self):
443 bbs_slice_id=self.get_attribute("bbs_slice_id")
444 if not bbs_slice_id:
445 return None
446 bbs_slices=Slice.objects.filter(id=bbs_slice_id)
447 if not bbs_slices:
448 return None
449 return bbs_slices[0]
450
451 @bbs_slice.setter
452 def bbs_slice(self, value):
453 if value:
454 value = value.id
455 self.set_attribute("bbs_slice_id", value)
456
Scott Baker62312972015-07-13 14:30:25 -0700457VCPEService.setup_simple_attributes()
458
459
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700460class VCPETenant(Tenant):
461 class Meta:
462 proxy = True
463
Scott Bakerd9133342015-07-06 14:38:02 -0700464 KIND = VCPE_KIND
Scott Bakerd4b48c02015-04-15 20:59:15 -0700465
Scott Baker92a81d42015-09-09 10:57:16 -0700466 sync_attributes = ("nat_ip", "nat_mac",
467 "lan_ip", "lan_mac",
468 "wan_ip", "wan_mac",
469 "private_ip", "private_mac",
470 "hpc_client_ip", "hpc_client_mac")
Scott Bakerc633dc92015-05-05 17:49:46 -0700471
Scott Baker126ad472015-07-07 17:59:44 -0700472 default_attributes = {"sliver_id": None,
Scott Baker4e6d60d2015-05-20 20:45:11 -0700473 "users": [],
Scott Baker4aa660e2015-06-09 12:22:29 -0700474 "bbs_account": None,
475 "last_ansible_hash": None}
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700476
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700477 def __init__(self, *args, **kwargs):
478 super(VCPETenant, self).__init__(*args, **kwargs)
479 self.cached_vbng=None
480 self.cached_sliver=None
Scott Baker868dabf2015-06-24 12:54:24 -0700481 self.orig_sliver_id = self.get_initial_attribute("sliver_id")
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700482
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700483 @property
484 def image(self):
Scott Baker192da222015-07-08 19:01:56 -0700485 LOOK_FOR_IMAGES=["ubuntu-vcpe4", # ONOS demo machine -- preferred vcpe image
Scott Baker866575c2015-06-02 16:03:30 -0700486 "Ubuntu 14.04 LTS", # portal
Scott Baker8c0ae622015-04-20 20:12:59 -0700487 "Ubuntu-14.04-LTS", # ONOS demo machine
488 ]
489 for image_name in LOOK_FOR_IMAGES:
490 images = Image.objects.filter(name = image_name)
491 if images:
492 return images[0]
493
494 raise XOSProgrammingError("No VPCE image (looked for %s)" % str(LOOK_FOR_IMAGES))
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700495
496 @property
497 def sliver(self):
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700498 if getattr(self, "cached_sliver", None):
499 return self.cached_sliver
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700500 sliver_id=self.get_attribute("sliver_id")
501 if not sliver_id:
502 return None
503 slivers=Sliver.objects.filter(id=sliver_id)
504 if not slivers:
505 return None
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700506 sliver=slivers[0]
Scott Bakerc633dc92015-05-05 17:49:46 -0700507 sliver.caller = self.creator
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700508 self.cached_sliver = sliver
509 return sliver
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700510
511 @sliver.setter
512 def sliver(self, value):
513 if value:
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700514 value = value.id
515 if (value != self.get_attribute("sliver_id", None)):
516 self.cached_sliver=None
517 self.set_attribute("sliver_id", value)
518
519 @property
Scott Bakerc633dc92015-05-05 17:49:46 -0700520 def creator(self):
521 if getattr(self, "cached_creator", None):
522 return self.cached_creator
523 creator_id=self.get_attribute("creator_id")
524 if not creator_id:
525 return None
526 users=User.objects.filter(id=creator_id)
527 if not users:
528 return None
529 user=users[0]
530 self.cached_creator = users[0]
531 return user
532
533 @creator.setter
534 def creator(self, value):
535 if value:
536 value = value.id
537 if (value != self.get_attribute("creator_id", None)):
538 self.cached_creator=None
539 self.set_attribute("creator_id", value)
540
541 @property
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700542 def vbng(self):
Scott Bakerd9133342015-07-06 14:38:02 -0700543 vbng = self.get_newest_subscribed_tenant(VBNGTenant)
544 if not vbng:
545 return None
546
547 # always return the same object when possible
548 if (self.cached_vbng) and (self.cached_vbng.id == vbng.id):
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700549 return self.cached_vbng
Scott Bakerd9133342015-07-06 14:38:02 -0700550
Scott Bakerc633dc92015-05-05 17:49:46 -0700551 vbng.caller = self.creator
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700552 self.cached_vbng = vbng
553 return vbng
554
555 @vbng.setter
556 def vbng(self, value):
Scott Bakerd9133342015-07-06 14:38:02 -0700557 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 -0700558
Scott Bakere4364d12015-07-06 17:21:21 -0700559 @property
560 def volt(self):
561 if not self.subscriber_tenant:
562 return None
563 volts = VOLTTenant.objects.filter(id=self.subscriber_tenant.id)
564 if not volts:
565 return None
566 return volts[0]
567
Scott Baker81de6402015-07-06 16:50:30 -0700568 @property
569 def bbs_account(self):
570 return self.get_attribute("bbs_account", self.default_attributes["bbs_account"])
571
572 @bbs_account.setter
573 def bbs_account(self, value):
574 return self.set_attribute("bbs_account", value)
575
576 @property
577 def last_ansible_hash(self):
578 return self.get_attribute("last_ansible_hash", self.default_attributes["last_ansible_hash"])
579
580 @last_ansible_hash.setter
581 def last_ansible_hash(self, value):
582 return self.set_attribute("last_ansible_hash", value)
583
584 @property
585 def ssh_command(self):
586 if self.sliver:
587 return self.sliver.get_ssh_command()
588 else:
589 return "no-sliver"
590
591 @ssh_command.setter
592 def ssh_command(self, value):
593 pass
594
Scott Baker5571c692015-05-20 08:19:25 -0700595 @property
596 def addresses(self):
597 if not self.sliver:
598 return {}
599
600 addresses = {}
Scott Baker11fe2e92015-08-28 11:55:19 -0700601 for ns in self.sliver.ports.all():
Scott Baker5571c692015-05-20 08:19:25 -0700602 if "lan" in ns.network.name.lower():
Scott Baker92a81d42015-09-09 10:57:16 -0700603 addresses["lan"] = (ns.ip, ns.mac)
Scott Baker5571c692015-05-20 08:19:25 -0700604 elif "wan" in ns.network.name.lower():
Scott Baker92a81d42015-09-09 10:57:16 -0700605 addresses["wan"] = (ns.ip, ns.mac)
Scott Baker5571c692015-05-20 08:19:25 -0700606 elif "private" in ns.network.name.lower():
Scott Baker92a81d42015-09-09 10:57:16 -0700607 addresses["private"] = (ns.ip, ns.mac)
Scott Baker5571c692015-05-20 08:19:25 -0700608 elif "nat" in ns.network.name.lower():
Scott Baker92a81d42015-09-09 10:57:16 -0700609 addresses["nat"] = (ns.ip, ns.mac)
Scott Baker281b1af2015-06-04 10:26:44 -0700610 elif "hpc_client" in ns.network.name.lower():
Scott Baker92a81d42015-09-09 10:57:16 -0700611 addresses["hpc_client"] = (ns.ip, ns.mac)
Scott Baker5571c692015-05-20 08:19:25 -0700612 return addresses
613
Scott Baker432d1402015-05-20 08:25:29 -0700614 @property
615 def nat_ip(self):
Scott Baker92a81d42015-09-09 10:57:16 -0700616 return self.addresses.get("nat", (None,None) )[0]
617
618 @property
619 def nat_mac(self):
620 return self.addresses.get("nat", (None,None) )[1]
Scott Baker432d1402015-05-20 08:25:29 -0700621
622 @property
623 def lan_ip(self):
Scott Baker92a81d42015-09-09 10:57:16 -0700624 return self.addresses.get("lan", (None, None) )[0]
625
626 @property
627 def lan_mac(self):
628 return self.addresses.get("lan", (None, None) )[1]
Scott Baker432d1402015-05-20 08:25:29 -0700629
630 @property
631 def wan_ip(self):
Scott Baker92a81d42015-09-09 10:57:16 -0700632 return self.addresses.get("wan", (None, None) )[0]
Scott Baker432d1402015-05-20 08:25:29 -0700633
634 @property
Scott Baker4f972592015-06-05 12:08:34 -0700635 def wan_mac(self):
Andy Bavier4c7e76d2015-09-09 18:06:30 -0400636 return self.addresses.get("wan", (None, None) )[1]
Scott Baker4f972592015-06-05 12:08:34 -0700637
638 @property
Scott Baker432d1402015-05-20 08:25:29 -0700639 def private_ip(self):
Scott Baker92a81d42015-09-09 10:57:16 -0700640 return self.addresses.get("private", (None, None) )[0]
641
642 @property
643 def private_mac(self):
644 return self.addresses.get("private", (None, None) )[1]
Scott Baker432d1402015-05-20 08:25:29 -0700645
Scott Baker281b1af2015-06-04 10:26:44 -0700646 @property
647 def hpc_client_ip(self):
Scott Baker92a81d42015-09-09 10:57:16 -0700648 return self.addresses.get("hpc_client", (None, None) )[0]
649
650 @property
651 def hpc_client_mac(self):
652 return self.addresses.get("hpc_client", (None, None) )[1]
Scott Baker281b1af2015-06-04 10:26:44 -0700653
Scott Bakerd517a102015-06-09 12:30:30 -0700654 @property
655 def is_synced(self):
656 return (self.enacted is not None) and (self.enacted >= self.updated)
657
658 @is_synced.setter
659 def is_synced(self, value):
660 pass
661
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700662 def pick_node(self):
663 nodes = list(Node.objects.all())
664 # TODO: logic to filter nodes by which nodes are up, and which
665 # nodes the slice can instantiate on.
666 nodes = sorted(nodes, key=lambda node: node.slivers.all().count())
667 return nodes[0]
668
669 def manage_sliver(self):
Scott Bakerd4b48c02015-04-15 20:59:15 -0700670 # Each VCPE object owns exactly one sliver.
671
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700672 if self.deleted:
673 return
674
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700675 if (self.sliver is not None) and (self.sliver.image != self.image):
676 self.sliver.delete()
677 self.sliver = None
Scott Bakerc633dc92015-05-05 17:49:46 -0700678
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700679 if self.sliver is None:
680 if not self.provider_service.slices.count():
Scott Bakerf6790db2015-05-06 15:46:34 -0700681 raise XOSConfigurationError("The VCPE service has no slices")
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700682
Scott Bakere1f72d12015-05-14 21:48:53 -0700683 flavors = Flavor.objects.filter(name="m1.small")
684 if not flavors:
685 raise XOSConfigurationError("No m1.small flavor")
686
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700687 node =self.pick_node()
688 sliver = Sliver(slice = self.provider_service.slices.all()[0],
689 node = node,
690 image = self.image,
Scott Bakerc633dc92015-05-05 17:49:46 -0700691 creator = self.creator,
Scott Bakere1f72d12015-05-14 21:48:53 -0700692 deployment = node.site_deployment.deployment,
693 flavor = flavors[0])
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700694 sliver.save()
695
Scott Bakerd4b48c02015-04-15 20:59:15 -0700696 try:
697 self.sliver = sliver
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700698 super(VCPETenant, self).save()
Scott Bakerd4b48c02015-04-15 20:59:15 -0700699 except:
700 sliver.delete()
701 raise
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700702
703 def cleanup_sliver(self):
704 if self.sliver:
Scott Bakerd9133342015-07-06 14:38:02 -0700705 # print "XXX cleanup sliver", self.sliver
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700706 self.sliver.delete()
707 self.sliver = None
708
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700709 def manage_vbng(self):
710 # Each vCPE object owns exactly one vBNG object
711
712 if self.deleted:
713 return
714
715 if self.vbng is None:
716 vbngServices = VBNGService.get_service_objects().all()
717 if not vbngServices:
Scott Baker7f8ef8f2015-04-20 14:24:29 -0700718 raise XOSConfigurationError("No VBNG Services available")
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700719
720 vbng = VBNGTenant(provider_service = vbngServices[0],
721 subscriber_tenant = self)
Scott Bakerc633dc92015-05-05 17:49:46 -0700722 vbng.caller = self.creator
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700723 vbng.save()
724
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700725 def cleanup_vbng(self):
726 if self.vbng:
Scott Bakerd9133342015-07-06 14:38:02 -0700727 # print "XXX cleanup vnbg", self.vbng
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700728 self.vbng.delete()
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700729
Scott Baker868dabf2015-06-24 12:54:24 -0700730 def cleanup_orphans(self):
Scott Bakerd9133342015-07-06 14:38:02 -0700731 # ensure vCPE only has one vBNG
732 cur_vbng = self.vbng
733 for vbng in list(self.get_subscribed_tenants(VBNGTenant)):
734 if (not cur_vbng) or (vbng.id != cur_vbng.id):
735 # print "XXX clean up orphaned vbng", vbng
736 vbng.delete()
Scott Baker868dabf2015-06-24 12:54:24 -0700737
738 if self.orig_sliver_id and (self.orig_sliver_id != self.get_attribute("sliver_id")):
739 slivers=Sliver.objects.filter(id=self.orig_sliver_id)
740 if slivers:
741 # print "XXX clean up orphaned sliver", slivers[0]
742 slivers[0].delete()
743
Scott Baker4e6d60d2015-05-20 20:45:11 -0700744 def manage_bbs_account(self):
745 if self.deleted:
746 return
747
Scott Baker126ad472015-07-07 17:59:44 -0700748 if self.volt and self.volt.subscriber and self.volt.subscriber.url_filter_enable:
Scott Baker642126f2015-05-20 20:57:28 -0700749 if not self.bbs_account:
750 # make sure we use the proxied VCPEService object, not the generic Service object
751 vcpe_service = VCPEService.objects.get(id=self.provider_service.id)
Scott Baker050f8b32015-07-07 12:15:03 -0700752 self.bbs_account = vcpe_service.allocate_bbs_account()
Scott Baker642126f2015-05-20 20:57:28 -0700753 super(VCPETenant, self).save()
754 else:
755 if self.bbs_account:
756 self.bbs_account = None
757 super(VCPETenant, self).save()
Scott Baker4e6d60d2015-05-20 20:45:11 -0700758
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700759 def save(self, *args, **kwargs):
Scott Bakerc633dc92015-05-05 17:49:46 -0700760 if not self.creator:
761 if not getattr(self, "caller", None):
762 # caller must be set when creating a vCPE since it creates a slice
Scott Bakerf6790db2015-05-06 15:46:34 -0700763 raise XOSProgrammingError("VCPETenant's self.caller was not set")
Scott Bakerc633dc92015-05-05 17:49:46 -0700764 self.creator = self.caller
765 if not self.creator:
Scott Bakerf6790db2015-05-06 15:46:34 -0700766 raise XOSProgrammingError("VCPETenant's self.creator was not set")
Scott Bakerc633dc92015-05-05 17:49:46 -0700767
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700768 super(VCPETenant, self).save(*args, **kwargs)
Scott Baker192da222015-07-08 19:01:56 -0700769 model_policy_vcpe(self.pk)
770 #self.manage_sliver()
771 #self.manage_vbng()
772 #self.manage_bbs_account()
773 #self.cleanup_orphans()
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700774
775 def delete(self, *args, **kwargs):
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700776 self.cleanup_vbng()
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700777 self.cleanup_sliver()
778 super(VCPETenant, self).delete(*args, **kwargs)
779
Scott Baker192da222015-07-08 19:01:56 -0700780def model_policy_vcpe(pk):
781 # TODO: this should be made in to a real model_policy
782 with transaction.atomic():
783 vcpe = VCPETenant.objects.select_for_update().filter(pk=pk)
784 if not vcpe:
785 return
786 vcpe = vcpe[0]
787 vcpe.manage_sliver()
788 vcpe.manage_vbng()
789 vcpe.manage_bbs_account()
790 vcpe.cleanup_orphans()
791
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700792#----------------------------------------------------------------------------
793# vBNG
794#----------------------------------------------------------------------------
795
796class VBNGService(Service):
Scott Bakerd9133342015-07-06 14:38:02 -0700797 KIND = VBNG_KIND
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700798
Scott Baker21d18932015-07-21 18:24:21 -0700799 simple_attributes = ( ("vbng_url", "http://10.0.3.136:8181/onos/virtualbng/"), )
800
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700801 class Meta:
802 app_label = "cord"
803 verbose_name = "vBNG Service"
804 proxy = True
805
Scott Baker21d18932015-07-21 18:24:21 -0700806VBNGService.setup_simple_attributes()
807
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700808class VBNGTenant(Tenant):
809 class Meta:
810 proxy = True
811
Scott Bakerd9133342015-07-06 14:38:02 -0700812 KIND = VBNG_KIND
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700813
Scott Baker61c8e8d2015-06-02 14:34:04 -0700814 default_attributes = {"routeable_subnet": "",
Scott Bakercf155f42015-06-08 19:09:53 -0700815 "mapped_ip": "",
816 "mapped_mac": "",
817 "mapped_hostname": ""}
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700818
819 @property
820 def routeable_subnet(self):
821 return self.get_attribute("routeable_subnet", self.default_attributes["routeable_subnet"])
822
823 @routeable_subnet.setter
824 def routeable_subnet(self, value):
825 self.set_attribute("routeable_subnet", value)
Scott Baker61c8e8d2015-06-02 14:34:04 -0700826
827 @property
828 def mapped_ip(self):
829 return self.get_attribute("mapped_ip", self.default_attributes["mapped_ip"])
830
831 @mapped_ip.setter
832 def mapped_ip(self, value):
833 self.set_attribute("mapped_ip", value)
Scott Bakercf155f42015-06-08 19:09:53 -0700834
835 @property
836 def mapped_mac(self):
837 return self.get_attribute("mapped_mac", self.default_attributes["mapped_mac"])
838
839 @mapped_mac.setter
840 def mapped_mac(self, value):
841 self.set_attribute("mapped_mac", value)
842
843 @property
844 def mapped_hostname(self):
845 return self.get_attribute("mapped_hostname", self.default_attributes["mapped_hostname"])
846
847 @mapped_hostname.setter
848 def mapped_hostname(self, value):
849 self.set_attribute("mapped_hostname", value)