blob: 59397a05e058c4e2686b51b9c432b5f8a8994654 [file] [log] [blame]
Scott Baker1b241612015-04-14 17:19:16 -07001from django.db import models
Scott Bakerf08823d2015-07-06 16:50:30 -07002from core.models import Service, PlCoreBase, Slice, Sliver, Tenant, Node, Image, User, Flavor, Subscriber
Scott Baker1b241612015-04-14 17:19:16 -07003from core.models.plcorebase import StrippedCharField
4import os
5from django.db import models
6from django.forms.models import model_to_dict
7from django.db.models import Q
8from operator import itemgetter, attrgetter, methodcaller
Scott Baker697fb0b2015-04-20 09:16:17 -07009import traceback
Scott Bakerd921e1c2015-04-20 14:24:29 -070010from xos.exceptions import *
Scott Baker1b241612015-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 Baker1b241612015-04-14 17:19:16 -070022
Scott Baker557aada2015-04-20 09:48:34 -070023t = VOLTTenant()
Scott Baker1b241612015-04-14 17:19:16 -070024t.caller = User.objects.all()[0]
25t.save()
26
Scott Baker2b29a312015-05-11 08:31:24 -070027for v in VOLTTenant.get_tenant_objects().all():
Scott Baker39b0d892015-04-15 20:59:15 -070028 v.caller = User.objects.all()[0]
29 v.delete()
30
Scott Baker2b29a312015-05-11 08:31:24 -070031for v in VCPETenant.get_tenant_objects().all():
Scott Baker1b241612015-04-14 17:19:16 -070032 v.caller = User.objects.all()[0]
33 v.delete()
Scott Baker697fb0b2015-04-20 09:16:17 -070034
Scott Baker2b29a312015-05-11 08:31:24 -070035for v in VOLTTenant.get_tenant_objects().all():
Scott Baker697fb0b2015-04-20 09:16:17 -070036 v.caller = User.objects.all()[0]
37 v.delete()
Scott Baker9c8a2c72015-05-05 17:49:46 -070038
Scott Baker2b29a312015-05-11 08:31:24 -070039for v in VOLTTenant.get_tenant_objects().all():
Scott Baker9c8a2c72015-05-05 17:49:46 -070040 if not v.creator:
41 v.creator= User.objects.all()[0]
42 v.save()
43
Scott Baker2b29a312015-05-11 08:31:24 -070044for v in VCPETenant.get_tenant_objects().all():
Scott Baker9c8a2c72015-05-05 17:49:46 -070045 if not v.creator:
46 v.creator= User.objects.all()[0]
47 v.save()
Scott Baker1b241612015-04-14 17:19:16 -070048"""
49
50class ConfigurationError(Exception):
51 pass
52
Scott Baker361c86c2015-07-06 14:38:02 -070053VOLT_KIND = "vOLT"
54VCPE_KIND = "vCPE"
55VBNG_KIND = "vBNG"
Scott Bakerf08823d2015-07-06 16:50:30 -070056CORD_SUBSCRIBER_KIND = "CordSubscriberRoot"
57
58# -------------------------------------------
59# CordSubscriberRoot
60# -------------------------------------------
61
62class CordSubscriberRoot(Subscriber):
Scott Bakercd349182015-07-06 17:21:21 -070063 class Meta:
64 proxy = True
65
Scott Bakerf08823d2015-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,
74 "users": [] }
75
76 def __init__(self, *args, **kwargs):
77 super(CordSubscriberRoot, self).__init__(*args, **kwargs)
78 self.cached_volt = None
79
80 @property
81 def volt(self):
82 volt = self.get_newest_subscribed_tenant(VOLTTenant)
83 if not volt:
84 return None
85
86 # always return the same object when possible
87 if (self.cached_volt) and (self.cached_volt.id == volt.id):
88 return self.cached_vcpe
89
Scott Bakercd349182015-07-06 17:21:21 -070090 #volt.caller = self.creator
Scott Bakerf08823d2015-07-06 16:50:30 -070091 self.cached_volt = volt
92 return volt
93
94 @property
95 def firewall_enable(self):
96 return self.get_attribute("firewall_enable", self.default_attributes["firewall_enable"])
97
98 @firewall_enable.setter
99 def firewall_enable(self, value):
100 self.set_attribute("firewall_enable", value)
101
102 @property
103 def firewall_rules(self):
104 return self.get_attribute("firewall_rules", self.default_attributes["firewall_rules"])
105
106 @firewall_rules.setter
107 def firewall_rules(self, value):
108 self.set_attribute("firewall_rules", value)
109
110 @property
111 def url_filter_enable(self):
112 return self.get_attribute("url_filter_enable", self.default_attributes["url_filter_enable"])
113
114 @url_filter_enable.setter
115 def url_filter_enable(self, value):
116 self.set_attribute("url_filter_enable", value)
117
118 @property
119 def url_filter_level(self):
120 return self.get_attribute("url_filter_level", self.default_attributes["url_filter_level"])
121
122 @url_filter_level.setter
123 def url_filter_level(self, value):
124 self.set_attribute("url_filter_level", value)
125
126 @property
127 def url_filter_rules(self):
128 return self.get_attribute("url_filter_rules", self.default_attributes["url_filter_rules"])
129
130 @url_filter_rules.setter
131 def url_filter_rules(self, value):
132 self.set_attribute("url_filter_rules", value)
133
134 @property
135 def cdn_enable(self):
136 return self.get_attribute("cdn_enable", self.default_attributes["cdn_enable"])
137
138 @cdn_enable.setter
139 def cdn_enable(self, value):
140 self.set_attribute("cdn_enable", value)
141
142 @property
143 def users(self):
144 return self.get_attribute("users", self.default_attributes["users"])
145
146 @users.setter
147 def users(self, value):
148 self.set_attribute("users", value)
149
150 def find_user(self, uid):
151 uid = int(uid)
152 for user in self.users:
153 if user["id"] == uid:
154 return user
155 return None
156
157 def update_user(self, uid, **kwargs):
158 # kwargs may be "level" or "mac"
159 # Setting one of these to None will cause None to be stored in the db
160 uid = int(uid)
161 users = self.users
162 for user in users:
163 if user["id"] == uid:
164 for arg in kwargs.keys():
165 user[arg] = kwargs[arg]
166 self.users = users
167 return user
168 raise ValueError("User %d not found" % uid)
169
170 def create_user(self, **kwargs):
171 if "name" not in kwargs:
172 raise XOSMissingField("The name field is required")
173
174 for user in self.users:
175 if kwargs["name"] == user["name"]:
176 raise XOSDuplicateKey("User %s already exists" % kwargs["name"])
177
178 uids = [x["id"] for x in self.users]
179 if uids:
180 uid = max(uids)+1
181 else:
182 uid = 0
183 newuser = kwargs.copy()
184 newuser["id"] = uid
185
186 users = self.users
187 users.append(newuser)
188 self.users = users
189
190 return newuser
191
192 def delete_user(self, uid):
193 uid = int(uid)
194 users = self.users
195 for user in users:
196 if user["id"]==uid:
197 users.remove(user)
198 self.users = users
199 return
200
201 raise ValueError("Users %d not found" % uid)
202
203 @property
204 def services(self):
205 return {"cdn": self.cdn_enable,
206 "url_filter": self.url_filter_enable,
207 "firewall": self.firewall_enable}
208
209 @services.setter
210 def services(self, value):
211 pass
Scott Baker361c86c2015-07-06 14:38:02 -0700212
Scott Baker39b0d892015-04-15 20:59:15 -0700213# -------------------------------------------
214# VOLT
215# -------------------------------------------
216
217class VOLTService(Service):
Scott Baker361c86c2015-07-06 14:38:02 -0700218 KIND = VOLT_KIND
Scott Baker39b0d892015-04-15 20:59:15 -0700219
Scott Baker1b241612015-04-14 17:19:16 -0700220 class Meta:
Scott Baker39b0d892015-04-15 20:59:15 -0700221 app_label = "cord"
222 verbose_name = "vOLT Service"
223 proxy = True
224
225class VOLTTenant(Tenant):
226 class Meta:
227 proxy = True
228
Scott Baker361c86c2015-07-06 14:38:02 -0700229 KIND = VOLT_KIND
Scott Baker39b0d892015-04-15 20:59:15 -0700230
Scott Baker664c4282015-05-28 17:12:00 -0700231 default_attributes = {"vlan_id": None,
232 "is_demo_user": False }
Scott Bakere744c7b2015-04-20 11:50:09 -0700233
Scott Baker557aada2015-04-20 09:48:34 -0700234 def __init__(self, *args, **kwargs):
235 volt_services = VOLTService.get_service_objects().all()
236 if volt_services:
237 self._meta.get_field("provider_service").default = volt_services[0].id
238 super(VOLTTenant, self).__init__(*args, **kwargs)
Scott Baker361c86c2015-07-06 14:38:02 -0700239 self.cached_vcpe = None
Scott Baker5e76f802015-06-24 12:54:24 -0700240
Scott Baker39b0d892015-04-15 20:59:15 -0700241 @property
Scott Bakere744c7b2015-04-20 11:50:09 -0700242 def vlan_id(self):
243 return self.get_attribute("vlan_id", self.default_attributes["vlan_id"])
244
245 @vlan_id.setter
246 def vlan_id(self, value):
247 self.set_attribute("vlan_id", value)
248
249 @property
Scott Baker39b0d892015-04-15 20:59:15 -0700250 def vcpe(self):
Scott Baker361c86c2015-07-06 14:38:02 -0700251 vcpe = self.get_newest_subscribed_tenant(VCPETenant)
252 if not vcpe:
253 return None
254
255 # always return the same object when possible
256 if (self.cached_vcpe) and (self.cached_vcpe.id == vcpe.id):
Scott Baker697fb0b2015-04-20 09:16:17 -0700257 return self.cached_vcpe
Scott Baker361c86c2015-07-06 14:38:02 -0700258
Scott Baker9c8a2c72015-05-05 17:49:46 -0700259 vcpe.caller = self.creator
Scott Baker697fb0b2015-04-20 09:16:17 -0700260 self.cached_vcpe = vcpe
261 return vcpe
Scott Baker39b0d892015-04-15 20:59:15 -0700262
263 @vcpe.setter
264 def vcpe(self, value):
Scott Bakercd349182015-07-06 17:21:21 -0700265 raise XOSConfigurationError("vOLT.vCPE cannot be set this way -- create a new vCPE object and set its subscriber_tenant instead")
266
267 @property
268 def subscriber(self):
269 if not self.subscriber_root:
270 return None
271 subs = CordSubscriberRoot.objects.filter(id=self.subscriber_root.id)
272 if not subs:
273 return None
274 return subs[0]
Scott Baker39b0d892015-04-15 20:59:15 -0700275
Scott Baker9c8a2c72015-05-05 17:49:46 -0700276 @property
277 def creator(self):
278 if getattr(self, "cached_creator", None):
279 return self.cached_creator
280 creator_id=self.get_attribute("creator_id")
281 if not creator_id:
282 return None
283 users=User.objects.filter(id=creator_id)
284 if not users:
285 return None
286 user=users[0]
287 self.cached_creator = users[0]
288 return user
289
290 @creator.setter
291 def creator(self, value):
292 if value:
293 value = value.id
294 if (value != self.get_attribute("creator_id", None)):
295 self.cached_creator=None
296 self.set_attribute("creator_id", value)
297
Scott Baker664c4282015-05-28 17:12:00 -0700298 @property
299 def is_demo_user(self):
300 return self.get_attribute("is_demo_user", self.default_attributes["is_demo_user"])
301
302 @is_demo_user.setter
303 def is_demo_user(self, value):
304 self.set_attribute("is_demo_user", value)
305
Scott Baker39b0d892015-04-15 20:59:15 -0700306 def manage_vcpe(self):
307 # Each VOLT object owns exactly one VCPE object
308
309 if self.deleted:
310 return
311
312 if self.vcpe is None:
313 vcpeServices = VCPEService.get_service_objects().all()
314 if not vcpeServices:
Scott Bakerd921e1c2015-04-20 14:24:29 -0700315 raise XOSConfigurationError("No VCPE Services available")
Scott Baker39b0d892015-04-15 20:59:15 -0700316
317 vcpe = VCPETenant(provider_service = vcpeServices[0],
318 subscriber_tenant = self)
Scott Baker9c8a2c72015-05-05 17:49:46 -0700319 vcpe.caller = self.creator
Scott Baker39b0d892015-04-15 20:59:15 -0700320 vcpe.save()
321
Scott Baker39b0d892015-04-15 20:59:15 -0700322 def cleanup_vcpe(self):
323 if self.vcpe:
Scott Baker361c86c2015-07-06 14:38:02 -0700324 # print "XXX cleanup vcpe", self.vcpe
Scott Baker39b0d892015-04-15 20:59:15 -0700325 self.vcpe.delete()
Scott Baker39b0d892015-04-15 20:59:15 -0700326
Scott Baker5e76f802015-06-24 12:54:24 -0700327 def cleanup_orphans(self):
Scott Baker361c86c2015-07-06 14:38:02 -0700328 # ensure vOLT only has one vCPE
329 cur_vcpe = self.vcpe
330 for vcpe in list(self.get_subscribed_tenants(VCPETenant)):
331 if (not cur_vcpe) or (vcpe.id != cur_vcpe.id):
332 # print "XXX clean up orphaned vcpe", vcpe
333 vcpe.delete()
Scott Baker5e76f802015-06-24 12:54:24 -0700334
Scott Baker39b0d892015-04-15 20:59:15 -0700335 def save(self, *args, **kwargs):
Scott Bakerd921e1c2015-04-20 14:24:29 -0700336 self.validate_unique_service_specific_id()
337
Scott Baker9c8a2c72015-05-05 17:49:46 -0700338 if not self.creator:
339 if not getattr(self, "caller", None):
340 # caller must be set when creating a vCPE since it creates a slice
341 raise XOSProgrammingError("VOLTTenant's self.caller was not set")
342 self.creator = self.caller
343 if not self.creator:
344 raise XOSProgrammingError("VOLTTenant's self.creator was not set")
345
Scott Baker39b0d892015-04-15 20:59:15 -0700346 super(VOLTTenant, self).save(*args, **kwargs)
347 self.manage_vcpe()
Scott Baker5e76f802015-06-24 12:54:24 -0700348 self.cleanup_orphans()
Scott Baker39b0d892015-04-15 20:59:15 -0700349
350 def delete(self, *args, **kwargs):
351 self.cleanup_vcpe()
352 super(VOLTTenant, self).delete(*args, **kwargs)
353
354# -------------------------------------------
355# VCPE
356# -------------------------------------------
357
358class VCPEService(Service):
Scott Baker361c86c2015-07-06 14:38:02 -0700359 KIND = VCPE_KIND
Scott Baker39b0d892015-04-15 20:59:15 -0700360
361 class Meta:
362 app_label = "cord"
Scott Baker1b241612015-04-14 17:19:16 -0700363 verbose_name = "vCPE Service"
Scott Baker39b0d892015-04-15 20:59:15 -0700364 proxy = True
Scott Baker1b241612015-04-14 17:19:16 -0700365
Scott Baker5c8abf82015-05-20 20:45:11 -0700366 def allocate_bbs_account(self):
367 vcpes = VCPETenant.get_tenant_objects().all()
368 bbs_accounts = [vcpe.bbs_account for vcpe in vcpes]
369
370 # There's a bit of a race here; some other user could be trying to
371 # allocate a bbs_account at the same time we are.
372
Scott Bakerf4f61ca2015-06-09 12:03:56 -0700373 for i in range(2,21):
Scott Baker5c8abf82015-05-20 20:45:11 -0700374 account_name = "bbs%02d@onlab.us" % i
375 if (account_name not in bbs_accounts):
376 return account_name
377
378 raise XOSConfigurationError("We've run out of available broadbandshield accounts. Delete some vcpe and try again.")
379
Scott Baker1b241612015-04-14 17:19:16 -0700380class VCPETenant(Tenant):
381 class Meta:
382 proxy = True
383
Scott Baker361c86c2015-07-06 14:38:02 -0700384 KIND = VCPE_KIND
Scott Baker39b0d892015-04-15 20:59:15 -0700385
Scott Baker9c8a2c72015-05-05 17:49:46 -0700386 sync_attributes = ("firewall_enable",
387 "firewall_rules",
388 "url_filter_enable",
389 "url_filter_rules",
Scott Bakerc7a96c82015-05-20 08:41:38 -0700390 "cdn_enable",
391 "nat_ip",
392 "lan_ip",
393 "wan_ip",
Scott Baker710ad052015-06-04 10:26:44 -0700394 "private_ip",
Scott Baker3f4fe402015-06-05 12:08:34 -0700395 "hpc_client_ip",
396 "wan_mac")
Scott Baker9c8a2c72015-05-05 17:49:46 -0700397
Scott Baker1b241612015-04-14 17:19:16 -0700398 default_attributes = {"firewall_enable": False,
Scott Baker0bcbb962015-04-16 21:54:50 -0700399 "firewall_rules": "accept all anywhere anywhere",
400 "url_filter_enable": False,
401 "url_filter_rules": "allow all",
Scott Baker8d13a982015-05-14 20:29:04 -0700402 "url_filter_level": "PG",
Scott Baker0bcbb962015-04-16 21:54:50 -0700403 "cdn_enable": False,
Scott Bakera0cf9612015-05-20 16:31:58 -0700404 "sliver_id": None,
Scott Baker5c8abf82015-05-20 20:45:11 -0700405 "users": [],
Scott Bakerd40a42d2015-06-09 12:22:29 -0700406 "bbs_account": None,
407 "last_ansible_hash": None}
Scott Baker1b241612015-04-14 17:19:16 -0700408
Scott Baker697fb0b2015-04-20 09:16:17 -0700409 def __init__(self, *args, **kwargs):
410 super(VCPETenant, self).__init__(*args, **kwargs)
411 self.cached_vbng=None
412 self.cached_sliver=None
Scott Baker5e76f802015-06-24 12:54:24 -0700413 self.orig_sliver_id = self.get_initial_attribute("sliver_id")
Scott Baker697fb0b2015-04-20 09:16:17 -0700414
Scott Baker1b241612015-04-14 17:19:16 -0700415 @property
416 def image(self):
Andy Bavieracf02052015-06-10 15:59:04 -0400417 LOOK_FOR_IMAGES=["ubuntu-vcpe3", # ONOS demo machine -- preferred vcpe image
Scott Baker2c4f1eb2015-06-02 16:03:30 -0700418 "Ubuntu 14.04 LTS", # portal
Scott Baker4f751bd2015-04-20 20:12:59 -0700419 "Ubuntu-14.04-LTS", # ONOS demo machine
420 ]
421 for image_name in LOOK_FOR_IMAGES:
422 images = Image.objects.filter(name = image_name)
423 if images:
424 return images[0]
425
426 raise XOSProgrammingError("No VPCE image (looked for %s)" % str(LOOK_FOR_IMAGES))
Scott Baker1b241612015-04-14 17:19:16 -0700427
428 @property
429 def sliver(self):
Scott Baker697fb0b2015-04-20 09:16:17 -0700430 if getattr(self, "cached_sliver", None):
431 return self.cached_sliver
Scott Baker1b241612015-04-14 17:19:16 -0700432 sliver_id=self.get_attribute("sliver_id")
433 if not sliver_id:
434 return None
435 slivers=Sliver.objects.filter(id=sliver_id)
436 if not slivers:
437 return None
Scott Baker697fb0b2015-04-20 09:16:17 -0700438 sliver=slivers[0]
Scott Baker9c8a2c72015-05-05 17:49:46 -0700439 sliver.caller = self.creator
Scott Baker697fb0b2015-04-20 09:16:17 -0700440 self.cached_sliver = sliver
441 return sliver
Scott Baker1b241612015-04-14 17:19:16 -0700442
443 @sliver.setter
444 def sliver(self, value):
445 if value:
Scott Baker697fb0b2015-04-20 09:16:17 -0700446 value = value.id
447 if (value != self.get_attribute("sliver_id", None)):
448 self.cached_sliver=None
449 self.set_attribute("sliver_id", value)
450
451 @property
Scott Baker9c8a2c72015-05-05 17:49:46 -0700452 def creator(self):
453 if getattr(self, "cached_creator", None):
454 return self.cached_creator
455 creator_id=self.get_attribute("creator_id")
456 if not creator_id:
457 return None
458 users=User.objects.filter(id=creator_id)
459 if not users:
460 return None
461 user=users[0]
462 self.cached_creator = users[0]
463 return user
464
465 @creator.setter
466 def creator(self, value):
467 if value:
468 value = value.id
469 if (value != self.get_attribute("creator_id", None)):
470 self.cached_creator=None
471 self.set_attribute("creator_id", value)
472
473 @property
Scott Baker697fb0b2015-04-20 09:16:17 -0700474 def vbng(self):
Scott Baker361c86c2015-07-06 14:38:02 -0700475 vbng = self.get_newest_subscribed_tenant(VBNGTenant)
476 if not vbng:
477 return None
478
479 # always return the same object when possible
480 if (self.cached_vbng) and (self.cached_vbng.id == vbng.id):
Scott Baker697fb0b2015-04-20 09:16:17 -0700481 return self.cached_vbng
Scott Baker361c86c2015-07-06 14:38:02 -0700482
Scott Baker9c8a2c72015-05-05 17:49:46 -0700483 vbng.caller = self.creator
Scott Baker697fb0b2015-04-20 09:16:17 -0700484 self.cached_vbng = vbng
485 return vbng
486
487 @vbng.setter
488 def vbng(self, value):
Scott Baker361c86c2015-07-06 14:38:02 -0700489 raise XOSConfigurationError("vCPE.vBNG cannot be set this way -- create a new vBNG object and set it's subscriber_tenant instead")
Scott Baker1b241612015-04-14 17:19:16 -0700490
Scott Bakercd349182015-07-06 17:21:21 -0700491 @property
492 def volt(self):
493 if not self.subscriber_tenant:
494 return None
495 volts = VOLTTenant.objects.filter(id=self.subscriber_tenant.id)
496 if not volts:
497 return None
498 return volts[0]
499
Scott Bakerf08823d2015-07-06 16:50:30 -0700500 # *** to be moved to CordSubscriberRoot
501
Scott Baker1b241612015-04-14 17:19:16 -0700502 @property
503 def firewall_enable(self):
504 return self.get_attribute("firewall_enable", self.default_attributes["firewall_enable"])
505
506 @firewall_enable.setter
507 def firewall_enable(self, value):
508 self.set_attribute("firewall_enable", value)
509
Scott Baker0bcbb962015-04-16 21:54:50 -0700510 @property
511 def firewall_rules(self):
512 return self.get_attribute("firewall_rules", self.default_attributes["firewall_rules"])
513
514 @firewall_rules.setter
515 def firewall_rules(self, value):
516 self.set_attribute("firewall_rules", value)
517
518 @property
519 def url_filter_enable(self):
520 return self.get_attribute("url_filter_enable", self.default_attributes["url_filter_enable"])
521
522 @url_filter_enable.setter
523 def url_filter_enable(self, value):
524 self.set_attribute("url_filter_enable", value)
525
526 @property
Scott Baker8d13a982015-05-14 20:29:04 -0700527 def url_filter_level(self):
528 return self.get_attribute("url_filter_level", self.default_attributes["url_filter_level"])
529
530 @url_filter_level.setter
531 def url_filter_level(self, value):
532 self.set_attribute("url_filter_level", value)
533
534 @property
Scott Baker0bcbb962015-04-16 21:54:50 -0700535 def url_filter_rules(self):
536 return self.get_attribute("url_filter_rules", self.default_attributes["url_filter_rules"])
537
538 @url_filter_rules.setter
539 def url_filter_rules(self, value):
540 self.set_attribute("url_filter_rules", value)
541
542 @property
543 def cdn_enable(self):
544 return self.get_attribute("cdn_enable", self.default_attributes["cdn_enable"])
545
546 @cdn_enable.setter
547 def cdn_enable(self, value):
548 self.set_attribute("cdn_enable", value)
549
Scott Baker8d13a982015-05-14 20:29:04 -0700550 @property
551 def users(self):
Scott Bakera0cf9612015-05-20 16:31:58 -0700552 return self.get_attribute("users", self.default_attributes["users"])
Scott Baker8d13a982015-05-14 20:29:04 -0700553
554 @users.setter
555 def users(self, value):
Scott Bakera0cf9612015-05-20 16:31:58 -0700556 self.set_attribute("users", value)
557
558 def find_user(self, uid):
559 uid = int(uid)
560 for user in self.users:
561 if user["id"] == uid:
562 return user
563 return None
564
565 def update_user(self, uid, **kwargs):
566 # kwargs may be "level" or "mac"
567 # Setting one of these to None will cause None to be stored in the db
568 uid = int(uid)
569 users = self.users
570 for user in users:
571 if user["id"] == uid:
572 for arg in kwargs.keys():
573 user[arg] = kwargs[arg]
574 self.users = users
Scott Bakerac731702015-06-01 20:34:03 -0700575 return user
Scott Bakera0cf9612015-05-20 16:31:58 -0700576 raise ValueError("User %d not found" % uid)
577
578 def create_user(self, **kwargs):
Scott Baker7c796302015-05-28 19:44:20 -0700579 if "name" not in kwargs:
580 raise XOSMissingField("The name field is required")
581
582 for user in self.users:
583 if kwargs["name"] == user["name"]:
584 raise XOSDuplicateKey("User %s already exists" % kwargs["name"])
585
Scott Bakera0cf9612015-05-20 16:31:58 -0700586 uids = [x["id"] for x in self.users]
587 if uids:
588 uid = max(uids)+1
589 else:
590 uid = 0
591 newuser = kwargs.copy()
592 newuser["id"] = uid
593
594 users = self.users
595 users.append(newuser)
596 self.users = users
597
598 return newuser
599
600 def delete_user(self, uid):
601 uid = int(uid)
602 users = self.users
603 for user in users:
604 if user["id"]==uid:
605 users.remove(user)
606 self.users = users
607 return
608
609 raise ValueError("Users %d not found" % uid)
Scott Baker8d13a982015-05-14 20:29:04 -0700610
611 @property
612 def services(self):
Scott Bakerf4c3ad42015-05-15 14:59:47 -0700613 return {"cdn": self.cdn_enable,
614 "url_filter": self.url_filter_enable,
615 "firewall": self.firewall_enable}
Scott Baker8d13a982015-05-14 20:29:04 -0700616
617 @services.setter
618 def services(self, value):
619 pass
620
Scott Bakerf08823d2015-07-06 16:50:30 -0700621 # *** end of stuff to be moved to CordSubscriberRoot
622
623 @property
624 def bbs_account(self):
625 return self.get_attribute("bbs_account", self.default_attributes["bbs_account"])
626
627 @bbs_account.setter
628 def bbs_account(self, value):
629 return self.set_attribute("bbs_account", value)
630
631 @property
632 def last_ansible_hash(self):
633 return self.get_attribute("last_ansible_hash", self.default_attributes["last_ansible_hash"])
634
635 @last_ansible_hash.setter
636 def last_ansible_hash(self, value):
637 return self.set_attribute("last_ansible_hash", value)
638
639 @property
640 def ssh_command(self):
641 if self.sliver:
642 return self.sliver.get_ssh_command()
643 else:
644 return "no-sliver"
645
646 @ssh_command.setter
647 def ssh_command(self, value):
648 pass
649
Scott Baker706bf972015-05-20 08:19:25 -0700650 @property
651 def addresses(self):
652 if not self.sliver:
653 return {}
654
655 addresses = {}
656 for ns in self.sliver.networkslivers.all():
657 if "lan" in ns.network.name.lower():
658 addresses["lan"] = ns.ip
659 elif "wan" in ns.network.name.lower():
660 addresses["wan"] = ns.ip
661 elif "private" in ns.network.name.lower():
662 addresses["private"] = ns.ip
663 elif "nat" in ns.network.name.lower():
664 addresses["nat"] = ns.ip
Scott Baker710ad052015-06-04 10:26:44 -0700665 elif "hpc_client" in ns.network.name.lower():
666 addresses["hpc_client"] = ns.ip
Scott Baker706bf972015-05-20 08:19:25 -0700667 return addresses
668
Scott Bakera6a7e032015-05-20 08:25:29 -0700669 @property
670 def nat_ip(self):
671 return self.addresses.get("nat",None)
672
673 @property
674 def lan_ip(self):
675 return self.addresses.get("lan",None)
676
677 @property
678 def wan_ip(self):
679 return self.addresses.get("wan",None)
680
681 @property
Scott Baker3f4fe402015-06-05 12:08:34 -0700682 def wan_mac(self):
683 ip = self.wan_ip
684 if not ip:
685 return None
686 try:
687 (a,b,c,d) = ip.split('.')
688 wan_mac = "02:42:%2x:%2x:%2x:%2x" % (int(a), int(b), int(c), int(d))
689 except:
690 wan_mac = "Exception"
691 return wan_mac
692
693 @property
Scott Bakera6a7e032015-05-20 08:25:29 -0700694 def private_ip(self):
695 return self.addresses.get("private",None)
696
Scott Baker710ad052015-06-04 10:26:44 -0700697 @property
698 def hpc_client_ip(self):
699 return self.addresses.get("hpc_client",None)
700
Scott Baker7bbdd2f2015-06-09 12:30:30 -0700701 @property
702 def is_synced(self):
703 return (self.enacted is not None) and (self.enacted >= self.updated)
704
705 @is_synced.setter
706 def is_synced(self, value):
707 pass
708
Scott Baker1b241612015-04-14 17:19:16 -0700709 def pick_node(self):
710 nodes = list(Node.objects.all())
711 # TODO: logic to filter nodes by which nodes are up, and which
712 # nodes the slice can instantiate on.
713 nodes = sorted(nodes, key=lambda node: node.slivers.all().count())
714 return nodes[0]
715
716 def manage_sliver(self):
Scott Baker39b0d892015-04-15 20:59:15 -0700717 # Each VCPE object owns exactly one sliver.
718
Scott Baker1b241612015-04-14 17:19:16 -0700719 if self.deleted:
720 return
721
Scott Baker1b241612015-04-14 17:19:16 -0700722 if (self.sliver is not None) and (self.sliver.image != self.image):
723 self.sliver.delete()
724 self.sliver = None
Scott Baker9c8a2c72015-05-05 17:49:46 -0700725
Scott Baker1b241612015-04-14 17:19:16 -0700726 if self.sliver is None:
727 if not self.provider_service.slices.count():
Scott Bakeree0c2802015-05-06 15:46:34 -0700728 raise XOSConfigurationError("The VCPE service has no slices")
Scott Baker1b241612015-04-14 17:19:16 -0700729
Scott Bakerac60d5f2015-05-14 21:48:53 -0700730 flavors = Flavor.objects.filter(name="m1.small")
731 if not flavors:
732 raise XOSConfigurationError("No m1.small flavor")
733
Scott Baker1b241612015-04-14 17:19:16 -0700734 node =self.pick_node()
735 sliver = Sliver(slice = self.provider_service.slices.all()[0],
736 node = node,
737 image = self.image,
Scott Baker9c8a2c72015-05-05 17:49:46 -0700738 creator = self.creator,
Scott Bakerac60d5f2015-05-14 21:48:53 -0700739 deployment = node.site_deployment.deployment,
740 flavor = flavors[0])
Scott Baker1b241612015-04-14 17:19:16 -0700741 sliver.save()
742
Scott Baker39b0d892015-04-15 20:59:15 -0700743 try:
744 self.sliver = sliver
Scott Baker697fb0b2015-04-20 09:16:17 -0700745 super(VCPETenant, self).save()
Scott Baker39b0d892015-04-15 20:59:15 -0700746 except:
747 sliver.delete()
748 raise
Scott Baker1b241612015-04-14 17:19:16 -0700749
750 def cleanup_sliver(self):
751 if self.sliver:
Scott Baker361c86c2015-07-06 14:38:02 -0700752 # print "XXX cleanup sliver", self.sliver
Scott Baker1b241612015-04-14 17:19:16 -0700753 self.sliver.delete()
754 self.sliver = None
755
Scott Baker697fb0b2015-04-20 09:16:17 -0700756 def manage_vbng(self):
757 # Each vCPE object owns exactly one vBNG object
758
759 if self.deleted:
760 return
761
762 if self.vbng is None:
763 vbngServices = VBNGService.get_service_objects().all()
764 if not vbngServices:
Scott Bakerd921e1c2015-04-20 14:24:29 -0700765 raise XOSConfigurationError("No VBNG Services available")
Scott Baker697fb0b2015-04-20 09:16:17 -0700766
767 vbng = VBNGTenant(provider_service = vbngServices[0],
768 subscriber_tenant = self)
Scott Baker9c8a2c72015-05-05 17:49:46 -0700769 vbng.caller = self.creator
Scott Baker697fb0b2015-04-20 09:16:17 -0700770 vbng.save()
771
Scott Baker697fb0b2015-04-20 09:16:17 -0700772 def cleanup_vbng(self):
773 if self.vbng:
Scott Baker361c86c2015-07-06 14:38:02 -0700774 # print "XXX cleanup vnbg", self.vbng
Scott Baker697fb0b2015-04-20 09:16:17 -0700775 self.vbng.delete()
Scott Baker697fb0b2015-04-20 09:16:17 -0700776
Scott Baker5e76f802015-06-24 12:54:24 -0700777 def cleanup_orphans(self):
Scott Baker361c86c2015-07-06 14:38:02 -0700778 # ensure vCPE only has one vBNG
779 cur_vbng = self.vbng
780 for vbng in list(self.get_subscribed_tenants(VBNGTenant)):
781 if (not cur_vbng) or (vbng.id != cur_vbng.id):
782 # print "XXX clean up orphaned vbng", vbng
783 vbng.delete()
Scott Baker5e76f802015-06-24 12:54:24 -0700784
785 if self.orig_sliver_id and (self.orig_sliver_id != self.get_attribute("sliver_id")):
786 slivers=Sliver.objects.filter(id=self.orig_sliver_id)
787 if slivers:
788 # print "XXX clean up orphaned sliver", slivers[0]
789 slivers[0].delete()
790
Scott Baker5c8abf82015-05-20 20:45:11 -0700791 def manage_bbs_account(self):
792 if self.deleted:
793 return
794
Scott Bakere2570112015-05-20 20:57:28 -0700795 if self.url_filter_enable:
796 if not self.bbs_account:
797 # make sure we use the proxied VCPEService object, not the generic Service object
798 vcpe_service = VCPEService.objects.get(id=self.provider_service.id)
Scott Bakerf4f61ca2015-06-09 12:03:56 -0700799 if self.service_specific_id=="SYNCME":
800 self.bbs_account = "bbs01@onlab.us"
801 else:
802 self.bbs_account = vcpe_service.allocate_bbs_account()
Scott Bakere2570112015-05-20 20:57:28 -0700803 super(VCPETenant, self).save()
804 else:
805 if self.bbs_account:
806 self.bbs_account = None
807 super(VCPETenant, self).save()
Scott Baker5c8abf82015-05-20 20:45:11 -0700808
Scott Baker1b241612015-04-14 17:19:16 -0700809 def save(self, *args, **kwargs):
Scott Baker9c8a2c72015-05-05 17:49:46 -0700810 if not self.creator:
811 if not getattr(self, "caller", None):
812 # caller must be set when creating a vCPE since it creates a slice
Scott Bakeree0c2802015-05-06 15:46:34 -0700813 raise XOSProgrammingError("VCPETenant's self.caller was not set")
Scott Baker9c8a2c72015-05-05 17:49:46 -0700814 self.creator = self.caller
815 if not self.creator:
Scott Bakeree0c2802015-05-06 15:46:34 -0700816 raise XOSProgrammingError("VCPETenant's self.creator was not set")
Scott Baker9c8a2c72015-05-05 17:49:46 -0700817
Scott Baker1b241612015-04-14 17:19:16 -0700818 super(VCPETenant, self).save(*args, **kwargs)
Scott Baker39b0d892015-04-15 20:59:15 -0700819 self.manage_sliver()
Scott Baker697fb0b2015-04-20 09:16:17 -0700820 self.manage_vbng()
Scott Baker5c8abf82015-05-20 20:45:11 -0700821 self.manage_bbs_account()
Scott Baker5e76f802015-06-24 12:54:24 -0700822 self.cleanup_orphans()
Scott Baker1b241612015-04-14 17:19:16 -0700823
824 def delete(self, *args, **kwargs):
Scott Baker697fb0b2015-04-20 09:16:17 -0700825 self.cleanup_vbng()
Scott Baker1b241612015-04-14 17:19:16 -0700826 self.cleanup_sliver()
827 super(VCPETenant, self).delete(*args, **kwargs)
828
Scott Baker697fb0b2015-04-20 09:16:17 -0700829#----------------------------------------------------------------------------
830# vBNG
831#----------------------------------------------------------------------------
832
833class VBNGService(Service):
Scott Baker361c86c2015-07-06 14:38:02 -0700834 KIND = VBNG_KIND
Scott Baker697fb0b2015-04-20 09:16:17 -0700835
836 class Meta:
837 app_label = "cord"
838 verbose_name = "vBNG Service"
839 proxy = True
840
841class VBNGTenant(Tenant):
842 class Meta:
843 proxy = True
844
Scott Baker361c86c2015-07-06 14:38:02 -0700845 KIND = VBNG_KIND
Scott Baker697fb0b2015-04-20 09:16:17 -0700846
Scott Baker99ff5512015-06-02 14:34:04 -0700847 default_attributes = {"routeable_subnet": "",
Scott Baker790613c2015-06-08 19:09:53 -0700848 "mapped_ip": "",
849 "mapped_mac": "",
850 "mapped_hostname": ""}
Scott Baker697fb0b2015-04-20 09:16:17 -0700851
852 @property
853 def routeable_subnet(self):
854 return self.get_attribute("routeable_subnet", self.default_attributes["routeable_subnet"])
855
856 @routeable_subnet.setter
857 def routeable_subnet(self, value):
858 self.set_attribute("routeable_subnet", value)
Scott Baker99ff5512015-06-02 14:34:04 -0700859
860 @property
861 def mapped_ip(self):
862 return self.get_attribute("mapped_ip", self.default_attributes["mapped_ip"])
863
864 @mapped_ip.setter
865 def mapped_ip(self, value):
866 self.set_attribute("mapped_ip", value)
Scott Baker790613c2015-06-08 19:09:53 -0700867
868 @property
869 def mapped_mac(self):
870 return self.get_attribute("mapped_mac", self.default_attributes["mapped_mac"])
871
872 @mapped_mac.setter
873 def mapped_mac(self, value):
874 self.set_attribute("mapped_mac", value)
875
876 @property
877 def mapped_hostname(self):
878 return self.get_attribute("mapped_hostname", self.default_attributes["mapped_hostname"])
879
880 @mapped_hostname.setter
881 def mapped_hostname(self, value):
882 self.set_attribute("mapped_hostname", value)