blob: 7eb82892aaae218b287dd97f435e19fb8f340c11 [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 Bakera0886fb2015-07-15 18:08:06 -0700411 simple_attributes = ( ("bbs_api_hostname", None),
412 ("bbs_api_port", None),
Scott Baker3d2493b2015-07-15 17:42:43 -0700413 ("bbs_server", None),
Scott Bakercec6a702015-07-15 18:04:22 -0700414 ("backend_network_label", "hpc_client"), )
Scott Baker7ba272e2015-07-13 14:30:25 -0700415
416 def __init__(self, *args, **kwargs):
417 super(VCPEService, self).__init__(*args, **kwargs)
418
Scott Baker39b0d892015-04-15 20:59:15 -0700419 class Meta:
420 app_label = "cord"
Scott Baker1b241612015-04-14 17:19:16 -0700421 verbose_name = "vCPE Service"
Scott Baker39b0d892015-04-15 20:59:15 -0700422 proxy = True
Scott Baker1b241612015-04-14 17:19:16 -0700423
Scott Baker5c8abf82015-05-20 20:45:11 -0700424 def allocate_bbs_account(self):
425 vcpes = VCPETenant.get_tenant_objects().all()
426 bbs_accounts = [vcpe.bbs_account for vcpe in vcpes]
427
428 # There's a bit of a race here; some other user could be trying to
429 # allocate a bbs_account at the same time we are.
430
Scott Bakerf4f61ca2015-06-09 12:03:56 -0700431 for i in range(2,21):
Scott Baker5c8abf82015-05-20 20:45:11 -0700432 account_name = "bbs%02d@onlab.us" % i
433 if (account_name not in bbs_accounts):
434 return account_name
435
436 raise XOSConfigurationError("We've run out of available broadbandshield accounts. Delete some vcpe and try again.")
437
Scott Baker3d2493b2015-07-15 17:42:43 -0700438 @property
439 def bbs_slice(self):
440 bbs_slice_id=self.get_attribute("bbs_slice_id")
441 if not bbs_slice_id:
442 return None
443 bbs_slices=Slice.objects.filter(id=bbs_slice_id)
444 if not bbs_slices:
445 return None
446 return bbs_slices[0]
447
448 @bbs_slice.setter
449 def bbs_slice(self, value):
450 if value:
451 value = value.id
452 self.set_attribute("bbs_slice_id", value)
453
Scott Baker7ba272e2015-07-13 14:30:25 -0700454VCPEService.setup_simple_attributes()
455
456
Scott Baker1b241612015-04-14 17:19:16 -0700457class VCPETenant(Tenant):
458 class Meta:
459 proxy = True
460
Scott Baker361c86c2015-07-06 14:38:02 -0700461 KIND = VCPE_KIND
Scott Baker39b0d892015-04-15 20:59:15 -0700462
Scott Bakerdb66fd32015-07-07 17:59:44 -0700463 sync_attributes = ("nat_ip",
Scott Bakerc7a96c82015-05-20 08:41:38 -0700464 "lan_ip",
465 "wan_ip",
Scott Baker710ad052015-06-04 10:26:44 -0700466 "private_ip",
Scott Baker3f4fe402015-06-05 12:08:34 -0700467 "hpc_client_ip",
468 "wan_mac")
Scott Baker9c8a2c72015-05-05 17:49:46 -0700469
Scott Bakerdb66fd32015-07-07 17:59:44 -0700470 default_attributes = {"sliver_id": None,
Scott Baker5c8abf82015-05-20 20:45:11 -0700471 "users": [],
Scott Bakerd40a42d2015-06-09 12:22:29 -0700472 "bbs_account": None,
473 "last_ansible_hash": None}
Scott Baker1b241612015-04-14 17:19:16 -0700474
Scott Baker697fb0b2015-04-20 09:16:17 -0700475 def __init__(self, *args, **kwargs):
476 super(VCPETenant, self).__init__(*args, **kwargs)
477 self.cached_vbng=None
478 self.cached_sliver=None
Scott Baker5e76f802015-06-24 12:54:24 -0700479 self.orig_sliver_id = self.get_initial_attribute("sliver_id")
Scott Baker697fb0b2015-04-20 09:16:17 -0700480
Scott Baker1b241612015-04-14 17:19:16 -0700481 @property
482 def image(self):
Scott Baker1027cd62015-07-08 19:01:56 -0700483 LOOK_FOR_IMAGES=["ubuntu-vcpe4", # ONOS demo machine -- preferred vcpe image
Scott Baker2c4f1eb2015-06-02 16:03:30 -0700484 "Ubuntu 14.04 LTS", # portal
Scott Baker4f751bd2015-04-20 20:12:59 -0700485 "Ubuntu-14.04-LTS", # ONOS demo machine
486 ]
487 for image_name in LOOK_FOR_IMAGES:
488 images = Image.objects.filter(name = image_name)
489 if images:
490 return images[0]
491
492 raise XOSProgrammingError("No VPCE image (looked for %s)" % str(LOOK_FOR_IMAGES))
Scott Baker1b241612015-04-14 17:19:16 -0700493
494 @property
495 def sliver(self):
Scott Baker697fb0b2015-04-20 09:16:17 -0700496 if getattr(self, "cached_sliver", None):
497 return self.cached_sliver
Scott Baker1b241612015-04-14 17:19:16 -0700498 sliver_id=self.get_attribute("sliver_id")
499 if not sliver_id:
500 return None
501 slivers=Sliver.objects.filter(id=sliver_id)
502 if not slivers:
503 return None
Scott Baker697fb0b2015-04-20 09:16:17 -0700504 sliver=slivers[0]
Scott Baker9c8a2c72015-05-05 17:49:46 -0700505 sliver.caller = self.creator
Scott Baker697fb0b2015-04-20 09:16:17 -0700506 self.cached_sliver = sliver
507 return sliver
Scott Baker1b241612015-04-14 17:19:16 -0700508
509 @sliver.setter
510 def sliver(self, value):
511 if value:
Scott Baker697fb0b2015-04-20 09:16:17 -0700512 value = value.id
513 if (value != self.get_attribute("sliver_id", None)):
514 self.cached_sliver=None
515 self.set_attribute("sliver_id", value)
516
517 @property
Scott Baker9c8a2c72015-05-05 17:49:46 -0700518 def creator(self):
519 if getattr(self, "cached_creator", None):
520 return self.cached_creator
521 creator_id=self.get_attribute("creator_id")
522 if not creator_id:
523 return None
524 users=User.objects.filter(id=creator_id)
525 if not users:
526 return None
527 user=users[0]
528 self.cached_creator = users[0]
529 return user
530
531 @creator.setter
532 def creator(self, value):
533 if value:
534 value = value.id
535 if (value != self.get_attribute("creator_id", None)):
536 self.cached_creator=None
537 self.set_attribute("creator_id", value)
538
539 @property
Scott Baker697fb0b2015-04-20 09:16:17 -0700540 def vbng(self):
Scott Baker361c86c2015-07-06 14:38:02 -0700541 vbng = self.get_newest_subscribed_tenant(VBNGTenant)
542 if not vbng:
543 return None
544
545 # always return the same object when possible
546 if (self.cached_vbng) and (self.cached_vbng.id == vbng.id):
Scott Baker697fb0b2015-04-20 09:16:17 -0700547 return self.cached_vbng
Scott Baker361c86c2015-07-06 14:38:02 -0700548
Scott Baker9c8a2c72015-05-05 17:49:46 -0700549 vbng.caller = self.creator
Scott Baker697fb0b2015-04-20 09:16:17 -0700550 self.cached_vbng = vbng
551 return vbng
552
553 @vbng.setter
554 def vbng(self, value):
Scott Baker361c86c2015-07-06 14:38:02 -0700555 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 -0700556
Scott Bakercd349182015-07-06 17:21:21 -0700557 @property
558 def volt(self):
559 if not self.subscriber_tenant:
560 return None
561 volts = VOLTTenant.objects.filter(id=self.subscriber_tenant.id)
562 if not volts:
563 return None
564 return volts[0]
565
Scott Bakerf08823d2015-07-06 16:50:30 -0700566 @property
567 def bbs_account(self):
568 return self.get_attribute("bbs_account", self.default_attributes["bbs_account"])
569
570 @bbs_account.setter
571 def bbs_account(self, value):
572 return self.set_attribute("bbs_account", value)
573
574 @property
575 def last_ansible_hash(self):
576 return self.get_attribute("last_ansible_hash", self.default_attributes["last_ansible_hash"])
577
578 @last_ansible_hash.setter
579 def last_ansible_hash(self, value):
580 return self.set_attribute("last_ansible_hash", value)
581
582 @property
583 def ssh_command(self):
584 if self.sliver:
585 return self.sliver.get_ssh_command()
586 else:
587 return "no-sliver"
588
589 @ssh_command.setter
590 def ssh_command(self, value):
591 pass
592
Scott Baker706bf972015-05-20 08:19:25 -0700593 @property
594 def addresses(self):
595 if not self.sliver:
596 return {}
597
598 addresses = {}
599 for ns in self.sliver.networkslivers.all():
600 if "lan" in ns.network.name.lower():
601 addresses["lan"] = ns.ip
602 elif "wan" in ns.network.name.lower():
603 addresses["wan"] = ns.ip
604 elif "private" in ns.network.name.lower():
605 addresses["private"] = ns.ip
606 elif "nat" in ns.network.name.lower():
607 addresses["nat"] = ns.ip
Scott Baker710ad052015-06-04 10:26:44 -0700608 elif "hpc_client" in ns.network.name.lower():
609 addresses["hpc_client"] = ns.ip
Scott Baker706bf972015-05-20 08:19:25 -0700610 return addresses
611
Scott Bakera6a7e032015-05-20 08:25:29 -0700612 @property
613 def nat_ip(self):
614 return self.addresses.get("nat",None)
615
616 @property
617 def lan_ip(self):
618 return self.addresses.get("lan",None)
619
620 @property
621 def wan_ip(self):
622 return self.addresses.get("wan",None)
623
624 @property
Scott Baker3f4fe402015-06-05 12:08:34 -0700625 def wan_mac(self):
626 ip = self.wan_ip
627 if not ip:
628 return None
629 try:
630 (a,b,c,d) = ip.split('.')
631 wan_mac = "02:42:%2x:%2x:%2x:%2x" % (int(a), int(b), int(c), int(d))
632 except:
633 wan_mac = "Exception"
634 return wan_mac
635
636 @property
Scott Bakera6a7e032015-05-20 08:25:29 -0700637 def private_ip(self):
638 return self.addresses.get("private",None)
639
Scott Baker710ad052015-06-04 10:26:44 -0700640 @property
641 def hpc_client_ip(self):
642 return self.addresses.get("hpc_client",None)
643
Scott Baker7bbdd2f2015-06-09 12:30:30 -0700644 @property
645 def is_synced(self):
646 return (self.enacted is not None) and (self.enacted >= self.updated)
647
648 @is_synced.setter
649 def is_synced(self, value):
650 pass
651
Scott Baker1b241612015-04-14 17:19:16 -0700652 def pick_node(self):
653 nodes = list(Node.objects.all())
654 # TODO: logic to filter nodes by which nodes are up, and which
655 # nodes the slice can instantiate on.
656 nodes = sorted(nodes, key=lambda node: node.slivers.all().count())
657 return nodes[0]
658
659 def manage_sliver(self):
Scott Baker39b0d892015-04-15 20:59:15 -0700660 # Each VCPE object owns exactly one sliver.
661
Scott Baker1b241612015-04-14 17:19:16 -0700662 if self.deleted:
663 return
664
Scott Baker1b241612015-04-14 17:19:16 -0700665 if (self.sliver is not None) and (self.sliver.image != self.image):
666 self.sliver.delete()
667 self.sliver = None
Scott Baker9c8a2c72015-05-05 17:49:46 -0700668
Scott Baker1b241612015-04-14 17:19:16 -0700669 if self.sliver is None:
670 if not self.provider_service.slices.count():
Scott Bakeree0c2802015-05-06 15:46:34 -0700671 raise XOSConfigurationError("The VCPE service has no slices")
Scott Baker1b241612015-04-14 17:19:16 -0700672
Scott Bakerac60d5f2015-05-14 21:48:53 -0700673 flavors = Flavor.objects.filter(name="m1.small")
674 if not flavors:
675 raise XOSConfigurationError("No m1.small flavor")
676
Scott Baker1b241612015-04-14 17:19:16 -0700677 node =self.pick_node()
678 sliver = Sliver(slice = self.provider_service.slices.all()[0],
679 node = node,
680 image = self.image,
Scott Baker9c8a2c72015-05-05 17:49:46 -0700681 creator = self.creator,
Scott Bakerac60d5f2015-05-14 21:48:53 -0700682 deployment = node.site_deployment.deployment,
683 flavor = flavors[0])
Scott Baker1b241612015-04-14 17:19:16 -0700684 sliver.save()
685
Scott Baker39b0d892015-04-15 20:59:15 -0700686 try:
687 self.sliver = sliver
Scott Baker697fb0b2015-04-20 09:16:17 -0700688 super(VCPETenant, self).save()
Scott Baker39b0d892015-04-15 20:59:15 -0700689 except:
690 sliver.delete()
691 raise
Scott Baker1b241612015-04-14 17:19:16 -0700692
693 def cleanup_sliver(self):
694 if self.sliver:
Scott Baker361c86c2015-07-06 14:38:02 -0700695 # print "XXX cleanup sliver", self.sliver
Scott Baker1b241612015-04-14 17:19:16 -0700696 self.sliver.delete()
697 self.sliver = None
698
Scott Baker697fb0b2015-04-20 09:16:17 -0700699 def manage_vbng(self):
700 # Each vCPE object owns exactly one vBNG object
701
702 if self.deleted:
703 return
704
705 if self.vbng is None:
706 vbngServices = VBNGService.get_service_objects().all()
707 if not vbngServices:
Scott Bakerd921e1c2015-04-20 14:24:29 -0700708 raise XOSConfigurationError("No VBNG Services available")
Scott Baker697fb0b2015-04-20 09:16:17 -0700709
710 vbng = VBNGTenant(provider_service = vbngServices[0],
711 subscriber_tenant = self)
Scott Baker9c8a2c72015-05-05 17:49:46 -0700712 vbng.caller = self.creator
Scott Baker697fb0b2015-04-20 09:16:17 -0700713 vbng.save()
714
Scott Baker697fb0b2015-04-20 09:16:17 -0700715 def cleanup_vbng(self):
716 if self.vbng:
Scott Baker361c86c2015-07-06 14:38:02 -0700717 # print "XXX cleanup vnbg", self.vbng
Scott Baker697fb0b2015-04-20 09:16:17 -0700718 self.vbng.delete()
Scott Baker697fb0b2015-04-20 09:16:17 -0700719
Scott Baker5e76f802015-06-24 12:54:24 -0700720 def cleanup_orphans(self):
Scott Baker361c86c2015-07-06 14:38:02 -0700721 # ensure vCPE only has one vBNG
722 cur_vbng = self.vbng
723 for vbng in list(self.get_subscribed_tenants(VBNGTenant)):
724 if (not cur_vbng) or (vbng.id != cur_vbng.id):
725 # print "XXX clean up orphaned vbng", vbng
726 vbng.delete()
Scott Baker5e76f802015-06-24 12:54:24 -0700727
728 if self.orig_sliver_id and (self.orig_sliver_id != self.get_attribute("sliver_id")):
729 slivers=Sliver.objects.filter(id=self.orig_sliver_id)
730 if slivers:
731 # print "XXX clean up orphaned sliver", slivers[0]
732 slivers[0].delete()
733
Scott Baker5c8abf82015-05-20 20:45:11 -0700734 def manage_bbs_account(self):
735 if self.deleted:
736 return
737
Scott Bakerdb66fd32015-07-07 17:59:44 -0700738 if self.volt and self.volt.subscriber and self.volt.subscriber.url_filter_enable:
Scott Bakere2570112015-05-20 20:57:28 -0700739 if not self.bbs_account:
740 # make sure we use the proxied VCPEService object, not the generic Service object
741 vcpe_service = VCPEService.objects.get(id=self.provider_service.id)
Scott Baker7c7b6312015-07-07 12:15:03 -0700742 self.bbs_account = vcpe_service.allocate_bbs_account()
Scott Bakere2570112015-05-20 20:57:28 -0700743 super(VCPETenant, self).save()
744 else:
745 if self.bbs_account:
746 self.bbs_account = None
747 super(VCPETenant, self).save()
Scott Baker5c8abf82015-05-20 20:45:11 -0700748
Scott Baker1b241612015-04-14 17:19:16 -0700749 def save(self, *args, **kwargs):
Scott Baker9c8a2c72015-05-05 17:49:46 -0700750 if not self.creator:
751 if not getattr(self, "caller", None):
752 # caller must be set when creating a vCPE since it creates a slice
Scott Bakeree0c2802015-05-06 15:46:34 -0700753 raise XOSProgrammingError("VCPETenant's self.caller was not set")
Scott Baker9c8a2c72015-05-05 17:49:46 -0700754 self.creator = self.caller
755 if not self.creator:
Scott Bakeree0c2802015-05-06 15:46:34 -0700756 raise XOSProgrammingError("VCPETenant's self.creator was not set")
Scott Baker9c8a2c72015-05-05 17:49:46 -0700757
Scott Baker1b241612015-04-14 17:19:16 -0700758 super(VCPETenant, self).save(*args, **kwargs)
Scott Baker1027cd62015-07-08 19:01:56 -0700759 model_policy_vcpe(self.pk)
760 #self.manage_sliver()
761 #self.manage_vbng()
762 #self.manage_bbs_account()
763 #self.cleanup_orphans()
Scott Baker1b241612015-04-14 17:19:16 -0700764
765 def delete(self, *args, **kwargs):
Scott Baker697fb0b2015-04-20 09:16:17 -0700766 self.cleanup_vbng()
Scott Baker1b241612015-04-14 17:19:16 -0700767 self.cleanup_sliver()
768 super(VCPETenant, self).delete(*args, **kwargs)
769
Scott Baker1027cd62015-07-08 19:01:56 -0700770def model_policy_vcpe(pk):
771 # TODO: this should be made in to a real model_policy
772 with transaction.atomic():
773 vcpe = VCPETenant.objects.select_for_update().filter(pk=pk)
774 if not vcpe:
775 return
776 vcpe = vcpe[0]
777 vcpe.manage_sliver()
778 vcpe.manage_vbng()
779 vcpe.manage_bbs_account()
780 vcpe.cleanup_orphans()
781
Scott Baker697fb0b2015-04-20 09:16:17 -0700782#----------------------------------------------------------------------------
783# vBNG
784#----------------------------------------------------------------------------
785
786class VBNGService(Service):
Scott Baker361c86c2015-07-06 14:38:02 -0700787 KIND = VBNG_KIND
Scott Baker697fb0b2015-04-20 09:16:17 -0700788
Scott Baker3d7ec1a2015-07-21 18:24:21 -0700789 simple_attributes = ( ("vbng_url", "http://10.0.3.136:8181/onos/virtualbng/"), )
790
Scott Baker697fb0b2015-04-20 09:16:17 -0700791 class Meta:
792 app_label = "cord"
793 verbose_name = "vBNG Service"
794 proxy = True
795
Scott Baker3d7ec1a2015-07-21 18:24:21 -0700796VBNGService.setup_simple_attributes()
797
Scott Baker697fb0b2015-04-20 09:16:17 -0700798class VBNGTenant(Tenant):
799 class Meta:
800 proxy = True
801
Scott Baker361c86c2015-07-06 14:38:02 -0700802 KIND = VBNG_KIND
Scott Baker697fb0b2015-04-20 09:16:17 -0700803
Scott Baker99ff5512015-06-02 14:34:04 -0700804 default_attributes = {"routeable_subnet": "",
Scott Baker790613c2015-06-08 19:09:53 -0700805 "mapped_ip": "",
806 "mapped_mac": "",
807 "mapped_hostname": ""}
Scott Baker697fb0b2015-04-20 09:16:17 -0700808
809 @property
810 def routeable_subnet(self):
811 return self.get_attribute("routeable_subnet", self.default_attributes["routeable_subnet"])
812
813 @routeable_subnet.setter
814 def routeable_subnet(self, value):
815 self.set_attribute("routeable_subnet", value)
Scott Baker99ff5512015-06-02 14:34:04 -0700816
817 @property
818 def mapped_ip(self):
819 return self.get_attribute("mapped_ip", self.default_attributes["mapped_ip"])
820
821 @mapped_ip.setter
822 def mapped_ip(self, value):
823 self.set_attribute("mapped_ip", value)
Scott Baker790613c2015-06-08 19:09:53 -0700824
825 @property
826 def mapped_mac(self):
827 return self.get_attribute("mapped_mac", self.default_attributes["mapped_mac"])
828
829 @mapped_mac.setter
830 def mapped_mac(self, value):
831 self.set_attribute("mapped_mac", value)
832
833 @property
834 def mapped_hostname(self):
835 return self.get_attribute("mapped_hostname", self.default_attributes["mapped_hostname"])
836
837 @mapped_hostname.setter
838 def mapped_hostname(self, value):
839 self.set_attribute("mapped_hostname", value)