blob: 8befa17bb52725fbf5940a59c1ef57bee9905ed9 [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 Baker126ad472015-07-07 17:59:44 -0700466 sync_attributes = ("nat_ip",
Scott Baker0c8512b2015-05-20 08:41:38 -0700467 "lan_ip",
468 "wan_ip",
Scott Baker281b1af2015-06-04 10:26:44 -0700469 "private_ip",
Scott Baker4f972592015-06-05 12:08:34 -0700470 "hpc_client_ip",
471 "wan_mac")
Scott Bakerc633dc92015-05-05 17:49:46 -0700472
Scott Baker126ad472015-07-07 17:59:44 -0700473 default_attributes = {"sliver_id": None,
Scott Baker4e6d60d2015-05-20 20:45:11 -0700474 "users": [],
Scott Baker4aa660e2015-06-09 12:22:29 -0700475 "bbs_account": None,
476 "last_ansible_hash": None}
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700477
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700478 def __init__(self, *args, **kwargs):
479 super(VCPETenant, self).__init__(*args, **kwargs)
480 self.cached_vbng=None
481 self.cached_sliver=None
Scott Baker868dabf2015-06-24 12:54:24 -0700482 self.orig_sliver_id = self.get_initial_attribute("sliver_id")
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700483
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700484 @property
485 def image(self):
Scott Baker192da222015-07-08 19:01:56 -0700486 LOOK_FOR_IMAGES=["ubuntu-vcpe4", # ONOS demo machine -- preferred vcpe image
Scott Baker866575c2015-06-02 16:03:30 -0700487 "Ubuntu 14.04 LTS", # portal
Scott Baker8c0ae622015-04-20 20:12:59 -0700488 "Ubuntu-14.04-LTS", # ONOS demo machine
489 ]
490 for image_name in LOOK_FOR_IMAGES:
491 images = Image.objects.filter(name = image_name)
492 if images:
493 return images[0]
494
495 raise XOSProgrammingError("No VPCE image (looked for %s)" % str(LOOK_FOR_IMAGES))
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700496
497 @property
498 def sliver(self):
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700499 if getattr(self, "cached_sliver", None):
500 return self.cached_sliver
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700501 sliver_id=self.get_attribute("sliver_id")
502 if not sliver_id:
503 return None
504 slivers=Sliver.objects.filter(id=sliver_id)
505 if not slivers:
506 return None
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700507 sliver=slivers[0]
Scott Bakerc633dc92015-05-05 17:49:46 -0700508 sliver.caller = self.creator
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700509 self.cached_sliver = sliver
510 return sliver
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700511
512 @sliver.setter
513 def sliver(self, value):
514 if value:
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700515 value = value.id
516 if (value != self.get_attribute("sliver_id", None)):
517 self.cached_sliver=None
518 self.set_attribute("sliver_id", value)
519
520 @property
Scott Bakerc633dc92015-05-05 17:49:46 -0700521 def creator(self):
522 if getattr(self, "cached_creator", None):
523 return self.cached_creator
524 creator_id=self.get_attribute("creator_id")
525 if not creator_id:
526 return None
527 users=User.objects.filter(id=creator_id)
528 if not users:
529 return None
530 user=users[0]
531 self.cached_creator = users[0]
532 return user
533
534 @creator.setter
535 def creator(self, value):
536 if value:
537 value = value.id
538 if (value != self.get_attribute("creator_id", None)):
539 self.cached_creator=None
540 self.set_attribute("creator_id", value)
541
542 @property
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700543 def vbng(self):
Scott Bakerd9133342015-07-06 14:38:02 -0700544 vbng = self.get_newest_subscribed_tenant(VBNGTenant)
545 if not vbng:
546 return None
547
548 # always return the same object when possible
549 if (self.cached_vbng) and (self.cached_vbng.id == vbng.id):
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700550 return self.cached_vbng
Scott Bakerd9133342015-07-06 14:38:02 -0700551
Scott Bakerc633dc92015-05-05 17:49:46 -0700552 vbng.caller = self.creator
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700553 self.cached_vbng = vbng
554 return vbng
555
556 @vbng.setter
557 def vbng(self, value):
Scott Bakerd9133342015-07-06 14:38:02 -0700558 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 -0700559
Scott Bakere4364d12015-07-06 17:21:21 -0700560 @property
561 def volt(self):
562 if not self.subscriber_tenant:
563 return None
564 volts = VOLTTenant.objects.filter(id=self.subscriber_tenant.id)
565 if not volts:
566 return None
567 return volts[0]
568
Scott Baker81de6402015-07-06 16:50:30 -0700569 @property
570 def bbs_account(self):
571 return self.get_attribute("bbs_account", self.default_attributes["bbs_account"])
572
573 @bbs_account.setter
574 def bbs_account(self, value):
575 return self.set_attribute("bbs_account", value)
576
577 @property
578 def last_ansible_hash(self):
579 return self.get_attribute("last_ansible_hash", self.default_attributes["last_ansible_hash"])
580
581 @last_ansible_hash.setter
582 def last_ansible_hash(self, value):
583 return self.set_attribute("last_ansible_hash", value)
584
585 @property
586 def ssh_command(self):
587 if self.sliver:
588 return self.sliver.get_ssh_command()
589 else:
590 return "no-sliver"
591
592 @ssh_command.setter
593 def ssh_command(self, value):
594 pass
595
Scott Baker5571c692015-05-20 08:19:25 -0700596 @property
597 def addresses(self):
598 if not self.sliver:
599 return {}
600
601 addresses = {}
Scott Baker11fe2e92015-08-28 11:55:19 -0700602 for ns in self.sliver.ports.all():
Scott Baker5571c692015-05-20 08:19:25 -0700603 if "lan" in ns.network.name.lower():
604 addresses["lan"] = ns.ip
605 elif "wan" in ns.network.name.lower():
606 addresses["wan"] = ns.ip
607 elif "private" in ns.network.name.lower():
608 addresses["private"] = ns.ip
609 elif "nat" in ns.network.name.lower():
610 addresses["nat"] = ns.ip
Scott Baker281b1af2015-06-04 10:26:44 -0700611 elif "hpc_client" in ns.network.name.lower():
612 addresses["hpc_client"] = ns.ip
Scott Baker5571c692015-05-20 08:19:25 -0700613 return addresses
614
Scott Baker432d1402015-05-20 08:25:29 -0700615 @property
616 def nat_ip(self):
617 return self.addresses.get("nat",None)
618
619 @property
620 def lan_ip(self):
621 return self.addresses.get("lan",None)
622
623 @property
624 def wan_ip(self):
625 return self.addresses.get("wan",None)
626
627 @property
Scott Baker4f972592015-06-05 12:08:34 -0700628 def wan_mac(self):
629 ip = self.wan_ip
630 if not ip:
631 return None
632 try:
633 (a,b,c,d) = ip.split('.')
634 wan_mac = "02:42:%2x:%2x:%2x:%2x" % (int(a), int(b), int(c), int(d))
635 except:
636 wan_mac = "Exception"
637 return wan_mac
638
639 @property
Scott Baker432d1402015-05-20 08:25:29 -0700640 def private_ip(self):
641 return self.addresses.get("private",None)
642
Scott Baker281b1af2015-06-04 10:26:44 -0700643 @property
644 def hpc_client_ip(self):
645 return self.addresses.get("hpc_client",None)
646
Scott Bakerd517a102015-06-09 12:30:30 -0700647 @property
648 def is_synced(self):
649 return (self.enacted is not None) and (self.enacted >= self.updated)
650
651 @is_synced.setter
652 def is_synced(self, value):
653 pass
654
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700655 def pick_node(self):
656 nodes = list(Node.objects.all())
657 # TODO: logic to filter nodes by which nodes are up, and which
658 # nodes the slice can instantiate on.
659 nodes = sorted(nodes, key=lambda node: node.slivers.all().count())
660 return nodes[0]
661
662 def manage_sliver(self):
Scott Bakerd4b48c02015-04-15 20:59:15 -0700663 # Each VCPE object owns exactly one sliver.
664
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700665 if self.deleted:
666 return
667
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700668 if (self.sliver is not None) and (self.sliver.image != self.image):
669 self.sliver.delete()
670 self.sliver = None
Scott Bakerc633dc92015-05-05 17:49:46 -0700671
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700672 if self.sliver is None:
673 if not self.provider_service.slices.count():
Scott Bakerf6790db2015-05-06 15:46:34 -0700674 raise XOSConfigurationError("The VCPE service has no slices")
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700675
Scott Bakere1f72d12015-05-14 21:48:53 -0700676 flavors = Flavor.objects.filter(name="m1.small")
677 if not flavors:
678 raise XOSConfigurationError("No m1.small flavor")
679
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700680 node =self.pick_node()
681 sliver = Sliver(slice = self.provider_service.slices.all()[0],
682 node = node,
683 image = self.image,
Scott Bakerc633dc92015-05-05 17:49:46 -0700684 creator = self.creator,
Scott Bakere1f72d12015-05-14 21:48:53 -0700685 deployment = node.site_deployment.deployment,
686 flavor = flavors[0])
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700687 sliver.save()
688
Scott Bakerd4b48c02015-04-15 20:59:15 -0700689 try:
690 self.sliver = sliver
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700691 super(VCPETenant, self).save()
Scott Bakerd4b48c02015-04-15 20:59:15 -0700692 except:
693 sliver.delete()
694 raise
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700695
696 def cleanup_sliver(self):
697 if self.sliver:
Scott Bakerd9133342015-07-06 14:38:02 -0700698 # print "XXX cleanup sliver", self.sliver
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700699 self.sliver.delete()
700 self.sliver = None
701
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700702 def manage_vbng(self):
703 # Each vCPE object owns exactly one vBNG object
704
705 if self.deleted:
706 return
707
708 if self.vbng is None:
709 vbngServices = VBNGService.get_service_objects().all()
710 if not vbngServices:
Scott Baker7f8ef8f2015-04-20 14:24:29 -0700711 raise XOSConfigurationError("No VBNG Services available")
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700712
713 vbng = VBNGTenant(provider_service = vbngServices[0],
714 subscriber_tenant = self)
Scott Bakerc633dc92015-05-05 17:49:46 -0700715 vbng.caller = self.creator
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700716 vbng.save()
717
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700718 def cleanup_vbng(self):
719 if self.vbng:
Scott Bakerd9133342015-07-06 14:38:02 -0700720 # print "XXX cleanup vnbg", self.vbng
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700721 self.vbng.delete()
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700722
Scott Baker868dabf2015-06-24 12:54:24 -0700723 def cleanup_orphans(self):
Scott Bakerd9133342015-07-06 14:38:02 -0700724 # ensure vCPE only has one vBNG
725 cur_vbng = self.vbng
726 for vbng in list(self.get_subscribed_tenants(VBNGTenant)):
727 if (not cur_vbng) or (vbng.id != cur_vbng.id):
728 # print "XXX clean up orphaned vbng", vbng
729 vbng.delete()
Scott Baker868dabf2015-06-24 12:54:24 -0700730
731 if self.orig_sliver_id and (self.orig_sliver_id != self.get_attribute("sliver_id")):
732 slivers=Sliver.objects.filter(id=self.orig_sliver_id)
733 if slivers:
734 # print "XXX clean up orphaned sliver", slivers[0]
735 slivers[0].delete()
736
Scott Baker4e6d60d2015-05-20 20:45:11 -0700737 def manage_bbs_account(self):
738 if self.deleted:
739 return
740
Scott Baker126ad472015-07-07 17:59:44 -0700741 if self.volt and self.volt.subscriber and self.volt.subscriber.url_filter_enable:
Scott Baker642126f2015-05-20 20:57:28 -0700742 if not self.bbs_account:
743 # make sure we use the proxied VCPEService object, not the generic Service object
744 vcpe_service = VCPEService.objects.get(id=self.provider_service.id)
Scott Baker050f8b32015-07-07 12:15:03 -0700745 self.bbs_account = vcpe_service.allocate_bbs_account()
Scott Baker642126f2015-05-20 20:57:28 -0700746 super(VCPETenant, self).save()
747 else:
748 if self.bbs_account:
749 self.bbs_account = None
750 super(VCPETenant, self).save()
Scott Baker4e6d60d2015-05-20 20:45:11 -0700751
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700752 def save(self, *args, **kwargs):
Scott Bakerc633dc92015-05-05 17:49:46 -0700753 if not self.creator:
754 if not getattr(self, "caller", None):
755 # caller must be set when creating a vCPE since it creates a slice
Scott Bakerf6790db2015-05-06 15:46:34 -0700756 raise XOSProgrammingError("VCPETenant's self.caller was not set")
Scott Bakerc633dc92015-05-05 17:49:46 -0700757 self.creator = self.caller
758 if not self.creator:
Scott Bakerf6790db2015-05-06 15:46:34 -0700759 raise XOSProgrammingError("VCPETenant's self.creator was not set")
Scott Bakerc633dc92015-05-05 17:49:46 -0700760
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700761 super(VCPETenant, self).save(*args, **kwargs)
Scott Baker192da222015-07-08 19:01:56 -0700762 model_policy_vcpe(self.pk)
763 #self.manage_sliver()
764 #self.manage_vbng()
765 #self.manage_bbs_account()
766 #self.cleanup_orphans()
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700767
768 def delete(self, *args, **kwargs):
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700769 self.cleanup_vbng()
Scott Bakere9ff7ce2015-04-14 17:19:16 -0700770 self.cleanup_sliver()
771 super(VCPETenant, self).delete(*args, **kwargs)
772
Scott Baker192da222015-07-08 19:01:56 -0700773def model_policy_vcpe(pk):
774 # TODO: this should be made in to a real model_policy
775 with transaction.atomic():
776 vcpe = VCPETenant.objects.select_for_update().filter(pk=pk)
777 if not vcpe:
778 return
779 vcpe = vcpe[0]
780 vcpe.manage_sliver()
781 vcpe.manage_vbng()
782 vcpe.manage_bbs_account()
783 vcpe.cleanup_orphans()
784
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700785#----------------------------------------------------------------------------
786# vBNG
787#----------------------------------------------------------------------------
788
789class VBNGService(Service):
Scott Bakerd9133342015-07-06 14:38:02 -0700790 KIND = VBNG_KIND
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700791
Scott Baker21d18932015-07-21 18:24:21 -0700792 simple_attributes = ( ("vbng_url", "http://10.0.3.136:8181/onos/virtualbng/"), )
793
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700794 class Meta:
795 app_label = "cord"
796 verbose_name = "vBNG Service"
797 proxy = True
798
Scott Baker21d18932015-07-21 18:24:21 -0700799VBNGService.setup_simple_attributes()
800
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700801class VBNGTenant(Tenant):
802 class Meta:
803 proxy = True
804
Scott Bakerd9133342015-07-06 14:38:02 -0700805 KIND = VBNG_KIND
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700806
Scott Baker61c8e8d2015-06-02 14:34:04 -0700807 default_attributes = {"routeable_subnet": "",
Scott Bakercf155f42015-06-08 19:09:53 -0700808 "mapped_ip": "",
809 "mapped_mac": "",
810 "mapped_hostname": ""}
Scott Bakerfa5cdd62015-04-20 09:16:17 -0700811
812 @property
813 def routeable_subnet(self):
814 return self.get_attribute("routeable_subnet", self.default_attributes["routeable_subnet"])
815
816 @routeable_subnet.setter
817 def routeable_subnet(self, value):
818 self.set_attribute("routeable_subnet", value)
Scott Baker61c8e8d2015-06-02 14:34:04 -0700819
820 @property
821 def mapped_ip(self):
822 return self.get_attribute("mapped_ip", self.default_attributes["mapped_ip"])
823
824 @mapped_ip.setter
825 def mapped_ip(self, value):
826 self.set_attribute("mapped_ip", value)
Scott Bakercf155f42015-06-08 19:09:53 -0700827
828 @property
829 def mapped_mac(self):
830 return self.get_attribute("mapped_mac", self.default_attributes["mapped_mac"])
831
832 @mapped_mac.setter
833 def mapped_mac(self, value):
834 self.set_attribute("mapped_mac", value)
835
836 @property
837 def mapped_hostname(self):
838 return self.get_attribute("mapped_hostname", self.default_attributes["mapped_hostname"])
839
840 @mapped_hostname.setter
841 def mapped_hostname(self, value):
842 self.set_attribute("mapped_hostname", value)