blob: 01b2de9586d53408509c6d1e30cdc38f3f7b132a [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
Scott Baker1027cd62015-07-08 19:01:56 -07005from django.db import models, transaction
Scott Baker1b241612015-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 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,
Scott Bakerdb66fd32015-07-07 17:59:44 -070074 "users": [],
75 "is_demo_user": False }
Scott Bakerf08823d2015-07-06 16:50:30 -070076
Scott Baker7c7b6312015-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 Bakerf08823d2015-07-06 16:50:30 -070083 def __init__(self, *args, **kwargs):
84 super(CordSubscriberRoot, self).__init__(*args, **kwargs)
85 self.cached_volt = None
Scott Baker7c7b6312015-07-07 12:15:03 -070086 self._initial_url_filter_enable = self.url_filter_enable
Scott Bakerf08823d2015-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 Bakerdb66fd32015-07-07 17:59:44 -070096 return self.cached_volt
Scott Bakerf08823d2015-07-06 16:50:30 -070097
Scott Bakercd349182015-07-06 17:21:21 -070098 #volt.caller = self.creator
Scott Bakerf08823d2015-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 Baker361c86c2015-07-06 14:38:02 -0700220
Scott Baker7c7b6312015-07-07 12:15:03 -0700221 def save(self, *args, **kwargs):
222 super(CordSubscriberRoot, self).save(*args, **kwargs)
223 if (self.volt) and (self.volt.vcpe): # and (self._initial_url_filter_enabled != self.url_filter_enable):
224 # 1) trigger manage_bbs_account to run
225 # 2) trigger vcpe observer to wake up
226 self.volt.vcpe.save()
227
Scott Bakerdb66fd32015-07-07 17:59:44 -0700228 @property
229 def is_demo_user(self):
230 return self.get_attribute("is_demo_user", self.default_attributes["is_demo_user"])
231
232 @is_demo_user.setter
233 def is_demo_user(self, value):
234 self.set_attribute("is_demo_user", value)
235
Scott Baker39b0d892015-04-15 20:59:15 -0700236# -------------------------------------------
237# VOLT
238# -------------------------------------------
239
240class VOLTService(Service):
Scott Baker361c86c2015-07-06 14:38:02 -0700241 KIND = VOLT_KIND
Scott Baker39b0d892015-04-15 20:59:15 -0700242
Scott Baker1b241612015-04-14 17:19:16 -0700243 class Meta:
Scott Baker39b0d892015-04-15 20:59:15 -0700244 app_label = "cord"
245 verbose_name = "vOLT Service"
246 proxy = True
247
248class VOLTTenant(Tenant):
249 class Meta:
250 proxy = True
251
Scott Baker361c86c2015-07-06 14:38:02 -0700252 KIND = VOLT_KIND
Scott Baker39b0d892015-04-15 20:59:15 -0700253
Scott Bakerdb66fd32015-07-07 17:59:44 -0700254 default_attributes = {"vlan_id": None, }
Scott Baker557aada2015-04-20 09:48:34 -0700255 def __init__(self, *args, **kwargs):
256 volt_services = VOLTService.get_service_objects().all()
257 if volt_services:
258 self._meta.get_field("provider_service").default = volt_services[0].id
259 super(VOLTTenant, self).__init__(*args, **kwargs)
Scott Baker361c86c2015-07-06 14:38:02 -0700260 self.cached_vcpe = None
Scott Baker5e76f802015-06-24 12:54:24 -0700261
Scott Baker39b0d892015-04-15 20:59:15 -0700262 @property
Scott Bakere744c7b2015-04-20 11:50:09 -0700263 def vlan_id(self):
264 return self.get_attribute("vlan_id", self.default_attributes["vlan_id"])
265
266 @vlan_id.setter
267 def vlan_id(self, value):
268 self.set_attribute("vlan_id", value)
269
270 @property
Scott Baker39b0d892015-04-15 20:59:15 -0700271 def vcpe(self):
Scott Baker361c86c2015-07-06 14:38:02 -0700272 vcpe = self.get_newest_subscribed_tenant(VCPETenant)
273 if not vcpe:
274 return None
275
276 # always return the same object when possible
277 if (self.cached_vcpe) and (self.cached_vcpe.id == vcpe.id):
Scott Baker697fb0b2015-04-20 09:16:17 -0700278 return self.cached_vcpe
Scott Baker361c86c2015-07-06 14:38:02 -0700279
Scott Baker9c8a2c72015-05-05 17:49:46 -0700280 vcpe.caller = self.creator
Scott Baker697fb0b2015-04-20 09:16:17 -0700281 self.cached_vcpe = vcpe
282 return vcpe
Scott Baker39b0d892015-04-15 20:59:15 -0700283
284 @vcpe.setter
285 def vcpe(self, value):
Scott Bakercd349182015-07-06 17:21:21 -0700286 raise XOSConfigurationError("vOLT.vCPE cannot be set this way -- create a new vCPE object and set its subscriber_tenant instead")
287
288 @property
289 def subscriber(self):
290 if not self.subscriber_root:
291 return None
292 subs = CordSubscriberRoot.objects.filter(id=self.subscriber_root.id)
293 if not subs:
294 return None
295 return subs[0]
Scott Baker39b0d892015-04-15 20:59:15 -0700296
Scott Baker9c8a2c72015-05-05 17:49:46 -0700297 @property
298 def creator(self):
299 if getattr(self, "cached_creator", None):
300 return self.cached_creator
301 creator_id=self.get_attribute("creator_id")
302 if not creator_id:
303 return None
304 users=User.objects.filter(id=creator_id)
305 if not users:
306 return None
307 user=users[0]
308 self.cached_creator = users[0]
309 return user
310
311 @creator.setter
312 def creator(self, value):
313 if value:
314 value = value.id
315 if (value != self.get_attribute("creator_id", None)):
316 self.cached_creator=None
317 self.set_attribute("creator_id", value)
318
Scott Baker39b0d892015-04-15 20:59:15 -0700319 def manage_vcpe(self):
320 # Each VOLT object owns exactly one VCPE object
321
322 if self.deleted:
323 return
324
325 if self.vcpe is None:
326 vcpeServices = VCPEService.get_service_objects().all()
327 if not vcpeServices:
Scott Bakerd921e1c2015-04-20 14:24:29 -0700328 raise XOSConfigurationError("No VCPE Services available")
Scott Baker39b0d892015-04-15 20:59:15 -0700329
330 vcpe = VCPETenant(provider_service = vcpeServices[0],
331 subscriber_tenant = self)
Scott Baker9c8a2c72015-05-05 17:49:46 -0700332 vcpe.caller = self.creator
Scott Baker39b0d892015-04-15 20:59:15 -0700333 vcpe.save()
334
Scott Baker7c7b6312015-07-07 12:15:03 -0700335 def manage_subscriber(self):
336 if (self.subscriber_root is None):
337 # The vOLT is not connected to a Subscriber, so either find an
338 # existing subscriber with the same SSID, or autogenerate a new
339 # subscriber.
340 #
341 # TODO: This probably goes away when we rethink the ONOS-to-XOS
342 # vOLT API.
343
344 subs = CordSubscriberRoot.get_tenant_objects().filter(service_specific_id = self.service_specific_id)
345 if subs:
346 sub = subs[0]
347 else:
348 sub = CordSubscriberRoot(service_specific_id = self.service_specific_id,
349 name = "autogenerated-for-vOLT-%s" % self.id)
350 sub.save()
351 self.subscriber_root = sub
352 self.save()
353
Scott Baker39b0d892015-04-15 20:59:15 -0700354 def cleanup_vcpe(self):
355 if self.vcpe:
Scott Baker361c86c2015-07-06 14:38:02 -0700356 # print "XXX cleanup vcpe", self.vcpe
Scott Baker39b0d892015-04-15 20:59:15 -0700357 self.vcpe.delete()
Scott Baker39b0d892015-04-15 20:59:15 -0700358
Scott Baker5e76f802015-06-24 12:54:24 -0700359 def cleanup_orphans(self):
Scott Baker361c86c2015-07-06 14:38:02 -0700360 # ensure vOLT only has one vCPE
361 cur_vcpe = self.vcpe
362 for vcpe in list(self.get_subscribed_tenants(VCPETenant)):
363 if (not cur_vcpe) or (vcpe.id != cur_vcpe.id):
364 # print "XXX clean up orphaned vcpe", vcpe
365 vcpe.delete()
Scott Baker5e76f802015-06-24 12:54:24 -0700366
Scott Baker39b0d892015-04-15 20:59:15 -0700367 def save(self, *args, **kwargs):
Scott Bakerd921e1c2015-04-20 14:24:29 -0700368 self.validate_unique_service_specific_id()
369
Scott Baker7c7b6312015-07-07 12:15:03 -0700370 if (self.subscriber_root is not None):
371 subs = self.subscriber_root.get_subscribed_tenants(VOLTTenant)
372 if (subs) and (self not in subs):
373 raise XOSDuplicateKey("Subscriber should only be linked to one vOLT")
374
Scott Baker9c8a2c72015-05-05 17:49:46 -0700375 if not self.creator:
376 if not getattr(self, "caller", None):
377 # caller must be set when creating a vCPE since it creates a slice
378 raise XOSProgrammingError("VOLTTenant's self.caller was not set")
379 self.creator = self.caller
380 if not self.creator:
381 raise XOSProgrammingError("VOLTTenant's self.creator was not set")
382
Scott Baker39b0d892015-04-15 20:59:15 -0700383 super(VOLTTenant, self).save(*args, **kwargs)
Scott Baker1027cd62015-07-08 19:01:56 -0700384 model_policy_volt(self.pk)
385 #self.manage_vcpe()
386 #self.manage_subscriber()
387 #self.cleanup_orphans()
Scott Baker39b0d892015-04-15 20:59:15 -0700388
389 def delete(self, *args, **kwargs):
390 self.cleanup_vcpe()
391 super(VOLTTenant, self).delete(*args, **kwargs)
392
Scott Baker1027cd62015-07-08 19:01:56 -0700393def model_policy_volt(pk):
394 # TODO: this should be made in to a real model_policy
395 with transaction.atomic():
396 volt = VOLTTenant.objects.select_for_update().filter(pk=pk)
397 if not volt:
398 return
399 volt = volt[0]
400 volt.manage_vcpe()
401 volt.manage_subscriber()
402 volt.cleanup_orphans()
403
Scott Baker39b0d892015-04-15 20:59:15 -0700404# -------------------------------------------
405# VCPE
406# -------------------------------------------
407
408class VCPEService(Service):
Scott Baker361c86c2015-07-06 14:38:02 -0700409 KIND = VCPE_KIND
Scott Baker39b0d892015-04-15 20:59:15 -0700410
Scott Baker7ba272e2015-07-13 14:30:25 -0700411 simple_attributes = ( ("bbs_url", None),
Scott Baker3d2493b2015-07-15 17:42:43 -0700412 ("bbs_server", None),
Scott Bakercec6a702015-07-15 18:04:22 -0700413 ("backend_network_label", "hpc_client"), )
Scott Baker7ba272e2015-07-13 14:30:25 -0700414
415 def __init__(self, *args, **kwargs):
416 super(VCPEService, self).__init__(*args, **kwargs)
417
Scott Baker39b0d892015-04-15 20:59:15 -0700418 class Meta:
419 app_label = "cord"
Scott Baker1b241612015-04-14 17:19:16 -0700420 verbose_name = "vCPE Service"
Scott Baker39b0d892015-04-15 20:59:15 -0700421 proxy = True
Scott Baker1b241612015-04-14 17:19:16 -0700422
Scott Baker5c8abf82015-05-20 20:45:11 -0700423 def allocate_bbs_account(self):
424 vcpes = VCPETenant.get_tenant_objects().all()
425 bbs_accounts = [vcpe.bbs_account for vcpe in vcpes]
426
427 # There's a bit of a race here; some other user could be trying to
428 # allocate a bbs_account at the same time we are.
429
Scott Bakerf4f61ca2015-06-09 12:03:56 -0700430 for i in range(2,21):
Scott Baker5c8abf82015-05-20 20:45:11 -0700431 account_name = "bbs%02d@onlab.us" % i
432 if (account_name not in bbs_accounts):
433 return account_name
434
435 raise XOSConfigurationError("We've run out of available broadbandshield accounts. Delete some vcpe and try again.")
436
Scott Baker3d2493b2015-07-15 17:42:43 -0700437 @property
438 def bbs_slice(self):
439 bbs_slice_id=self.get_attribute("bbs_slice_id")
440 if not bbs_slice_id:
441 return None
442 bbs_slices=Slice.objects.filter(id=bbs_slice_id)
443 if not bbs_slices:
444 return None
445 return bbs_slices[0]
446
447 @bbs_slice.setter
448 def bbs_slice(self, value):
449 if value:
450 value = value.id
451 self.set_attribute("bbs_slice_id", value)
452
Scott Baker7ba272e2015-07-13 14:30:25 -0700453VCPEService.setup_simple_attributes()
454
455
Scott Baker1b241612015-04-14 17:19:16 -0700456class VCPETenant(Tenant):
457 class Meta:
458 proxy = True
459
Scott Baker361c86c2015-07-06 14:38:02 -0700460 KIND = VCPE_KIND
Scott Baker39b0d892015-04-15 20:59:15 -0700461
Scott Bakerdb66fd32015-07-07 17:59:44 -0700462 sync_attributes = ("nat_ip",
Scott Bakerc7a96c82015-05-20 08:41:38 -0700463 "lan_ip",
464 "wan_ip",
Scott Baker710ad052015-06-04 10:26:44 -0700465 "private_ip",
Scott Baker3f4fe402015-06-05 12:08:34 -0700466 "hpc_client_ip",
467 "wan_mac")
Scott Baker9c8a2c72015-05-05 17:49:46 -0700468
Scott Bakerdb66fd32015-07-07 17:59:44 -0700469 default_attributes = {"sliver_id": None,
Scott Baker5c8abf82015-05-20 20:45:11 -0700470 "users": [],
Scott Bakerd40a42d2015-06-09 12:22:29 -0700471 "bbs_account": None,
472 "last_ansible_hash": None}
Scott Baker1b241612015-04-14 17:19:16 -0700473
Scott Baker697fb0b2015-04-20 09:16:17 -0700474 def __init__(self, *args, **kwargs):
475 super(VCPETenant, self).__init__(*args, **kwargs)
476 self.cached_vbng=None
477 self.cached_sliver=None
Scott Baker5e76f802015-06-24 12:54:24 -0700478 self.orig_sliver_id = self.get_initial_attribute("sliver_id")
Scott Baker697fb0b2015-04-20 09:16:17 -0700479
Scott Baker1b241612015-04-14 17:19:16 -0700480 @property
481 def image(self):
Scott Baker1027cd62015-07-08 19:01:56 -0700482 LOOK_FOR_IMAGES=["ubuntu-vcpe4", # ONOS demo machine -- preferred vcpe image
Scott Baker2c4f1eb2015-06-02 16:03:30 -0700483 "Ubuntu 14.04 LTS", # portal
Scott Baker4f751bd2015-04-20 20:12:59 -0700484 "Ubuntu-14.04-LTS", # ONOS demo machine
485 ]
486 for image_name in LOOK_FOR_IMAGES:
487 images = Image.objects.filter(name = image_name)
488 if images:
489 return images[0]
490
491 raise XOSProgrammingError("No VPCE image (looked for %s)" % str(LOOK_FOR_IMAGES))
Scott Baker1b241612015-04-14 17:19:16 -0700492
493 @property
494 def sliver(self):
Scott Baker697fb0b2015-04-20 09:16:17 -0700495 if getattr(self, "cached_sliver", None):
496 return self.cached_sliver
Scott Baker1b241612015-04-14 17:19:16 -0700497 sliver_id=self.get_attribute("sliver_id")
498 if not sliver_id:
499 return None
500 slivers=Sliver.objects.filter(id=sliver_id)
501 if not slivers:
502 return None
Scott Baker697fb0b2015-04-20 09:16:17 -0700503 sliver=slivers[0]
Scott Baker9c8a2c72015-05-05 17:49:46 -0700504 sliver.caller = self.creator
Scott Baker697fb0b2015-04-20 09:16:17 -0700505 self.cached_sliver = sliver
506 return sliver
Scott Baker1b241612015-04-14 17:19:16 -0700507
508 @sliver.setter
509 def sliver(self, value):
510 if value:
Scott Baker697fb0b2015-04-20 09:16:17 -0700511 value = value.id
512 if (value != self.get_attribute("sliver_id", None)):
513 self.cached_sliver=None
514 self.set_attribute("sliver_id", value)
515
516 @property
Scott Baker9c8a2c72015-05-05 17:49:46 -0700517 def creator(self):
518 if getattr(self, "cached_creator", None):
519 return self.cached_creator
520 creator_id=self.get_attribute("creator_id")
521 if not creator_id:
522 return None
523 users=User.objects.filter(id=creator_id)
524 if not users:
525 return None
526 user=users[0]
527 self.cached_creator = users[0]
528 return user
529
530 @creator.setter
531 def creator(self, value):
532 if value:
533 value = value.id
534 if (value != self.get_attribute("creator_id", None)):
535 self.cached_creator=None
536 self.set_attribute("creator_id", value)
537
538 @property
Scott Baker697fb0b2015-04-20 09:16:17 -0700539 def vbng(self):
Scott Baker361c86c2015-07-06 14:38:02 -0700540 vbng = self.get_newest_subscribed_tenant(VBNGTenant)
541 if not vbng:
542 return None
543
544 # always return the same object when possible
545 if (self.cached_vbng) and (self.cached_vbng.id == vbng.id):
Scott Baker697fb0b2015-04-20 09:16:17 -0700546 return self.cached_vbng
Scott Baker361c86c2015-07-06 14:38:02 -0700547
Scott Baker9c8a2c72015-05-05 17:49:46 -0700548 vbng.caller = self.creator
Scott Baker697fb0b2015-04-20 09:16:17 -0700549 self.cached_vbng = vbng
550 return vbng
551
552 @vbng.setter
553 def vbng(self, value):
Scott Baker361c86c2015-07-06 14:38:02 -0700554 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 -0700555
Scott Bakercd349182015-07-06 17:21:21 -0700556 @property
557 def volt(self):
558 if not self.subscriber_tenant:
559 return None
560 volts = VOLTTenant.objects.filter(id=self.subscriber_tenant.id)
561 if not volts:
562 return None
563 return volts[0]
564
Scott Bakerf08823d2015-07-06 16:50:30 -0700565 @property
566 def bbs_account(self):
567 return self.get_attribute("bbs_account", self.default_attributes["bbs_account"])
568
569 @bbs_account.setter
570 def bbs_account(self, value):
571 return self.set_attribute("bbs_account", value)
572
573 @property
574 def last_ansible_hash(self):
575 return self.get_attribute("last_ansible_hash", self.default_attributes["last_ansible_hash"])
576
577 @last_ansible_hash.setter
578 def last_ansible_hash(self, value):
579 return self.set_attribute("last_ansible_hash", value)
580
581 @property
582 def ssh_command(self):
583 if self.sliver:
584 return self.sliver.get_ssh_command()
585 else:
586 return "no-sliver"
587
588 @ssh_command.setter
589 def ssh_command(self, value):
590 pass
591
Scott Baker706bf972015-05-20 08:19:25 -0700592 @property
593 def addresses(self):
594 if not self.sliver:
595 return {}
596
597 addresses = {}
598 for ns in self.sliver.networkslivers.all():
599 if "lan" in ns.network.name.lower():
600 addresses["lan"] = ns.ip
601 elif "wan" in ns.network.name.lower():
602 addresses["wan"] = ns.ip
603 elif "private" in ns.network.name.lower():
604 addresses["private"] = ns.ip
605 elif "nat" in ns.network.name.lower():
606 addresses["nat"] = ns.ip
Scott Baker710ad052015-06-04 10:26:44 -0700607 elif "hpc_client" in ns.network.name.lower():
608 addresses["hpc_client"] = ns.ip
Scott Baker706bf972015-05-20 08:19:25 -0700609 return addresses
610
Scott Bakera6a7e032015-05-20 08:25:29 -0700611 @property
612 def nat_ip(self):
613 return self.addresses.get("nat",None)
614
615 @property
616 def lan_ip(self):
617 return self.addresses.get("lan",None)
618
619 @property
620 def wan_ip(self):
621 return self.addresses.get("wan",None)
622
623 @property
Scott Baker3f4fe402015-06-05 12:08:34 -0700624 def wan_mac(self):
625 ip = self.wan_ip
626 if not ip:
627 return None
628 try:
629 (a,b,c,d) = ip.split('.')
630 wan_mac = "02:42:%2x:%2x:%2x:%2x" % (int(a), int(b), int(c), int(d))
631 except:
632 wan_mac = "Exception"
633 return wan_mac
634
635 @property
Scott Bakera6a7e032015-05-20 08:25:29 -0700636 def private_ip(self):
637 return self.addresses.get("private",None)
638
Scott Baker710ad052015-06-04 10:26:44 -0700639 @property
640 def hpc_client_ip(self):
641 return self.addresses.get("hpc_client",None)
642
Scott Baker7bbdd2f2015-06-09 12:30:30 -0700643 @property
644 def is_synced(self):
645 return (self.enacted is not None) and (self.enacted >= self.updated)
646
647 @is_synced.setter
648 def is_synced(self, value):
649 pass
650
Scott Baker1b241612015-04-14 17:19:16 -0700651 def pick_node(self):
652 nodes = list(Node.objects.all())
653 # TODO: logic to filter nodes by which nodes are up, and which
654 # nodes the slice can instantiate on.
655 nodes = sorted(nodes, key=lambda node: node.slivers.all().count())
656 return nodes[0]
657
658 def manage_sliver(self):
Scott Baker39b0d892015-04-15 20:59:15 -0700659 # Each VCPE object owns exactly one sliver.
660
Scott Baker1b241612015-04-14 17:19:16 -0700661 if self.deleted:
662 return
663
Scott Baker1b241612015-04-14 17:19:16 -0700664 if (self.sliver is not None) and (self.sliver.image != self.image):
665 self.sliver.delete()
666 self.sliver = None
Scott Baker9c8a2c72015-05-05 17:49:46 -0700667
Scott Baker1b241612015-04-14 17:19:16 -0700668 if self.sliver is None:
669 if not self.provider_service.slices.count():
Scott Bakeree0c2802015-05-06 15:46:34 -0700670 raise XOSConfigurationError("The VCPE service has no slices")
Scott Baker1b241612015-04-14 17:19:16 -0700671
Scott Bakerac60d5f2015-05-14 21:48:53 -0700672 flavors = Flavor.objects.filter(name="m1.small")
673 if not flavors:
674 raise XOSConfigurationError("No m1.small flavor")
675
Scott Baker1b241612015-04-14 17:19:16 -0700676 node =self.pick_node()
677 sliver = Sliver(slice = self.provider_service.slices.all()[0],
678 node = node,
679 image = self.image,
Scott Baker9c8a2c72015-05-05 17:49:46 -0700680 creator = self.creator,
Scott Bakerac60d5f2015-05-14 21:48:53 -0700681 deployment = node.site_deployment.deployment,
682 flavor = flavors[0])
Scott Baker1b241612015-04-14 17:19:16 -0700683 sliver.save()
684
Scott Baker39b0d892015-04-15 20:59:15 -0700685 try:
686 self.sliver = sliver
Scott Baker697fb0b2015-04-20 09:16:17 -0700687 super(VCPETenant, self).save()
Scott Baker39b0d892015-04-15 20:59:15 -0700688 except:
689 sliver.delete()
690 raise
Scott Baker1b241612015-04-14 17:19:16 -0700691
692 def cleanup_sliver(self):
693 if self.sliver:
Scott Baker361c86c2015-07-06 14:38:02 -0700694 # print "XXX cleanup sliver", self.sliver
Scott Baker1b241612015-04-14 17:19:16 -0700695 self.sliver.delete()
696 self.sliver = None
697
Scott Baker697fb0b2015-04-20 09:16:17 -0700698 def manage_vbng(self):
699 # Each vCPE object owns exactly one vBNG object
700
701 if self.deleted:
702 return
703
704 if self.vbng is None:
705 vbngServices = VBNGService.get_service_objects().all()
706 if not vbngServices:
Scott Bakerd921e1c2015-04-20 14:24:29 -0700707 raise XOSConfigurationError("No VBNG Services available")
Scott Baker697fb0b2015-04-20 09:16:17 -0700708
709 vbng = VBNGTenant(provider_service = vbngServices[0],
710 subscriber_tenant = self)
Scott Baker9c8a2c72015-05-05 17:49:46 -0700711 vbng.caller = self.creator
Scott Baker697fb0b2015-04-20 09:16:17 -0700712 vbng.save()
713
Scott Baker697fb0b2015-04-20 09:16:17 -0700714 def cleanup_vbng(self):
715 if self.vbng:
Scott Baker361c86c2015-07-06 14:38:02 -0700716 # print "XXX cleanup vnbg", self.vbng
Scott Baker697fb0b2015-04-20 09:16:17 -0700717 self.vbng.delete()
Scott Baker697fb0b2015-04-20 09:16:17 -0700718
Scott Baker5e76f802015-06-24 12:54:24 -0700719 def cleanup_orphans(self):
Scott Baker361c86c2015-07-06 14:38:02 -0700720 # ensure vCPE only has one vBNG
721 cur_vbng = self.vbng
722 for vbng in list(self.get_subscribed_tenants(VBNGTenant)):
723 if (not cur_vbng) or (vbng.id != cur_vbng.id):
724 # print "XXX clean up orphaned vbng", vbng
725 vbng.delete()
Scott Baker5e76f802015-06-24 12:54:24 -0700726
727 if self.orig_sliver_id and (self.orig_sliver_id != self.get_attribute("sliver_id")):
728 slivers=Sliver.objects.filter(id=self.orig_sliver_id)
729 if slivers:
730 # print "XXX clean up orphaned sliver", slivers[0]
731 slivers[0].delete()
732
Scott Baker5c8abf82015-05-20 20:45:11 -0700733 def manage_bbs_account(self):
734 if self.deleted:
735 return
736
Scott Bakerdb66fd32015-07-07 17:59:44 -0700737 if self.volt and self.volt.subscriber and self.volt.subscriber.url_filter_enable:
Scott Bakere2570112015-05-20 20:57:28 -0700738 if not self.bbs_account:
739 # make sure we use the proxied VCPEService object, not the generic Service object
740 vcpe_service = VCPEService.objects.get(id=self.provider_service.id)
Scott Baker7c7b6312015-07-07 12:15:03 -0700741 self.bbs_account = vcpe_service.allocate_bbs_account()
Scott Bakere2570112015-05-20 20:57:28 -0700742 super(VCPETenant, self).save()
743 else:
744 if self.bbs_account:
745 self.bbs_account = None
746 super(VCPETenant, self).save()
Scott Baker5c8abf82015-05-20 20:45:11 -0700747
Scott Baker1b241612015-04-14 17:19:16 -0700748 def save(self, *args, **kwargs):
Scott Baker9c8a2c72015-05-05 17:49:46 -0700749 if not self.creator:
750 if not getattr(self, "caller", None):
751 # caller must be set when creating a vCPE since it creates a slice
Scott Bakeree0c2802015-05-06 15:46:34 -0700752 raise XOSProgrammingError("VCPETenant's self.caller was not set")
Scott Baker9c8a2c72015-05-05 17:49:46 -0700753 self.creator = self.caller
754 if not self.creator:
Scott Bakeree0c2802015-05-06 15:46:34 -0700755 raise XOSProgrammingError("VCPETenant's self.creator was not set")
Scott Baker9c8a2c72015-05-05 17:49:46 -0700756
Scott Baker1b241612015-04-14 17:19:16 -0700757 super(VCPETenant, self).save(*args, **kwargs)
Scott Baker1027cd62015-07-08 19:01:56 -0700758 model_policy_vcpe(self.pk)
759 #self.manage_sliver()
760 #self.manage_vbng()
761 #self.manage_bbs_account()
762 #self.cleanup_orphans()
Scott Baker1b241612015-04-14 17:19:16 -0700763
764 def delete(self, *args, **kwargs):
Scott Baker697fb0b2015-04-20 09:16:17 -0700765 self.cleanup_vbng()
Scott Baker1b241612015-04-14 17:19:16 -0700766 self.cleanup_sliver()
767 super(VCPETenant, self).delete(*args, **kwargs)
768
Scott Baker1027cd62015-07-08 19:01:56 -0700769def model_policy_vcpe(pk):
770 # TODO: this should be made in to a real model_policy
771 with transaction.atomic():
772 vcpe = VCPETenant.objects.select_for_update().filter(pk=pk)
773 if not vcpe:
774 return
775 vcpe = vcpe[0]
776 vcpe.manage_sliver()
777 vcpe.manage_vbng()
778 vcpe.manage_bbs_account()
779 vcpe.cleanup_orphans()
780
Scott Baker697fb0b2015-04-20 09:16:17 -0700781#----------------------------------------------------------------------------
782# vBNG
783#----------------------------------------------------------------------------
784
785class VBNGService(Service):
Scott Baker361c86c2015-07-06 14:38:02 -0700786 KIND = VBNG_KIND
Scott Baker697fb0b2015-04-20 09:16:17 -0700787
788 class Meta:
789 app_label = "cord"
790 verbose_name = "vBNG Service"
791 proxy = True
792
793class VBNGTenant(Tenant):
794 class Meta:
795 proxy = True
796
Scott Baker361c86c2015-07-06 14:38:02 -0700797 KIND = VBNG_KIND
Scott Baker697fb0b2015-04-20 09:16:17 -0700798
Scott Baker99ff5512015-06-02 14:34:04 -0700799 default_attributes = {"routeable_subnet": "",
Scott Baker790613c2015-06-08 19:09:53 -0700800 "mapped_ip": "",
801 "mapped_mac": "",
802 "mapped_hostname": ""}
Scott Baker697fb0b2015-04-20 09:16:17 -0700803
804 @property
805 def routeable_subnet(self):
806 return self.get_attribute("routeable_subnet", self.default_attributes["routeable_subnet"])
807
808 @routeable_subnet.setter
809 def routeable_subnet(self, value):
810 self.set_attribute("routeable_subnet", value)
Scott Baker99ff5512015-06-02 14:34:04 -0700811
812 @property
813 def mapped_ip(self):
814 return self.get_attribute("mapped_ip", self.default_attributes["mapped_ip"])
815
816 @mapped_ip.setter
817 def mapped_ip(self, value):
818 self.set_attribute("mapped_ip", value)
Scott Baker790613c2015-06-08 19:09:53 -0700819
820 @property
821 def mapped_mac(self):
822 return self.get_attribute("mapped_mac", self.default_attributes["mapped_mac"])
823
824 @mapped_mac.setter
825 def mapped_mac(self, value):
826 self.set_attribute("mapped_mac", value)
827
828 @property
829 def mapped_hostname(self):
830 return self.get_attribute("mapped_hostname", self.default_attributes["mapped_hostname"])
831
832 @mapped_hostname.setter
833 def mapped_hostname(self, value):
834 self.set_attribute("mapped_hostname", value)