blob: cf7a23bf4f1a22391c30b3261162dcb9f7090afb [file] [log] [blame]
Scott Baker31acc652016-06-23 15:47:56 -07001from django.db import models
rdudyala996d70b2016-10-13 17:40:55 +00002from django.core.validators import URLValidator
3from core.models import Service, PlCoreBase, Slice, Instance, Tenant, TenantWithContainer, Node, Image, User, Flavor, Subscriber, CoarseTenant, ServiceMonitoringAgentInfo
Scott Baker31acc652016-06-23 15:47:56 -07004from core.models.plcorebase import StrippedCharField
5import os
6from django.db import models, transaction
7from django.forms.models import model_to_dict
8from django.db.models import Q
9from operator import itemgetter, attrgetter, methodcaller
10import traceback
11from xos.exceptions import *
12from core.models import SlicePrivilege, SitePrivilege
13from sets import Set
14from urlparse import urlparse
15
16CEILOMETER_KIND = "ceilometer"
rdudyala996d70b2016-10-13 17:40:55 +000017#Ensure the length of name for 'kind' attribute is below 30
18CEILOMETER_PUBLISH_TENANT_KIND = "ceilo-publish-tenant"
19CEILOMETER_PUBLISH_TENANT_OS_KIND = "ceilo-os-publish-tenant"
20CEILOMETER_PUBLISH_TENANT_ONOS_KIND = "ceilo-onos-publish-tenant"
21CEILOMETER_PUBLISH_TENANT_USER_KIND = "ceilo-user-publish-tenant"
Scott Baker31acc652016-06-23 15:47:56 -070022
23class CeilometerService(Service):
24 KIND = CEILOMETER_KIND
Srikanth Vavilapallifd8c9b32016-08-15 22:59:28 +000025 LOOK_FOR_IMAGES=[ "ceilometer-service-trusty-server-multi-nic",
26 ]
Scott Baker31acc652016-06-23 15:47:56 -070027
raghunath dudyalaa927d562016-09-28 14:04:13 +053028 sync_attributes = ("private_ip", "private_mac",
29 "nat_ip", "nat_mac", )
Scott Baker31acc652016-06-23 15:47:56 -070030 class Meta:
Srikanth Vavilapallid84b7b72016-06-28 00:19:07 +000031 app_label = "monitoring"
Scott Baker31acc652016-06-23 15:47:56 -070032 verbose_name = "Ceilometer Service"
33 proxy = True
34
Srikanth Vavilapallifd8c9b32016-08-15 22:59:28 +000035 def get_instance(self):
36 for slice in self.slices.all():
37 for instance in slice.instances.all():
38 if instance.image.name in self.LOOK_FOR_IMAGES:
39 return instance
40 return None
41
42 @property
43 def addresses(self):
44 if (not self.id) or (not self.get_instance()):
45 return {}
46
47 addresses = {}
48 for ns in self.get_instance().ports.all():
49 if "private" in ns.network.name.lower():
50 addresses["private"] = (ns.ip, ns.mac)
51 elif ("nat" in ns.network.name.lower()) or ("management" in ns.network.name.lower()):
52 addresses["nat"] = (ns.ip, ns.mac)
53 #TODO: Do we need this client_access_network. Revisit in VTN context
54 #elif "ceilometer_client_access" in ns.network.labels.lower():
55 # addresses["ceilometer"] = (ns.ip, ns.mac)
56 return addresses
57
58 @property
59 def nat_ip(self):
60 return self.addresses.get("nat", (None, None))[0]
61
62 @property
63 def nat_mac(self):
64 return self.addresses.get("nat", (None, None))[1]
65
66 @property
67 def private_ip(self):
68 return self.addresses.get("private", (None, None))[0]
69
70 @property
71 def private_mac(self):
72 return self.addresses.get("private", (None, None))[1]
73
74 def get_controller(self):
75 if not self.slices.count:
76 raise XOSConfigurationError("The service has no slices")
77 cslice = self.slices.all()[0].controllerslices.all()[0]
78 controller = cslice.controller
79 if not controller:
80 raise XOSConfigurationError("The service slice has no controller")
81 return controller
82
Scott Baker31acc652016-06-23 15:47:56 -070083 @property
84 def ceilometer_pub_sub_url(self):
Srikanth Vavilapallifd8c9b32016-08-15 22:59:28 +000085 if not self.get_instance():
86 return self.get_attribute("ceilometer_pub_sub_url", None)
87 if not self.private_ip:
88 return None
89 return "http://" + self.private_ip + ":4455/"
Scott Baker31acc652016-06-23 15:47:56 -070090
91 @ceilometer_pub_sub_url.setter
92 def ceilometer_pub_sub_url(self, value):
93 self.set_attribute("ceilometer_pub_sub_url", value)
94
Srikanth Vavilapallifd8c9b32016-08-15 22:59:28 +000095 @property
96 def ceilometer_auth_url(self):
97 #FIXME: Crude way to determine if monitoring service is getting deployed with its own ceilometer+keystone
98 if not self.get_instance():
99 return self.get_controller().auth_url
100 if not self.private_ip:
101 return None
102 return "http://" + self.private_ip + ":5000/v2.0"
103
104 @property
105 def ceilometer_admin_user(self):
106 if not self.get_instance():
107 return self.get_controller().admin_user
108 return 'admin'
109
110 @property
111 def ceilometer_admin_password(self):
112 if not self.get_instance():
113 return self.get_controller().admin_password
114 return 'password'
115
116 @property
117 def ceilometer_admin_tenant(self):
118 if not self.get_instance():
119 return self.get_controller().admin_tenant
120 return 'admin'
121
rdudyala996d70b2016-10-13 17:40:55 +0000122 @property
123 def ceilometer_rabbit_compute_node(self):
124 if not self.get_instance():
125 return None
126 return self.get_instance().node.name
127
128 @property
129 def ceilometer_rabbit_host(self):
130 if not self.get_instance():
131 return None
132 return self.nat_ip
133
134 @property
135 def ceilometer_rabbit_user(self):
136 if not self.get_instance():
137 return None
138 return 'openstack'
139
140 @property
141 def ceilometer_rabbit_password(self):
142 if not self.get_instance():
143 return None
144 return 'password'
145
146 @property
147 def ceilometer_rabbit_uri(self):
148 if not self.get_instance():
149 return None
150 if not self.private_ip:
151 return None
152 return 'rabbit://openstack:password@' + self.private_ip + ':5672'
153
154 def delete(self, *args, **kwargs):
155 instance = self.get_instance()
156 if instance:
157 instance.delete()
158 super(CeilometerService, self).delete(*args, **kwargs)
159
160
Scott Baker31acc652016-06-23 15:47:56 -0700161class MonitoringChannel(TenantWithContainer): # aka 'CeilometerTenant'
162 class Meta:
rdudyala996d70b2016-10-13 17:40:55 +0000163 app_label = "monitoring"
Scott Baker31acc652016-06-23 15:47:56 -0700164 proxy = True
165
166 KIND = CEILOMETER_KIND
167 LOOK_FOR_IMAGES=[ #"trusty-server-multi-nic-docker", # CloudLab
168 "ceilometer-trusty-server-multi-nic",
169 #"trusty-server-multi-nic",
170 ]
171
172
173 sync_attributes = ("private_ip", "private_mac",
174 "ceilometer_ip", "ceilometer_mac",
175 "nat_ip", "nat_mac", "ceilometer_port",)
176
177 default_attributes = {}
178 def __init__(self, *args, **kwargs):
179 ceilometer_services = CeilometerService.get_service_objects().all()
180 if ceilometer_services:
181 self._meta.get_field("provider_service").default = ceilometer_services[0].id
182 super(MonitoringChannel, self).__init__(*args, **kwargs)
183 self.set_attribute("use_same_instance_for_multiple_tenants", True)
184
185 def can_update(self, user):
186 #Allow creation of this model instances for non-admin users also
187 return True
188
189 def save(self, *args, **kwargs):
190 if not self.creator:
191 if not getattr(self, "caller", None):
192 # caller must be set when creating a monitoring channel since it creates a slice
193 raise XOSProgrammingError("MonitoringChannel's self.caller was not set")
194 self.creator = self.caller
195 if not self.creator:
196 raise XOSProgrammingError("MonitoringChannel's self.creator was not set")
197
198 if self.pk is None:
199 #Allow only one monitoring channel per user
rdudyala996d70b2016-10-13 17:40:55 +0000200 channel_count = sum ( [1 for channel in MonitoringChannel.get_tenant_objects().all() if (channel.creator == self.creator)] )
Scott Baker31acc652016-06-23 15:47:56 -0700201 if channel_count > 0:
202 raise XOSValidationError("Already %s channels exist for user Can only create max 1 MonitoringChannel instance per user" % str(channel_count))
203
204 super(MonitoringChannel, self).save(*args, **kwargs)
205 model_policy_monitoring_channel(self.pk)
206
207 def delete(self, *args, **kwargs):
208 self.cleanup_container()
209 super(MonitoringChannel, self).delete(*args, **kwargs)
210
211 @property
212 def addresses(self):
213 if (not self.id) or (not self.instance):
214 return {}
215
216 addresses = {}
217 for ns in self.instance.ports.all():
218 if "private" in ns.network.name.lower():
219 addresses["private"] = (ns.ip, ns.mac)
220 elif ("nat" in ns.network.name.lower()) or ("management" in ns.network.name.lower()):
221 addresses["nat"] = (ns.ip, ns.mac)
222 #TODO: Do we need this client_access_network. Revisit in VTN context
223 #elif "ceilometer_client_access" in ns.network.labels.lower():
224 # addresses["ceilometer"] = (ns.ip, ns.mac)
225 return addresses
226
227 @property
228 def nat_ip(self):
229 return self.addresses.get("nat", (None, None))[0]
230
231 @property
232 def nat_mac(self):
233 return self.addresses.get("nat", (None, None))[1]
234
235 @property
236 def private_ip(self):
237 return self.addresses.get("nat", (None, None))[0]
238
239 @property
240 def private_mac(self):
241 return self.addresses.get("nat", (None, None))[1]
242
243 @property
244 def ceilometer_ip(self):
245 return self.addresses.get("ceilometer", (None, None))[0]
246
247 @property
248 def ceilometer_mac(self):
249 return self.addresses.get("ceilometer", (None, None))[1]
250
251 @property
252 def site_tenant_list(self):
253 tenant_ids = Set()
254 for sp in SitePrivilege.objects.filter(user=self.creator):
255 site = sp.site
256 for cs in site.controllersite.all():
257 if cs.tenant_id:
258 tenant_ids.add(cs.tenant_id)
259 return tenant_ids
260
261 @property
262 def slice_tenant_list(self):
263 tenant_ids = Set()
264 for sp in SlicePrivilege.objects.filter(user=self.creator):
265 slice = sp.slice
266 for cs in slice.controllerslices.all():
267 if cs.tenant_id:
268 tenant_ids.add(cs.tenant_id)
269 for slice in Slice.objects.filter(creator=self.creator):
270 for cs in slice.controllerslices.all():
271 if cs.tenant_id:
272 tenant_ids.add(cs.tenant_id)
273 if self.creator.is_admin:
274 #TODO: Ceilometer publishes the SDN meters without associating to any tenant IDs.
275 #For now, ceilometer code is changed to pusblish all such meters with tenant
276 #id as "default_admin_tenant". Here add that default tenant as authroized tenant_id
277 #for all admin users.
278 tenant_ids.add("default_admin_tenant")
279 return tenant_ids
280
281 @property
282 def tenant_list(self):
283 return self.slice_tenant_list | self.site_tenant_list
284
285 @property
286 def tenant_list_str(self):
287 return ", ".join(self.tenant_list)
288
289 @property
290 def ceilometer_port(self):
291 # TODO: Find a better logic to choose unique ceilometer port number for each instance
292 if not self.id:
293 return None
294 return 8888+self.id
295
296 @property
Srikanth Vavilapallifd8c9b32016-08-15 22:59:28 +0000297 def ssh_proxy_tunnel(self):
298 return self.get_attribute("ssh_proxy_tunnel", False)
299
300 @ssh_proxy_tunnel.setter
301 def ssh_proxy_tunnel(self, value):
302 self.set_attribute("ssh_proxy_tunnel", value)
303
304 @property
305 def ssh_tunnel_port(self):
306 return self.get_attribute("ssh_tunnel_port")
307
308 @ssh_tunnel_port.setter
309 def ssh_tunnel_port(self, value):
310 self.set_attribute("ssh_tunnel_port", value)
311
312 @property
313 def ssh_tunnel_ip(self):
314 return self.get_attribute("ssh_tunnel_ip")
315
316 @ssh_tunnel_ip.setter
317 def ssh_tunnel_ip(self, value):
318 self.set_attribute("ssh_tunnel_ip", value)
319
320 @property
Scott Baker31acc652016-06-23 15:47:56 -0700321 def ceilometer_url(self):
Srikanth Vavilapallifd8c9b32016-08-15 22:59:28 +0000322 if self.ssh_proxy_tunnel:
323 if self.ssh_tunnel_ip and self.ssh_tunnel_port:
324 return "http://" + self.ssh_tunnel_ip + ":" + str(self.ssh_tunnel_port) + "/"
325 else:
326 return None
327 else:
328 if self.private_ip and self.ceilometer_port:
329 return "http://" + self.private_ip + ":" + str(self.ceilometer_port) + "/"
330 else:
331 return None
Scott Baker31acc652016-06-23 15:47:56 -0700332
333def model_policy_monitoring_channel(pk):
334 # TODO: this should be made in to a real model_policy
335 with transaction.atomic():
336 mc = MonitoringChannel.objects.select_for_update().filter(pk=pk)
337 if not mc:
338 return
339 mc = mc[0]
340 mc.manage_container()
341
rdudyala996d70b2016-10-13 17:40:55 +0000342#@receiver(models.signals.post_delete, sender=MonitoringChannel)
343#def cleanup_monitoring_channel(sender, o, *args, **kwargs):
344# #o.cleanup_container()
345# #Temporary change only, remove the below code after testing
346# if o.instance:
347# o.instance.delete()
348# o.instance = None
349
350class MonitoringPublisher(Tenant):
351 class Meta:
352 app_label = "monitoring"
353 proxy = True
354
355 KIND = CEILOMETER_PUBLISH_TENANT_KIND
356
357 default_attributes = {}
358 def __init__(self, *args, **kwargs):
359 ceilometer_services = CeilometerService.get_service_objects().all()
360 if ceilometer_services:
361 self._meta.get_field("provider_service").default = ceilometer_services[0].id
362 super(MonitoringPublisher, self).__init__(*args, **kwargs)
363
364 def can_update(self, user):
365 #Allow creation of this model instances for non-admin users also
366 return True
367
368 @property
369 def creator(self):
370 from core.models import User
371 if getattr(self, "cached_creator", None):
372 return self.cached_creator
373 creator_id=self.get_attribute("creator_id")
374 if not creator_id:
375 return None
376 users=User.objects.filter(id=creator_id)
377 if not users:
378 return None
379 user=users[0]
380 self.cached_creator = users[0]
381 return user
382
383 @creator.setter
384 def creator(self, value):
385 if value:
386 value = value.id
387 if (value != self.get_attribute("creator_id", None)):
388 self.cached_creator=None
389 self.set_attribute("creator_id", value)
390
391class OpenStackServiceMonitoringPublisher(MonitoringPublisher):
392 class Meta:
393 app_label = "monitoring"
394 proxy = True
395
396 KIND = CEILOMETER_PUBLISH_TENANT_OS_KIND
397
398 def __init__(self, *args, **kwargs):
399 super(OpenStackServiceMonitoringPublisher, self).__init__(*args, **kwargs)
400
401 def can_update(self, user):
402 #Don't allow creation of this model instances for non-admin users also
403 return False
404
405 def save(self, *args, **kwargs):
406 if not self.creator:
407 if not getattr(self, "caller", None):
408 # caller must be set when creating a monitoring channel since it creates a slice
409 raise XOSProgrammingError("OpenStackServiceMonitoringPublisher's self.caller was not set")
410 self.creator = self.caller
411 if not self.creator:
412 raise XOSProgrammingError("OpenStackServiceMonitoringPublisher's self.creator was not set")
413
414 if self.pk is None:
415 #Allow only one openstack monitoring publisher per admin user
416 publisher_count = sum ( [1 for ospublisher in OpenStackServiceMonitoringPublisher.get_tenant_objects().all() if (ospublisher.creator == self.creator)] )
417 if publisher_count > 0:
418 raise XOSValidationError("Already %s openstack publishers exist for user Can only create max 1 OpenStackServiceMonitoringPublisher instance per user" % str(publisher_count))
419
420 super(OpenStackServiceMonitoringPublisher, self).save(*args, **kwargs)
421
422class ONOSServiceMonitoringPublisher(MonitoringPublisher):
423 class Meta:
424 app_label = "monitoring"
425 proxy = True
426
427 KIND = CEILOMETER_PUBLISH_TENANT_ONOS_KIND
428
429 def __init__(self, *args, **kwargs):
430 super(ONOSServiceMonitoringPublisher, self).__init__(*args, **kwargs)
431
432 def can_update(self, user):
433 #Don't allow creation of this model instances for non-admin users also
434 return False
435
436 def save(self, *args, **kwargs):
437 if not self.creator:
438 if not getattr(self, "caller", None):
439 # caller must be set when creating a monitoring channel since it creates a slice
440 raise XOSProgrammingError("ONOSServiceMonitoringPublisher's self.caller was not set")
441 self.creator = self.caller
442 if not self.creator:
443 raise XOSProgrammingError("ONOSServiceMonitoringPublisher's self.creator was not set")
444
445 if self.pk is None:
446 #Allow only one openstack monitoring publisher per admin user
447 publisher_count = sum ( [1 for onospublisher in ONOSServiceMonitoringPublisher.get_tenant_objects().all() if (onospublisher.creator == self.creator)] )
448 if publisher_count > 0:
449 raise XOSValidationError("Already %s openstack publishers exist for user Can only create max 1 ONOSServiceMonitoringPublisher instance per user" % str(publisher_count))
450
451 super(ONOSServiceMonitoringPublisher, self).save(*args, **kwargs)
452
453class UserServiceMonitoringPublisher(MonitoringPublisher):
454 class Meta:
455 app_label = "monitoring"
456 proxy = True
457
458 KIND = CEILOMETER_PUBLISH_TENANT_USER_KIND
459
460 def __init__(self, *args, **kwargs):
461 self.cached_target_service = None
462 self.cached_tenancy_from_target_service = None
463 self.cached_service_monitoring_agent = None
464 super(UserServiceMonitoringPublisher, self).__init__(*args, **kwargs)
465
466 def can_update(self, user):
467 #Don't allow creation of this model instances for non-admin users also
468 return True
469
470 @property
471 def target_service(self):
472 if getattr(self, "cached_target_service", None):
473 return self.cached_target_service
474 target_service_id = self.get_attribute("target_service_id")
475 if not target_service_id:
476 return None
477 services = Service.objects.filter(id=target_service_id)
478 if not services:
479 return None
480 target_service = services[0]
481 self.cached_target_service = target_service
482 return target_service
483
484 @target_service.setter
485 def target_service(self, value):
486 if value:
487 value = value.id
488 if (value != self.get_attribute("target_service_id", None)):
489 self.cached_target_service = None
490 self.set_attribute("target_service_id", value)
491
492 @property
493 def tenancy_from_target_service(self):
494 if getattr(self, "cached_tenancy_from_target_service", None):
495 return self.cached_tenancy_from_target_service
496 tenancy_from_target_service_id = self.get_attribute("tenancy_from_target_service_id")
497 if not tenancy_from_target_service_id:
498 return None
499 tenancy_from_target_services = CoarseTenant.objects.filter(id=tenancy_from_target_service_id)
500 if not tenancy_from_target_services:
501 return None
502 tenancy_from_target_service = tenancy_from_target_services[0]
503 self.cached_tenancy_from_target_service = tenancy_from_target_service
504 return tenancy_from_target_service
505
506 @tenancy_from_target_service.setter
507 def tenancy_from_target_service(self, value):
508 if value:
509 value = value.id
510 if (value != self.get_attribute("tenancy_from_target_service_id", None)):
511 self.cached_tenancy_from_target_service = None
512 self.set_attribute("tenancy_from_target_service_id", value)
513
514 @property
515 def service_monitoring_agent(self):
516 if getattr(self, "cached_service_monitoring_agent", None):
517 return self.cached_service_monitoring_agent
518 service_monitoring_agent_id = self.get_attribute("service_monitoring_agent")
519 if not service_monitoring_agent_id:
520 return None
521 service_monitoring_agents = CoarseTenant.objects.filter(id=service_monitoring_agent_id)
522 if not service_monitoring_agents:
523 return None
524 service_monitoring_agent = service_monitoring_agents[0]
525 self.cached_service_monitoring_agent = service_monitoring_agent
526 return service_monitoring_agent
527
528 @service_monitoring_agent.setter
529 def service_monitoring_agent(self, value):
530 if value:
531 value = value.id
532 if (value != self.get_attribute("service_monitoring_agent", None)):
533 self.cached_service_monitoring_agent = None
534 self.set_attribute("service_monitoring_agent", value)
535
536 def save(self, *args, **kwargs):
537 if not self.creator:
538 if not getattr(self, "caller", None):
539 # caller must be set when creating a monitoring channel since it creates a slice
540 raise XOSProgrammingError("UserServiceMonitoringPublisher's self.caller was not set")
541 self.creator = self.caller
542 if not self.creator:
543 raise XOSProgrammingError("UserServiceMonitoringPublisher's self.creator was not set")
544
545 tenancy_from_target_service = None
546 if self.pk is None:
547 if self.target_service is None:
548 raise XOSValidationError("Target service is not specified in UserServiceMonitoringPublisher")
549 #Allow only one monitoring publisher for a given service
550 publisher_count = sum ( [1 for publisher in UserServiceMonitoringPublisher.get_tenant_objects().all() if (publisher.target_service.id == self.target_service.id)] )
551 if publisher_count > 0:
552 raise XOSValidationError("Already %s publishers exist for service. Can only create max 1 UserServiceMonitoringPublisher instances" % str(publisher_count))
553 #Create Service composition object here
554 tenancy_from_target_service = CoarseTenant(provider_service = self.provider_service,
555 subscriber_service = self.target_service)
556 tenancy_from_target_service.save()
557 self.tenancy_from_target_service = tenancy_from_target_service
558
559 target_uri = CeilometerService.objects.get(id=self.provider_service.id).ceilometer_rabbit_uri
560 if target_uri is None:
561 raise XOSProgrammingError("Unable to get the Target_URI for Monitoring Agent")
562 service_monitoring_agent = ServiceMonitoringAgentInfo(service = self.target_service,
563 target_uri = target_uri)
564 service_monitoring_agent.save()
565 self.service_monitoring_agent = service_monitoring_agent
566
567 try:
568 super(UserServiceMonitoringPublisher, self).save(*args, **kwargs)
569 except:
570 if tenancy_from_target_service:
571 tenancy_from_target_service.delete()
572 if service_monitoring_agent:
573 service_monitoring_agent.delete()
574 raise
575
576class InfraMonitoringAgentInfo(ServiceMonitoringAgentInfo):
577 class Meta:
578 app_label = "monitoring"
579 start_url = models.TextField(validators=[URLValidator()], help_text="URL/API to be used to start monitoring agent")
580 start_url_json_data = models.TextField(help_text="Metadata to be passed along with start API")
581 stop_url = models.TextField(validators=[URLValidator()], help_text="URL/API to be used to stop monitoring agent")
582 monitoring_publisher = models.ForeignKey(MonitoringPublisher, related_name="monitoring_agents", null=True, blank=True)
583
584class MonitoringCollectorPluginInfo(PlCoreBase):
585 class Meta:
586 app_label = "monitoring"
587 name = models.CharField(max_length=32)
588 plugin_folder_path = StrippedCharField(blank=True, null=True, max_length=1024, help_text="Path pointing to plugin files. e.g. /opt/xos/synchronizers/monitoring/ceilometer/ceilometer-plugins/network/ext_services/vsg/")
589 plugin_rabbit_exchange = StrippedCharField(blank=True, null=True, max_length=100)
590 #plugin_notification_handlers_json = models.TextField(blank=True, null=True, help_text="Dictionary of notification handler classes. e.g {\"name\":\"plugin handler main class\"}")
591 monitoring_publisher = models.OneToOneField(MonitoringPublisher, related_name="monitoring_collector_plugin", null=True, blank=True)
Scott Baker31acc652016-06-23 15:47:56 -0700592
593SFLOW_KIND = "sflow"
594SFLOW_PORT = 6343
595SFLOW_API_PORT = 33333
596
597class SFlowService(Service):
598 KIND = SFLOW_KIND
599
600 class Meta:
Srikanth Vavilapallid84b7b72016-06-28 00:19:07 +0000601 app_label = "monitoring"
Scott Baker31acc652016-06-23 15:47:56 -0700602 verbose_name = "sFlow Collection Service"
603 proxy = True
604
605 default_attributes = {"sflow_port": SFLOW_PORT, "sflow_api_port": SFLOW_API_PORT}
606
607 sync_attributes = ("sflow_port", "sflow_api_port",)
608
609 @property
610 def sflow_port(self):
611 return self.get_attribute("sflow_port", self.default_attributes["sflow_port"])
612
613 @sflow_port.setter
614 def sflow_port(self, value):
615 self.set_attribute("sflow_port", value)
616
617 @property
618 def sflow_api_port(self):
619 return self.get_attribute("sflow_api_port", self.default_attributes["sflow_api_port"])
620
621 @sflow_api_port.setter
622 def sflow_api_port(self, value):
623 self.set_attribute("sflow_api_port", value)
624
625 def get_instance(self):
626 if self.slices.exists():
627 slice = self.slices.all()[0]
628 if slice.instances.exists():
629 return slice.instances.all()[0]
630
631 return None
632
633 @property
634 def sflow_api_url(self):
635 if not self.get_instance():
636 return None
637 return "http://" + self.get_instance().get_ssh_ip() + ":" + str(self.sflow_api_port) + "/"
638
639class SFlowTenant(Tenant):
640 class Meta:
641 proxy = True
642
643 KIND = SFLOW_KIND
644
645 sync_attributes = ("listening_endpoint", )
646
647 default_attributes = {}
648 def __init__(self, *args, **kwargs):
649 sflow_services = SFlowService.get_service_objects().all()
650 if sflow_services:
651 self._meta.get_field("provider_service").default = sflow_services[0].id
652 super(SFlowTenant, self).__init__(*args, **kwargs)
653
654 @property
655 def creator(self):
656 from core.models import User
657 if getattr(self, "cached_creator", None):
658 return self.cached_creator
659 creator_id=self.get_attribute("creator_id")
660 if not creator_id:
661 return None
662 users=User.objects.filter(id=creator_id)
663 if not users:
664 return None
665 user=users[0]
666 self.cached_creator = users[0]
667 return user
668
669 @creator.setter
670 def creator(self, value):
671 if value:
672 value = value.id
673 if (value != self.get_attribute("creator_id", None)):
674 self.cached_creator=None
675 self.set_attribute("creator_id", value)
676
677 @property
678 def listening_endpoint(self):
679 return self.get_attribute("listening_endpoint", None)
680
681 @listening_endpoint.setter
682 def listening_endpoint(self, value):
683 if urlparse(value).scheme != 'udp':
684 raise XOSProgrammingError("SFlowTenant: Only UDP listening endpoint URLs are accepted...valid syntax is: udp://ip:port")
685 self.set_attribute("listening_endpoint", value)
686
687 def save(self, *args, **kwargs):
688 if not self.creator:
689 if not getattr(self, "caller", None):
690 # caller must be set when creating a SFlow tenant since it creates a slice
691 raise XOSProgrammingError("SFlowTenant's self.caller was not set")
692 self.creator = self.caller
693 if not self.creator:
694 raise XOSProgrammingError("SFlowTenant's self.creator was not set")
695
696 if not self.listening_endpoint:
697 raise XOSProgrammingError("SFlowTenant's self.listening_endpoint was not set")
698
699 if self.pk is None:
700 #Allow only one sflow channel per user and listening_endpoint
rdudyala996d70b2016-10-13 17:40:55 +0000701 channel_count = sum ( [1 for channel in SFlowTenant.get_tenant_objects().all() if ((channel.creator == self.creator) and (channel.listening_endpoint == self.listening_endpoint))] )
Scott Baker31acc652016-06-23 15:47:56 -0700702 if channel_count > 0:
703 raise XOSValidationError("Already %s sflow channels exist for user Can only create max 1 tenant per user and listening endpoint" % str(channel_count))
704
705 super(SFlowTenant, self).save(*args, **kwargs)
706
707 def delete(self, *args, **kwargs):
708 super(MonitoringChannel, self).delete(*args, **kwargs)
709
710 @property
711 def authorized_resource_list(self):
712 return ['all']
713
714 @property
715 def authorized_resource_list_str(self):
716 return ", ".join(self.authorized_resource_list)
717