blob: 8c0a8b02be07c80523c9f210bebfec2f36ef7c15 [file] [log] [blame]
Matteo Scandoloeb0d11c2017-08-08 13:05:26 -07001
2# Copyright 2017-present Open Networking Foundation
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16
Scott Baker31acc652016-06-23 15:47:56 -070017from django.db import models
rdudyala996d70b2016-10-13 17:40:55 +000018from django.core.validators import URLValidator
Sapan Bhatiaa367c062017-05-19 23:10:52 +020019from core.models import Service, XOSBase, Slice, Instance, Tenant, TenantWithContainer, Node, Image, User, Flavor, ServiceDependency, ServiceMonitoringAgentInfo
20from core.models.xosbase import StrippedCharField
Scott Baker31acc652016-06-23 15:47:56 -070021import os
22from django.db import models, transaction
23from django.forms.models import model_to_dict
24from django.db.models import Q
25from operator import itemgetter, attrgetter, methodcaller
26import traceback
27from xos.exceptions import *
28from core.models import SlicePrivilege, SitePrivilege
29from sets import Set
30from urlparse import urlparse
31
32CEILOMETER_KIND = "ceilometer"
rdudyala996d70b2016-10-13 17:40:55 +000033#Ensure the length of name for 'kind' attribute is below 30
34CEILOMETER_PUBLISH_TENANT_KIND = "ceilo-publish-tenant"
35CEILOMETER_PUBLISH_TENANT_OS_KIND = "ceilo-os-publish-tenant"
36CEILOMETER_PUBLISH_TENANT_ONOS_KIND = "ceilo-onos-publish-tenant"
37CEILOMETER_PUBLISH_TENANT_USER_KIND = "ceilo-user-publish-tenant"
Scott Baker31acc652016-06-23 15:47:56 -070038
39class CeilometerService(Service):
40 KIND = CEILOMETER_KIND
Srikanth Vavilapallifd8c9b32016-08-15 22:59:28 +000041 LOOK_FOR_IMAGES=[ "ceilometer-service-trusty-server-multi-nic",
42 ]
Scott Baker31acc652016-06-23 15:47:56 -070043
raghunath dudyalaa927d562016-09-28 14:04:13 +053044 sync_attributes = ("private_ip", "private_mac",
Srikanth Vavilapalli71aa28d2017-01-31 00:43:13 +000045 "nat_ip", "nat_mac", "ceilometer_enable_pub_sub")
Scott Baker31acc652016-06-23 15:47:56 -070046 class Meta:
Srikanth Vavilapallid84b7b72016-06-28 00:19:07 +000047 app_label = "monitoring"
Scott Baker31acc652016-06-23 15:47:56 -070048 verbose_name = "Ceilometer Service"
49 proxy = True
50
Srikanth Vavilapallifd8c9b32016-08-15 22:59:28 +000051 def get_instance(self):
52 for slice in self.slices.all():
53 for instance in slice.instances.all():
54 if instance.image.name in self.LOOK_FOR_IMAGES:
55 return instance
56 return None
57
58 @property
59 def addresses(self):
60 if (not self.id) or (not self.get_instance()):
61 return {}
62
63 addresses = {}
64 for ns in self.get_instance().ports.all():
65 if "private" in ns.network.name.lower():
66 addresses["private"] = (ns.ip, ns.mac)
67 elif ("nat" in ns.network.name.lower()) or ("management" in ns.network.name.lower()):
68 addresses["nat"] = (ns.ip, ns.mac)
69 #TODO: Do we need this client_access_network. Revisit in VTN context
70 #elif "ceilometer_client_access" in ns.network.labels.lower():
71 # addresses["ceilometer"] = (ns.ip, ns.mac)
72 return addresses
73
74 @property
75 def nat_ip(self):
76 return self.addresses.get("nat", (None, None))[0]
77
78 @property
79 def nat_mac(self):
80 return self.addresses.get("nat", (None, None))[1]
81
82 @property
83 def private_ip(self):
84 return self.addresses.get("private", (None, None))[0]
85
86 @property
87 def private_mac(self):
88 return self.addresses.get("private", (None, None))[1]
89
90 def get_controller(self):
91 if not self.slices.count:
92 raise XOSConfigurationError("The service has no slices")
93 cslice = self.slices.all()[0].controllerslices.all()[0]
94 controller = cslice.controller
95 if not controller:
96 raise XOSConfigurationError("The service slice has no controller")
97 return controller
98
Scott Baker31acc652016-06-23 15:47:56 -070099 @property
100 def ceilometer_pub_sub_url(self):
Srikanth Vavilapallifd8c9b32016-08-15 22:59:28 +0000101 if not self.get_instance():
102 return self.get_attribute("ceilometer_pub_sub_url", None)
103 if not self.private_ip:
104 return None
105 return "http://" + self.private_ip + ":4455/"
Scott Baker31acc652016-06-23 15:47:56 -0700106
107 @ceilometer_pub_sub_url.setter
108 def ceilometer_pub_sub_url(self, value):
109 self.set_attribute("ceilometer_pub_sub_url", value)
110
Srikanth Vavilapallifd8c9b32016-08-15 22:59:28 +0000111 @property
Srikanth Vavilapalli71aa28d2017-01-31 00:43:13 +0000112 def ceilometer_enable_pub_sub(self):
113 return self.get_attribute("ceilometer_enable_pub_sub", False)
114
115 @ceilometer_enable_pub_sub.setter
116 def ceilometer_enable_pub_sub(self, value):
117 self.set_attribute("ceilometer_enable_pub_sub", value)
118
119 @property
Srikanth Vavilapallifd8c9b32016-08-15 22:59:28 +0000120 def ceilometer_auth_url(self):
121 #FIXME: Crude way to determine if monitoring service is getting deployed with its own ceilometer+keystone
122 if not self.get_instance():
123 return self.get_controller().auth_url
124 if not self.private_ip:
125 return None
126 return "http://" + self.private_ip + ":5000/v2.0"
127
128 @property
129 def ceilometer_admin_user(self):
130 if not self.get_instance():
131 return self.get_controller().admin_user
132 return 'admin'
133
134 @property
135 def ceilometer_admin_password(self):
136 if not self.get_instance():
137 return self.get_controller().admin_password
138 return 'password'
139
140 @property
141 def ceilometer_admin_tenant(self):
142 if not self.get_instance():
143 return self.get_controller().admin_tenant
144 return 'admin'
145
rdudyala996d70b2016-10-13 17:40:55 +0000146 @property
147 def ceilometer_rabbit_compute_node(self):
148 if not self.get_instance():
149 return None
150 return self.get_instance().node.name
151
152 @property
153 def ceilometer_rabbit_host(self):
154 if not self.get_instance():
155 return None
156 return self.nat_ip
157
158 @property
159 def ceilometer_rabbit_user(self):
160 if not self.get_instance():
161 return None
162 return 'openstack'
163
164 @property
165 def ceilometer_rabbit_password(self):
166 if not self.get_instance():
167 return None
168 return 'password'
169
170 @property
171 def ceilometer_rabbit_uri(self):
172 if not self.get_instance():
173 return None
174 if not self.private_ip:
175 return None
176 return 'rabbit://openstack:password@' + self.private_ip + ':5672'
177
Srikanth Vavilapalli71aa28d2017-01-31 00:43:13 +0000178 @property
179 def kafka_url(self):
180 if not self.get_instance():
181 return None
182 if not self.private_ip:
183 return None
184 return 'kafka://' + self.private_ip + ':9092'
185
rdudyala996d70b2016-10-13 17:40:55 +0000186 def delete(self, *args, **kwargs):
187 instance = self.get_instance()
188 if instance:
189 instance.delete()
190 super(CeilometerService, self).delete(*args, **kwargs)
191
192
Scott Baker31acc652016-06-23 15:47:56 -0700193class MonitoringChannel(TenantWithContainer): # aka 'CeilometerTenant'
194 class Meta:
rdudyala996d70b2016-10-13 17:40:55 +0000195 app_label = "monitoring"
Scott Baker31acc652016-06-23 15:47:56 -0700196 proxy = True
197
198 KIND = CEILOMETER_KIND
199 LOOK_FOR_IMAGES=[ #"trusty-server-multi-nic-docker", # CloudLab
200 "ceilometer-trusty-server-multi-nic",
201 #"trusty-server-multi-nic",
202 ]
203
204
205 sync_attributes = ("private_ip", "private_mac",
206 "ceilometer_ip", "ceilometer_mac",
207 "nat_ip", "nat_mac", "ceilometer_port",)
208
209 default_attributes = {}
210 def __init__(self, *args, **kwargs):
211 ceilometer_services = CeilometerService.get_service_objects().all()
212 if ceilometer_services:
213 self._meta.get_field("provider_service").default = ceilometer_services[0].id
214 super(MonitoringChannel, self).__init__(*args, **kwargs)
215 self.set_attribute("use_same_instance_for_multiple_tenants", True)
216
217 def can_update(self, user):
218 #Allow creation of this model instances for non-admin users also
219 return True
220
221 def save(self, *args, **kwargs):
222 if not self.creator:
223 if not getattr(self, "caller", None):
224 # caller must be set when creating a monitoring channel since it creates a slice
225 raise XOSProgrammingError("MonitoringChannel's self.caller was not set")
226 self.creator = self.caller
227 if not self.creator:
228 raise XOSProgrammingError("MonitoringChannel's self.creator was not set")
229
230 if self.pk is None:
231 #Allow only one monitoring channel per user
rdudyala996d70b2016-10-13 17:40:55 +0000232 channel_count = sum ( [1 for channel in MonitoringChannel.get_tenant_objects().all() if (channel.creator == self.creator)] )
Scott Baker31acc652016-06-23 15:47:56 -0700233 if channel_count > 0:
234 raise XOSValidationError("Already %s channels exist for user Can only create max 1 MonitoringChannel instance per user" % str(channel_count))
235
236 super(MonitoringChannel, self).save(*args, **kwargs)
237 model_policy_monitoring_channel(self.pk)
238
239 def delete(self, *args, **kwargs):
240 self.cleanup_container()
241 super(MonitoringChannel, self).delete(*args, **kwargs)
242
243 @property
244 def addresses(self):
245 if (not self.id) or (not self.instance):
246 return {}
247
248 addresses = {}
249 for ns in self.instance.ports.all():
250 if "private" in ns.network.name.lower():
251 addresses["private"] = (ns.ip, ns.mac)
252 elif ("nat" in ns.network.name.lower()) or ("management" in ns.network.name.lower()):
253 addresses["nat"] = (ns.ip, ns.mac)
254 #TODO: Do we need this client_access_network. Revisit in VTN context
255 #elif "ceilometer_client_access" in ns.network.labels.lower():
256 # addresses["ceilometer"] = (ns.ip, ns.mac)
257 return addresses
258
259 @property
260 def nat_ip(self):
261 return self.addresses.get("nat", (None, None))[0]
262
263 @property
264 def nat_mac(self):
265 return self.addresses.get("nat", (None, None))[1]
266
267 @property
268 def private_ip(self):
Srikanth Vavilapalli71aa28d2017-01-31 00:43:13 +0000269 return self.addresses.get("private", (None, None))[0]
Scott Baker31acc652016-06-23 15:47:56 -0700270
271 @property
272 def private_mac(self):
Srikanth Vavilapalli71aa28d2017-01-31 00:43:13 +0000273 return self.addresses.get("private", (None, None))[1]
Scott Baker31acc652016-06-23 15:47:56 -0700274
275 @property
276 def ceilometer_ip(self):
277 return self.addresses.get("ceilometer", (None, None))[0]
278
279 @property
280 def ceilometer_mac(self):
281 return self.addresses.get("ceilometer", (None, None))[1]
282
283 @property
284 def site_tenant_list(self):
285 tenant_ids = Set()
286 for sp in SitePrivilege.objects.filter(user=self.creator):
287 site = sp.site
288 for cs in site.controllersite.all():
289 if cs.tenant_id:
290 tenant_ids.add(cs.tenant_id)
291 return tenant_ids
292
293 @property
294 def slice_tenant_list(self):
295 tenant_ids = Set()
296 for sp in SlicePrivilege.objects.filter(user=self.creator):
297 slice = sp.slice
298 for cs in slice.controllerslices.all():
299 if cs.tenant_id:
300 tenant_ids.add(cs.tenant_id)
301 for slice in Slice.objects.filter(creator=self.creator):
302 for cs in slice.controllerslices.all():
303 if cs.tenant_id:
304 tenant_ids.add(cs.tenant_id)
305 if self.creator.is_admin:
306 #TODO: Ceilometer publishes the SDN meters without associating to any tenant IDs.
307 #For now, ceilometer code is changed to pusblish all such meters with tenant
308 #id as "default_admin_tenant". Here add that default tenant as authroized tenant_id
309 #for all admin users.
310 tenant_ids.add("default_admin_tenant")
311 return tenant_ids
312
313 @property
314 def tenant_list(self):
315 return self.slice_tenant_list | self.site_tenant_list
316
317 @property
318 def tenant_list_str(self):
319 return ", ".join(self.tenant_list)
320
321 @property
322 def ceilometer_port(self):
323 # TODO: Find a better logic to choose unique ceilometer port number for each instance
324 if not self.id:
325 return None
326 return 8888+self.id
327
328 @property
Srikanth Vavilapallifd8c9b32016-08-15 22:59:28 +0000329 def ssh_proxy_tunnel(self):
330 return self.get_attribute("ssh_proxy_tunnel", False)
331
332 @ssh_proxy_tunnel.setter
333 def ssh_proxy_tunnel(self, value):
334 self.set_attribute("ssh_proxy_tunnel", value)
335
336 @property
337 def ssh_tunnel_port(self):
338 return self.get_attribute("ssh_tunnel_port")
339
340 @ssh_tunnel_port.setter
341 def ssh_tunnel_port(self, value):
342 self.set_attribute("ssh_tunnel_port", value)
343
344 @property
345 def ssh_tunnel_ip(self):
346 return self.get_attribute("ssh_tunnel_ip")
347
348 @ssh_tunnel_ip.setter
349 def ssh_tunnel_ip(self, value):
350 self.set_attribute("ssh_tunnel_ip", value)
351
352 @property
Scott Baker31acc652016-06-23 15:47:56 -0700353 def ceilometer_url(self):
Srikanth Vavilapalli71aa28d2017-01-31 00:43:13 +0000354 if self.private_ip and self.ceilometer_port:
355 return "http://" + self.private_ip + ":" + str(self.ceilometer_port) + "/"
356 else:
357 return None
358
359 @property
360 def ceilometer_ssh_proxy_url(self):
Srikanth Vavilapallifd8c9b32016-08-15 22:59:28 +0000361 if self.ssh_proxy_tunnel:
362 if self.ssh_tunnel_ip and self.ssh_tunnel_port:
363 return "http://" + self.ssh_tunnel_ip + ":" + str(self.ssh_tunnel_port) + "/"
364 else:
365 return None
366 else:
Srikanth Vavilapalli71aa28d2017-01-31 00:43:13 +0000367 return None
368
369 @property
370 def kafka_url(self):
371 ceilometer_services = CeilometerService.get_service_objects().all()
372 if not ceilometer_services:
373 return None
374 return ceilometer_services[0].kafka_url
375
Scott Baker31acc652016-06-23 15:47:56 -0700376
377def model_policy_monitoring_channel(pk):
378 # TODO: this should be made in to a real model_policy
379 with transaction.atomic():
380 mc = MonitoringChannel.objects.select_for_update().filter(pk=pk)
381 if not mc:
382 return
383 mc = mc[0]
384 mc.manage_container()
385
rdudyala996d70b2016-10-13 17:40:55 +0000386#@receiver(models.signals.post_delete, sender=MonitoringChannel)
387#def cleanup_monitoring_channel(sender, o, *args, **kwargs):
388# #o.cleanup_container()
389# #Temporary change only, remove the below code after testing
390# if o.instance:
391# o.instance.delete()
392# o.instance = None
393
394class MonitoringPublisher(Tenant):
395 class Meta:
396 app_label = "monitoring"
397 proxy = True
398
399 KIND = CEILOMETER_PUBLISH_TENANT_KIND
400
401 default_attributes = {}
402 def __init__(self, *args, **kwargs):
403 ceilometer_services = CeilometerService.get_service_objects().all()
404 if ceilometer_services:
405 self._meta.get_field("provider_service").default = ceilometer_services[0].id
406 super(MonitoringPublisher, self).__init__(*args, **kwargs)
407
408 def can_update(self, user):
409 #Allow creation of this model instances for non-admin users also
410 return True
411
412 @property
413 def creator(self):
414 from core.models import User
415 if getattr(self, "cached_creator", None):
416 return self.cached_creator
417 creator_id=self.get_attribute("creator_id")
418 if not creator_id:
419 return None
420 users=User.objects.filter(id=creator_id)
421 if not users:
422 return None
423 user=users[0]
424 self.cached_creator = users[0]
425 return user
426
427 @creator.setter
428 def creator(self, value):
429 if value:
430 value = value.id
431 if (value != self.get_attribute("creator_id", None)):
432 self.cached_creator=None
433 self.set_attribute("creator_id", value)
434
435class OpenStackServiceMonitoringPublisher(MonitoringPublisher):
436 class Meta:
437 app_label = "monitoring"
438 proxy = True
439
440 KIND = CEILOMETER_PUBLISH_TENANT_OS_KIND
441
442 def __init__(self, *args, **kwargs):
443 super(OpenStackServiceMonitoringPublisher, self).__init__(*args, **kwargs)
444
445 def can_update(self, user):
446 #Don't allow creation of this model instances for non-admin users also
447 return False
448
449 def save(self, *args, **kwargs):
450 if not self.creator:
451 if not getattr(self, "caller", None):
452 # caller must be set when creating a monitoring channel since it creates a slice
453 raise XOSProgrammingError("OpenStackServiceMonitoringPublisher's self.caller was not set")
454 self.creator = self.caller
455 if not self.creator:
456 raise XOSProgrammingError("OpenStackServiceMonitoringPublisher's self.creator was not set")
457
458 if self.pk is None:
459 #Allow only one openstack monitoring publisher per admin user
460 publisher_count = sum ( [1 for ospublisher in OpenStackServiceMonitoringPublisher.get_tenant_objects().all() if (ospublisher.creator == self.creator)] )
461 if publisher_count > 0:
462 raise XOSValidationError("Already %s openstack publishers exist for user Can only create max 1 OpenStackServiceMonitoringPublisher instance per user" % str(publisher_count))
463
464 super(OpenStackServiceMonitoringPublisher, self).save(*args, **kwargs)
465
466class ONOSServiceMonitoringPublisher(MonitoringPublisher):
467 class Meta:
468 app_label = "monitoring"
469 proxy = True
470
471 KIND = CEILOMETER_PUBLISH_TENANT_ONOS_KIND
472
473 def __init__(self, *args, **kwargs):
474 super(ONOSServiceMonitoringPublisher, self).__init__(*args, **kwargs)
475
476 def can_update(self, user):
477 #Don't allow creation of this model instances for non-admin users also
478 return False
479
480 def save(self, *args, **kwargs):
481 if not self.creator:
482 if not getattr(self, "caller", None):
483 # caller must be set when creating a monitoring channel since it creates a slice
484 raise XOSProgrammingError("ONOSServiceMonitoringPublisher's self.caller was not set")
485 self.creator = self.caller
486 if not self.creator:
487 raise XOSProgrammingError("ONOSServiceMonitoringPublisher's self.creator was not set")
488
489 if self.pk is None:
490 #Allow only one openstack monitoring publisher per admin user
491 publisher_count = sum ( [1 for onospublisher in ONOSServiceMonitoringPublisher.get_tenant_objects().all() if (onospublisher.creator == self.creator)] )
492 if publisher_count > 0:
493 raise XOSValidationError("Already %s openstack publishers exist for user Can only create max 1 ONOSServiceMonitoringPublisher instance per user" % str(publisher_count))
494
495 super(ONOSServiceMonitoringPublisher, self).save(*args, **kwargs)
496
497class UserServiceMonitoringPublisher(MonitoringPublisher):
498 class Meta:
499 app_label = "monitoring"
500 proxy = True
501
502 KIND = CEILOMETER_PUBLISH_TENANT_USER_KIND
503
504 def __init__(self, *args, **kwargs):
505 self.cached_target_service = None
506 self.cached_tenancy_from_target_service = None
507 self.cached_service_monitoring_agent = None
508 super(UserServiceMonitoringPublisher, self).__init__(*args, **kwargs)
509
510 def can_update(self, user):
511 #Don't allow creation of this model instances for non-admin users also
512 return True
513
514 @property
515 def target_service(self):
516 if getattr(self, "cached_target_service", None):
517 return self.cached_target_service
518 target_service_id = self.get_attribute("target_service_id")
519 if not target_service_id:
520 return None
521 services = Service.objects.filter(id=target_service_id)
522 if not services:
523 return None
524 target_service = services[0]
525 self.cached_target_service = target_service
526 return target_service
527
528 @target_service.setter
529 def target_service(self, value):
530 if value:
531 value = value.id
532 if (value != self.get_attribute("target_service_id", None)):
533 self.cached_target_service = None
534 self.set_attribute("target_service_id", value)
535
536 @property
537 def tenancy_from_target_service(self):
538 if getattr(self, "cached_tenancy_from_target_service", None):
539 return self.cached_tenancy_from_target_service
540 tenancy_from_target_service_id = self.get_attribute("tenancy_from_target_service_id")
541 if not tenancy_from_target_service_id:
542 return None
Scott Baker22392d42017-03-20 11:45:15 -0700543 tenancy_from_target_services = ServiceDependency.objects.filter(id=tenancy_from_target_service_id)
rdudyala996d70b2016-10-13 17:40:55 +0000544 if not tenancy_from_target_services:
545 return None
546 tenancy_from_target_service = tenancy_from_target_services[0]
547 self.cached_tenancy_from_target_service = tenancy_from_target_service
548 return tenancy_from_target_service
549
550 @tenancy_from_target_service.setter
551 def tenancy_from_target_service(self, value):
552 if value:
553 value = value.id
554 if (value != self.get_attribute("tenancy_from_target_service_id", None)):
555 self.cached_tenancy_from_target_service = None
556 self.set_attribute("tenancy_from_target_service_id", value)
557
558 @property
559 def service_monitoring_agent(self):
560 if getattr(self, "cached_service_monitoring_agent", None):
561 return self.cached_service_monitoring_agent
562 service_monitoring_agent_id = self.get_attribute("service_monitoring_agent")
563 if not service_monitoring_agent_id:
564 return None
Scott Baker22392d42017-03-20 11:45:15 -0700565 service_monitoring_agents = ServiceDependency.objects.filter(id=service_monitoring_agent_id)
rdudyala996d70b2016-10-13 17:40:55 +0000566 if not service_monitoring_agents:
567 return None
568 service_monitoring_agent = service_monitoring_agents[0]
569 self.cached_service_monitoring_agent = service_monitoring_agent
570 return service_monitoring_agent
571
572 @service_monitoring_agent.setter
573 def service_monitoring_agent(self, value):
574 if value:
575 value = value.id
576 if (value != self.get_attribute("service_monitoring_agent", None)):
577 self.cached_service_monitoring_agent = None
578 self.set_attribute("service_monitoring_agent", value)
579
580 def save(self, *args, **kwargs):
581 if not self.creator:
582 if not getattr(self, "caller", None):
583 # caller must be set when creating a monitoring channel since it creates a slice
584 raise XOSProgrammingError("UserServiceMonitoringPublisher's self.caller was not set")
585 self.creator = self.caller
586 if not self.creator:
587 raise XOSProgrammingError("UserServiceMonitoringPublisher's self.creator was not set")
588
589 tenancy_from_target_service = None
590 if self.pk is None:
591 if self.target_service is None:
592 raise XOSValidationError("Target service is not specified in UserServiceMonitoringPublisher")
593 #Allow only one monitoring publisher for a given service
594 publisher_count = sum ( [1 for publisher in UserServiceMonitoringPublisher.get_tenant_objects().all() if (publisher.target_service.id == self.target_service.id)] )
595 if publisher_count > 0:
596 raise XOSValidationError("Already %s publishers exist for service. Can only create max 1 UserServiceMonitoringPublisher instances" % str(publisher_count))
597 #Create Service composition object here
Scott Baker22392d42017-03-20 11:45:15 -0700598 tenancy_from_target_service = ServiceDependency(provider_service = self.provider_service,
rdudyala996d70b2016-10-13 17:40:55 +0000599 subscriber_service = self.target_service)
600 tenancy_from_target_service.save()
601 self.tenancy_from_target_service = tenancy_from_target_service
602
603 target_uri = CeilometerService.objects.get(id=self.provider_service.id).ceilometer_rabbit_uri
604 if target_uri is None:
605 raise XOSProgrammingError("Unable to get the Target_URI for Monitoring Agent")
606 service_monitoring_agent = ServiceMonitoringAgentInfo(service = self.target_service,
607 target_uri = target_uri)
608 service_monitoring_agent.save()
609 self.service_monitoring_agent = service_monitoring_agent
610
611 try:
612 super(UserServiceMonitoringPublisher, self).save(*args, **kwargs)
613 except:
614 if tenancy_from_target_service:
615 tenancy_from_target_service.delete()
616 if service_monitoring_agent:
617 service_monitoring_agent.delete()
618 raise
619
620class InfraMonitoringAgentInfo(ServiceMonitoringAgentInfo):
621 class Meta:
622 app_label = "monitoring"
623 start_url = models.TextField(validators=[URLValidator()], help_text="URL/API to be used to start monitoring agent")
624 start_url_json_data = models.TextField(help_text="Metadata to be passed along with start API")
625 stop_url = models.TextField(validators=[URLValidator()], help_text="URL/API to be used to stop monitoring agent")
626 monitoring_publisher = models.ForeignKey(MonitoringPublisher, related_name="monitoring_agents", null=True, blank=True)
627
Sapan Bhatiaa367c062017-05-19 23:10:52 +0200628class MonitoringCollectorPluginInfo(XOSBase):
rdudyala996d70b2016-10-13 17:40:55 +0000629 class Meta:
630 app_label = "monitoring"
631 name = models.CharField(max_length=32)
632 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/")
633 plugin_rabbit_exchange = StrippedCharField(blank=True, null=True, max_length=100)
634 #plugin_notification_handlers_json = models.TextField(blank=True, null=True, help_text="Dictionary of notification handler classes. e.g {\"name\":\"plugin handler main class\"}")
635 monitoring_publisher = models.OneToOneField(MonitoringPublisher, related_name="monitoring_collector_plugin", null=True, blank=True)
Scott Baker31acc652016-06-23 15:47:56 -0700636
637SFLOW_KIND = "sflow"
638SFLOW_PORT = 6343
639SFLOW_API_PORT = 33333
640
641class SFlowService(Service):
642 KIND = SFLOW_KIND
643
644 class Meta:
Srikanth Vavilapallid84b7b72016-06-28 00:19:07 +0000645 app_label = "monitoring"
Scott Baker31acc652016-06-23 15:47:56 -0700646 verbose_name = "sFlow Collection Service"
647 proxy = True
648
649 default_attributes = {"sflow_port": SFLOW_PORT, "sflow_api_port": SFLOW_API_PORT}
650
651 sync_attributes = ("sflow_port", "sflow_api_port",)
652
653 @property
654 def sflow_port(self):
655 return self.get_attribute("sflow_port", self.default_attributes["sflow_port"])
656
657 @sflow_port.setter
658 def sflow_port(self, value):
659 self.set_attribute("sflow_port", value)
660
661 @property
662 def sflow_api_port(self):
663 return self.get_attribute("sflow_api_port", self.default_attributes["sflow_api_port"])
664
665 @sflow_api_port.setter
666 def sflow_api_port(self, value):
667 self.set_attribute("sflow_api_port", value)
668
669 def get_instance(self):
670 if self.slices.exists():
671 slice = self.slices.all()[0]
672 if slice.instances.exists():
673 return slice.instances.all()[0]
674
675 return None
676
677 @property
678 def sflow_api_url(self):
679 if not self.get_instance():
680 return None
681 return "http://" + self.get_instance().get_ssh_ip() + ":" + str(self.sflow_api_port) + "/"
682
683class SFlowTenant(Tenant):
684 class Meta:
685 proxy = True
686
687 KIND = SFLOW_KIND
688
689 sync_attributes = ("listening_endpoint", )
690
691 default_attributes = {}
692 def __init__(self, *args, **kwargs):
693 sflow_services = SFlowService.get_service_objects().all()
694 if sflow_services:
695 self._meta.get_field("provider_service").default = sflow_services[0].id
696 super(SFlowTenant, self).__init__(*args, **kwargs)
697
698 @property
699 def creator(self):
700 from core.models import User
701 if getattr(self, "cached_creator", None):
702 return self.cached_creator
703 creator_id=self.get_attribute("creator_id")
704 if not creator_id:
705 return None
706 users=User.objects.filter(id=creator_id)
707 if not users:
708 return None
709 user=users[0]
710 self.cached_creator = users[0]
711 return user
712
713 @creator.setter
714 def creator(self, value):
715 if value:
716 value = value.id
717 if (value != self.get_attribute("creator_id", None)):
718 self.cached_creator=None
719 self.set_attribute("creator_id", value)
720
721 @property
722 def listening_endpoint(self):
723 return self.get_attribute("listening_endpoint", None)
724
725 @listening_endpoint.setter
726 def listening_endpoint(self, value):
727 if urlparse(value).scheme != 'udp':
728 raise XOSProgrammingError("SFlowTenant: Only UDP listening endpoint URLs are accepted...valid syntax is: udp://ip:port")
729 self.set_attribute("listening_endpoint", value)
730
731 def save(self, *args, **kwargs):
732 if not self.creator:
733 if not getattr(self, "caller", None):
734 # caller must be set when creating a SFlow tenant since it creates a slice
735 raise XOSProgrammingError("SFlowTenant's self.caller was not set")
736 self.creator = self.caller
737 if not self.creator:
738 raise XOSProgrammingError("SFlowTenant's self.creator was not set")
739
740 if not self.listening_endpoint:
741 raise XOSProgrammingError("SFlowTenant's self.listening_endpoint was not set")
742
743 if self.pk is None:
744 #Allow only one sflow channel per user and listening_endpoint
rdudyala996d70b2016-10-13 17:40:55 +0000745 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 -0700746 if channel_count > 0:
747 raise XOSValidationError("Already %s sflow channels exist for user Can only create max 1 tenant per user and listening endpoint" % str(channel_count))
748
749 super(SFlowTenant, self).save(*args, **kwargs)
750
751 def delete(self, *args, **kwargs):
752 super(MonitoringChannel, self).delete(*args, **kwargs)
753
754 @property
755 def authorized_resource_list(self):
756 return ['all']
757
758 @property
759 def authorized_resource_list_str(self):
760 return ", ".join(self.authorized_resource_list)
761