blob: 2397fa2dde53fc710a09cf49fc7faa57ae9d8a4c [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
Scott Baker975d1572017-03-20 18:53:39 -07003from core.models import Service, PlCoreBase, Slice, Instance, Tenant, TenantWithContainer, Node, Image, User, Flavor, ServiceDependency, 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",
Srikanth Vavilapalli71aa28d2017-01-31 00:43:13 +000029 "nat_ip", "nat_mac", "ceilometer_enable_pub_sub")
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
Srikanth Vavilapalli71aa28d2017-01-31 00:43:13 +000096 def ceilometer_enable_pub_sub(self):
97 return self.get_attribute("ceilometer_enable_pub_sub", False)
98
99 @ceilometer_enable_pub_sub.setter
100 def ceilometer_enable_pub_sub(self, value):
101 self.set_attribute("ceilometer_enable_pub_sub", value)
102
103 @property
Srikanth Vavilapallifd8c9b32016-08-15 22:59:28 +0000104 def ceilometer_auth_url(self):
105 #FIXME: Crude way to determine if monitoring service is getting deployed with its own ceilometer+keystone
106 if not self.get_instance():
107 return self.get_controller().auth_url
108 if not self.private_ip:
109 return None
110 return "http://" + self.private_ip + ":5000/v2.0"
111
112 @property
113 def ceilometer_admin_user(self):
114 if not self.get_instance():
115 return self.get_controller().admin_user
116 return 'admin'
117
118 @property
119 def ceilometer_admin_password(self):
120 if not self.get_instance():
121 return self.get_controller().admin_password
122 return 'password'
123
124 @property
125 def ceilometer_admin_tenant(self):
126 if not self.get_instance():
127 return self.get_controller().admin_tenant
128 return 'admin'
129
rdudyala996d70b2016-10-13 17:40:55 +0000130 @property
131 def ceilometer_rabbit_compute_node(self):
132 if not self.get_instance():
133 return None
134 return self.get_instance().node.name
135
136 @property
137 def ceilometer_rabbit_host(self):
138 if not self.get_instance():
139 return None
140 return self.nat_ip
141
142 @property
143 def ceilometer_rabbit_user(self):
144 if not self.get_instance():
145 return None
146 return 'openstack'
147
148 @property
149 def ceilometer_rabbit_password(self):
150 if not self.get_instance():
151 return None
152 return 'password'
153
154 @property
155 def ceilometer_rabbit_uri(self):
156 if not self.get_instance():
157 return None
158 if not self.private_ip:
159 return None
160 return 'rabbit://openstack:password@' + self.private_ip + ':5672'
161
Srikanth Vavilapalli71aa28d2017-01-31 00:43:13 +0000162 @property
163 def kafka_url(self):
164 if not self.get_instance():
165 return None
166 if not self.private_ip:
167 return None
168 return 'kafka://' + self.private_ip + ':9092'
169
rdudyala996d70b2016-10-13 17:40:55 +0000170 def delete(self, *args, **kwargs):
171 instance = self.get_instance()
172 if instance:
173 instance.delete()
174 super(CeilometerService, self).delete(*args, **kwargs)
175
176
Scott Baker31acc652016-06-23 15:47:56 -0700177class MonitoringChannel(TenantWithContainer): # aka 'CeilometerTenant'
178 class Meta:
rdudyala996d70b2016-10-13 17:40:55 +0000179 app_label = "monitoring"
Scott Baker31acc652016-06-23 15:47:56 -0700180 proxy = True
181
182 KIND = CEILOMETER_KIND
183 LOOK_FOR_IMAGES=[ #"trusty-server-multi-nic-docker", # CloudLab
184 "ceilometer-trusty-server-multi-nic",
185 #"trusty-server-multi-nic",
186 ]
187
188
189 sync_attributes = ("private_ip", "private_mac",
190 "ceilometer_ip", "ceilometer_mac",
191 "nat_ip", "nat_mac", "ceilometer_port",)
192
193 default_attributes = {}
194 def __init__(self, *args, **kwargs):
195 ceilometer_services = CeilometerService.get_service_objects().all()
196 if ceilometer_services:
197 self._meta.get_field("provider_service").default = ceilometer_services[0].id
198 super(MonitoringChannel, self).__init__(*args, **kwargs)
199 self.set_attribute("use_same_instance_for_multiple_tenants", True)
200
201 def can_update(self, user):
202 #Allow creation of this model instances for non-admin users also
203 return True
204
205 def save(self, *args, **kwargs):
206 if not self.creator:
207 if not getattr(self, "caller", None):
208 # caller must be set when creating a monitoring channel since it creates a slice
209 raise XOSProgrammingError("MonitoringChannel's self.caller was not set")
210 self.creator = self.caller
211 if not self.creator:
212 raise XOSProgrammingError("MonitoringChannel's self.creator was not set")
213
214 if self.pk is None:
215 #Allow only one monitoring channel per user
rdudyala996d70b2016-10-13 17:40:55 +0000216 channel_count = sum ( [1 for channel in MonitoringChannel.get_tenant_objects().all() if (channel.creator == self.creator)] )
Scott Baker31acc652016-06-23 15:47:56 -0700217 if channel_count > 0:
218 raise XOSValidationError("Already %s channels exist for user Can only create max 1 MonitoringChannel instance per user" % str(channel_count))
219
220 super(MonitoringChannel, self).save(*args, **kwargs)
221 model_policy_monitoring_channel(self.pk)
222
223 def delete(self, *args, **kwargs):
224 self.cleanup_container()
225 super(MonitoringChannel, self).delete(*args, **kwargs)
226
227 @property
228 def addresses(self):
229 if (not self.id) or (not self.instance):
230 return {}
231
232 addresses = {}
233 for ns in self.instance.ports.all():
234 if "private" in ns.network.name.lower():
235 addresses["private"] = (ns.ip, ns.mac)
236 elif ("nat" in ns.network.name.lower()) or ("management" in ns.network.name.lower()):
237 addresses["nat"] = (ns.ip, ns.mac)
238 #TODO: Do we need this client_access_network. Revisit in VTN context
239 #elif "ceilometer_client_access" in ns.network.labels.lower():
240 # addresses["ceilometer"] = (ns.ip, ns.mac)
241 return addresses
242
243 @property
244 def nat_ip(self):
245 return self.addresses.get("nat", (None, None))[0]
246
247 @property
248 def nat_mac(self):
249 return self.addresses.get("nat", (None, None))[1]
250
251 @property
252 def private_ip(self):
Srikanth Vavilapalli71aa28d2017-01-31 00:43:13 +0000253 return self.addresses.get("private", (None, None))[0]
Scott Baker31acc652016-06-23 15:47:56 -0700254
255 @property
256 def private_mac(self):
Srikanth Vavilapalli71aa28d2017-01-31 00:43:13 +0000257 return self.addresses.get("private", (None, None))[1]
Scott Baker31acc652016-06-23 15:47:56 -0700258
259 @property
260 def ceilometer_ip(self):
261 return self.addresses.get("ceilometer", (None, None))[0]
262
263 @property
264 def ceilometer_mac(self):
265 return self.addresses.get("ceilometer", (None, None))[1]
266
267 @property
268 def site_tenant_list(self):
269 tenant_ids = Set()
270 for sp in SitePrivilege.objects.filter(user=self.creator):
271 site = sp.site
272 for cs in site.controllersite.all():
273 if cs.tenant_id:
274 tenant_ids.add(cs.tenant_id)
275 return tenant_ids
276
277 @property
278 def slice_tenant_list(self):
279 tenant_ids = Set()
280 for sp in SlicePrivilege.objects.filter(user=self.creator):
281 slice = sp.slice
282 for cs in slice.controllerslices.all():
283 if cs.tenant_id:
284 tenant_ids.add(cs.tenant_id)
285 for slice in Slice.objects.filter(creator=self.creator):
286 for cs in slice.controllerslices.all():
287 if cs.tenant_id:
288 tenant_ids.add(cs.tenant_id)
289 if self.creator.is_admin:
290 #TODO: Ceilometer publishes the SDN meters without associating to any tenant IDs.
291 #For now, ceilometer code is changed to pusblish all such meters with tenant
292 #id as "default_admin_tenant". Here add that default tenant as authroized tenant_id
293 #for all admin users.
294 tenant_ids.add("default_admin_tenant")
295 return tenant_ids
296
297 @property
298 def tenant_list(self):
299 return self.slice_tenant_list | self.site_tenant_list
300
301 @property
302 def tenant_list_str(self):
303 return ", ".join(self.tenant_list)
304
305 @property
306 def ceilometer_port(self):
307 # TODO: Find a better logic to choose unique ceilometer port number for each instance
308 if not self.id:
309 return None
310 return 8888+self.id
311
312 @property
Srikanth Vavilapallifd8c9b32016-08-15 22:59:28 +0000313 def ssh_proxy_tunnel(self):
314 return self.get_attribute("ssh_proxy_tunnel", False)
315
316 @ssh_proxy_tunnel.setter
317 def ssh_proxy_tunnel(self, value):
318 self.set_attribute("ssh_proxy_tunnel", value)
319
320 @property
321 def ssh_tunnel_port(self):
322 return self.get_attribute("ssh_tunnel_port")
323
324 @ssh_tunnel_port.setter
325 def ssh_tunnel_port(self, value):
326 self.set_attribute("ssh_tunnel_port", value)
327
328 @property
329 def ssh_tunnel_ip(self):
330 return self.get_attribute("ssh_tunnel_ip")
331
332 @ssh_tunnel_ip.setter
333 def ssh_tunnel_ip(self, value):
334 self.set_attribute("ssh_tunnel_ip", value)
335
336 @property
Scott Baker31acc652016-06-23 15:47:56 -0700337 def ceilometer_url(self):
Srikanth Vavilapalli71aa28d2017-01-31 00:43:13 +0000338 if self.private_ip and self.ceilometer_port:
339 return "http://" + self.private_ip + ":" + str(self.ceilometer_port) + "/"
340 else:
341 return None
342
343 @property
344 def ceilometer_ssh_proxy_url(self):
Srikanth Vavilapallifd8c9b32016-08-15 22:59:28 +0000345 if self.ssh_proxy_tunnel:
346 if self.ssh_tunnel_ip and self.ssh_tunnel_port:
347 return "http://" + self.ssh_tunnel_ip + ":" + str(self.ssh_tunnel_port) + "/"
348 else:
349 return None
350 else:
Srikanth Vavilapalli71aa28d2017-01-31 00:43:13 +0000351 return None
352
353 @property
354 def kafka_url(self):
355 ceilometer_services = CeilometerService.get_service_objects().all()
356 if not ceilometer_services:
357 return None
358 return ceilometer_services[0].kafka_url
359
Scott Baker31acc652016-06-23 15:47:56 -0700360
361def model_policy_monitoring_channel(pk):
362 # TODO: this should be made in to a real model_policy
363 with transaction.atomic():
364 mc = MonitoringChannel.objects.select_for_update().filter(pk=pk)
365 if not mc:
366 return
367 mc = mc[0]
368 mc.manage_container()
369
rdudyala996d70b2016-10-13 17:40:55 +0000370#@receiver(models.signals.post_delete, sender=MonitoringChannel)
371#def cleanup_monitoring_channel(sender, o, *args, **kwargs):
372# #o.cleanup_container()
373# #Temporary change only, remove the below code after testing
374# if o.instance:
375# o.instance.delete()
376# o.instance = None
377
378class MonitoringPublisher(Tenant):
379 class Meta:
380 app_label = "monitoring"
381 proxy = True
382
383 KIND = CEILOMETER_PUBLISH_TENANT_KIND
384
385 default_attributes = {}
386 def __init__(self, *args, **kwargs):
387 ceilometer_services = CeilometerService.get_service_objects().all()
388 if ceilometer_services:
389 self._meta.get_field("provider_service").default = ceilometer_services[0].id
390 super(MonitoringPublisher, self).__init__(*args, **kwargs)
391
392 def can_update(self, user):
393 #Allow creation of this model instances for non-admin users also
394 return True
395
396 @property
397 def creator(self):
398 from core.models import User
399 if getattr(self, "cached_creator", None):
400 return self.cached_creator
401 creator_id=self.get_attribute("creator_id")
402 if not creator_id:
403 return None
404 users=User.objects.filter(id=creator_id)
405 if not users:
406 return None
407 user=users[0]
408 self.cached_creator = users[0]
409 return user
410
411 @creator.setter
412 def creator(self, value):
413 if value:
414 value = value.id
415 if (value != self.get_attribute("creator_id", None)):
416 self.cached_creator=None
417 self.set_attribute("creator_id", value)
418
419class OpenStackServiceMonitoringPublisher(MonitoringPublisher):
420 class Meta:
421 app_label = "monitoring"
422 proxy = True
423
424 KIND = CEILOMETER_PUBLISH_TENANT_OS_KIND
425
426 def __init__(self, *args, **kwargs):
427 super(OpenStackServiceMonitoringPublisher, self).__init__(*args, **kwargs)
428
429 def can_update(self, user):
430 #Don't allow creation of this model instances for non-admin users also
431 return False
432
433 def save(self, *args, **kwargs):
434 if not self.creator:
435 if not getattr(self, "caller", None):
436 # caller must be set when creating a monitoring channel since it creates a slice
437 raise XOSProgrammingError("OpenStackServiceMonitoringPublisher's self.caller was not set")
438 self.creator = self.caller
439 if not self.creator:
440 raise XOSProgrammingError("OpenStackServiceMonitoringPublisher's self.creator was not set")
441
442 if self.pk is None:
443 #Allow only one openstack monitoring publisher per admin user
444 publisher_count = sum ( [1 for ospublisher in OpenStackServiceMonitoringPublisher.get_tenant_objects().all() if (ospublisher.creator == self.creator)] )
445 if publisher_count > 0:
446 raise XOSValidationError("Already %s openstack publishers exist for user Can only create max 1 OpenStackServiceMonitoringPublisher instance per user" % str(publisher_count))
447
448 super(OpenStackServiceMonitoringPublisher, self).save(*args, **kwargs)
449
450class ONOSServiceMonitoringPublisher(MonitoringPublisher):
451 class Meta:
452 app_label = "monitoring"
453 proxy = True
454
455 KIND = CEILOMETER_PUBLISH_TENANT_ONOS_KIND
456
457 def __init__(self, *args, **kwargs):
458 super(ONOSServiceMonitoringPublisher, self).__init__(*args, **kwargs)
459
460 def can_update(self, user):
461 #Don't allow creation of this model instances for non-admin users also
462 return False
463
464 def save(self, *args, **kwargs):
465 if not self.creator:
466 if not getattr(self, "caller", None):
467 # caller must be set when creating a monitoring channel since it creates a slice
468 raise XOSProgrammingError("ONOSServiceMonitoringPublisher's self.caller was not set")
469 self.creator = self.caller
470 if not self.creator:
471 raise XOSProgrammingError("ONOSServiceMonitoringPublisher's self.creator was not set")
472
473 if self.pk is None:
474 #Allow only one openstack monitoring publisher per admin user
475 publisher_count = sum ( [1 for onospublisher in ONOSServiceMonitoringPublisher.get_tenant_objects().all() if (onospublisher.creator == self.creator)] )
476 if publisher_count > 0:
477 raise XOSValidationError("Already %s openstack publishers exist for user Can only create max 1 ONOSServiceMonitoringPublisher instance per user" % str(publisher_count))
478
479 super(ONOSServiceMonitoringPublisher, self).save(*args, **kwargs)
480
481class UserServiceMonitoringPublisher(MonitoringPublisher):
482 class Meta:
483 app_label = "monitoring"
484 proxy = True
485
486 KIND = CEILOMETER_PUBLISH_TENANT_USER_KIND
487
488 def __init__(self, *args, **kwargs):
489 self.cached_target_service = None
490 self.cached_tenancy_from_target_service = None
491 self.cached_service_monitoring_agent = None
492 super(UserServiceMonitoringPublisher, self).__init__(*args, **kwargs)
493
494 def can_update(self, user):
495 #Don't allow creation of this model instances for non-admin users also
496 return True
497
498 @property
499 def target_service(self):
500 if getattr(self, "cached_target_service", None):
501 return self.cached_target_service
502 target_service_id = self.get_attribute("target_service_id")
503 if not target_service_id:
504 return None
505 services = Service.objects.filter(id=target_service_id)
506 if not services:
507 return None
508 target_service = services[0]
509 self.cached_target_service = target_service
510 return target_service
511
512 @target_service.setter
513 def target_service(self, value):
514 if value:
515 value = value.id
516 if (value != self.get_attribute("target_service_id", None)):
517 self.cached_target_service = None
518 self.set_attribute("target_service_id", value)
519
520 @property
521 def tenancy_from_target_service(self):
522 if getattr(self, "cached_tenancy_from_target_service", None):
523 return self.cached_tenancy_from_target_service
524 tenancy_from_target_service_id = self.get_attribute("tenancy_from_target_service_id")
525 if not tenancy_from_target_service_id:
526 return None
Scott Baker22392d42017-03-20 11:45:15 -0700527 tenancy_from_target_services = ServiceDependency.objects.filter(id=tenancy_from_target_service_id)
rdudyala996d70b2016-10-13 17:40:55 +0000528 if not tenancy_from_target_services:
529 return None
530 tenancy_from_target_service = tenancy_from_target_services[0]
531 self.cached_tenancy_from_target_service = tenancy_from_target_service
532 return tenancy_from_target_service
533
534 @tenancy_from_target_service.setter
535 def tenancy_from_target_service(self, value):
536 if value:
537 value = value.id
538 if (value != self.get_attribute("tenancy_from_target_service_id", None)):
539 self.cached_tenancy_from_target_service = None
540 self.set_attribute("tenancy_from_target_service_id", value)
541
542 @property
543 def service_monitoring_agent(self):
544 if getattr(self, "cached_service_monitoring_agent", None):
545 return self.cached_service_monitoring_agent
546 service_monitoring_agent_id = self.get_attribute("service_monitoring_agent")
547 if not service_monitoring_agent_id:
548 return None
Scott Baker22392d42017-03-20 11:45:15 -0700549 service_monitoring_agents = ServiceDependency.objects.filter(id=service_monitoring_agent_id)
rdudyala996d70b2016-10-13 17:40:55 +0000550 if not service_monitoring_agents:
551 return None
552 service_monitoring_agent = service_monitoring_agents[0]
553 self.cached_service_monitoring_agent = service_monitoring_agent
554 return service_monitoring_agent
555
556 @service_monitoring_agent.setter
557 def service_monitoring_agent(self, value):
558 if value:
559 value = value.id
560 if (value != self.get_attribute("service_monitoring_agent", None)):
561 self.cached_service_monitoring_agent = None
562 self.set_attribute("service_monitoring_agent", value)
563
564 def save(self, *args, **kwargs):
565 if not self.creator:
566 if not getattr(self, "caller", None):
567 # caller must be set when creating a monitoring channel since it creates a slice
568 raise XOSProgrammingError("UserServiceMonitoringPublisher's self.caller was not set")
569 self.creator = self.caller
570 if not self.creator:
571 raise XOSProgrammingError("UserServiceMonitoringPublisher's self.creator was not set")
572
573 tenancy_from_target_service = None
574 if self.pk is None:
575 if self.target_service is None:
576 raise XOSValidationError("Target service is not specified in UserServiceMonitoringPublisher")
577 #Allow only one monitoring publisher for a given service
578 publisher_count = sum ( [1 for publisher in UserServiceMonitoringPublisher.get_tenant_objects().all() if (publisher.target_service.id == self.target_service.id)] )
579 if publisher_count > 0:
580 raise XOSValidationError("Already %s publishers exist for service. Can only create max 1 UserServiceMonitoringPublisher instances" % str(publisher_count))
581 #Create Service composition object here
Scott Baker22392d42017-03-20 11:45:15 -0700582 tenancy_from_target_service = ServiceDependency(provider_service = self.provider_service,
rdudyala996d70b2016-10-13 17:40:55 +0000583 subscriber_service = self.target_service)
584 tenancy_from_target_service.save()
585 self.tenancy_from_target_service = tenancy_from_target_service
586
587 target_uri = CeilometerService.objects.get(id=self.provider_service.id).ceilometer_rabbit_uri
588 if target_uri is None:
589 raise XOSProgrammingError("Unable to get the Target_URI for Monitoring Agent")
590 service_monitoring_agent = ServiceMonitoringAgentInfo(service = self.target_service,
591 target_uri = target_uri)
592 service_monitoring_agent.save()
593 self.service_monitoring_agent = service_monitoring_agent
594
595 try:
596 super(UserServiceMonitoringPublisher, self).save(*args, **kwargs)
597 except:
598 if tenancy_from_target_service:
599 tenancy_from_target_service.delete()
600 if service_monitoring_agent:
601 service_monitoring_agent.delete()
602 raise
603
604class InfraMonitoringAgentInfo(ServiceMonitoringAgentInfo):
605 class Meta:
606 app_label = "monitoring"
607 start_url = models.TextField(validators=[URLValidator()], help_text="URL/API to be used to start monitoring agent")
608 start_url_json_data = models.TextField(help_text="Metadata to be passed along with start API")
609 stop_url = models.TextField(validators=[URLValidator()], help_text="URL/API to be used to stop monitoring agent")
610 monitoring_publisher = models.ForeignKey(MonitoringPublisher, related_name="monitoring_agents", null=True, blank=True)
611
612class MonitoringCollectorPluginInfo(PlCoreBase):
613 class Meta:
614 app_label = "monitoring"
615 name = models.CharField(max_length=32)
616 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/")
617 plugin_rabbit_exchange = StrippedCharField(blank=True, null=True, max_length=100)
618 #plugin_notification_handlers_json = models.TextField(blank=True, null=True, help_text="Dictionary of notification handler classes. e.g {\"name\":\"plugin handler main class\"}")
619 monitoring_publisher = models.OneToOneField(MonitoringPublisher, related_name="monitoring_collector_plugin", null=True, blank=True)
Scott Baker31acc652016-06-23 15:47:56 -0700620
621SFLOW_KIND = "sflow"
622SFLOW_PORT = 6343
623SFLOW_API_PORT = 33333
624
625class SFlowService(Service):
626 KIND = SFLOW_KIND
627
628 class Meta:
Srikanth Vavilapallid84b7b72016-06-28 00:19:07 +0000629 app_label = "monitoring"
Scott Baker31acc652016-06-23 15:47:56 -0700630 verbose_name = "sFlow Collection Service"
631 proxy = True
632
633 default_attributes = {"sflow_port": SFLOW_PORT, "sflow_api_port": SFLOW_API_PORT}
634
635 sync_attributes = ("sflow_port", "sflow_api_port",)
636
637 @property
638 def sflow_port(self):
639 return self.get_attribute("sflow_port", self.default_attributes["sflow_port"])
640
641 @sflow_port.setter
642 def sflow_port(self, value):
643 self.set_attribute("sflow_port", value)
644
645 @property
646 def sflow_api_port(self):
647 return self.get_attribute("sflow_api_port", self.default_attributes["sflow_api_port"])
648
649 @sflow_api_port.setter
650 def sflow_api_port(self, value):
651 self.set_attribute("sflow_api_port", value)
652
653 def get_instance(self):
654 if self.slices.exists():
655 slice = self.slices.all()[0]
656 if slice.instances.exists():
657 return slice.instances.all()[0]
658
659 return None
660
661 @property
662 def sflow_api_url(self):
663 if not self.get_instance():
664 return None
665 return "http://" + self.get_instance().get_ssh_ip() + ":" + str(self.sflow_api_port) + "/"
666
667class SFlowTenant(Tenant):
668 class Meta:
669 proxy = True
670
671 KIND = SFLOW_KIND
672
673 sync_attributes = ("listening_endpoint", )
674
675 default_attributes = {}
676 def __init__(self, *args, **kwargs):
677 sflow_services = SFlowService.get_service_objects().all()
678 if sflow_services:
679 self._meta.get_field("provider_service").default = sflow_services[0].id
680 super(SFlowTenant, self).__init__(*args, **kwargs)
681
682 @property
683 def creator(self):
684 from core.models import User
685 if getattr(self, "cached_creator", None):
686 return self.cached_creator
687 creator_id=self.get_attribute("creator_id")
688 if not creator_id:
689 return None
690 users=User.objects.filter(id=creator_id)
691 if not users:
692 return None
693 user=users[0]
694 self.cached_creator = users[0]
695 return user
696
697 @creator.setter
698 def creator(self, value):
699 if value:
700 value = value.id
701 if (value != self.get_attribute("creator_id", None)):
702 self.cached_creator=None
703 self.set_attribute("creator_id", value)
704
705 @property
706 def listening_endpoint(self):
707 return self.get_attribute("listening_endpoint", None)
708
709 @listening_endpoint.setter
710 def listening_endpoint(self, value):
711 if urlparse(value).scheme != 'udp':
712 raise XOSProgrammingError("SFlowTenant: Only UDP listening endpoint URLs are accepted...valid syntax is: udp://ip:port")
713 self.set_attribute("listening_endpoint", value)
714
715 def save(self, *args, **kwargs):
716 if not self.creator:
717 if not getattr(self, "caller", None):
718 # caller must be set when creating a SFlow tenant since it creates a slice
719 raise XOSProgrammingError("SFlowTenant's self.caller was not set")
720 self.creator = self.caller
721 if not self.creator:
722 raise XOSProgrammingError("SFlowTenant's self.creator was not set")
723
724 if not self.listening_endpoint:
725 raise XOSProgrammingError("SFlowTenant's self.listening_endpoint was not set")
726
727 if self.pk is None:
728 #Allow only one sflow channel per user and listening_endpoint
rdudyala996d70b2016-10-13 17:40:55 +0000729 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 -0700730 if channel_count > 0:
731 raise XOSValidationError("Already %s sflow channels exist for user Can only create max 1 tenant per user and listening endpoint" % str(channel_count))
732
733 super(SFlowTenant, self).save(*args, **kwargs)
734
735 def delete(self, *args, **kwargs):
736 super(MonitoringChannel, self).delete(*args, **kwargs)
737
738 @property
739 def authorized_resource_list(self):
740 return ['all']
741
742 @property
743 def authorized_resource_list_str(self):
744 return ", ".join(self.authorized_resource_list)
745