update from RIFT as of 696b75d2fe9fb046261b08c616f1bcf6c0b54a9b second try
[osm/SO.git] / rwlaunchpad / plugins / rwmonitor / rift / tasklets / rwmonitor / core.py
1
2 #
3 # Copyright 2016 RIFT.IO Inc
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 #
17
18
19 import abc
20 import asyncio
21 import collections
22 import concurrent.futures
23 import importlib
24 import time
25
26 import gi
27 gi.require_version('RwVnfrYang', '1.0')
28 gi.require_version('RwMon', '1.0')
29 from gi.repository import (
30 RwTypes,
31 RwVnfrYang,
32 )
33
34 import rw_peas
35
36
37 class VdurMissingVimIdError(Exception):
38 def __init__(self, vdur_id):
39 super().__init__("VDUR:{} is has no VIM ID".format(vdur_id))
40
41
42 class VdurAlreadyRegisteredError(Exception):
43 def __init__(self, vdur_id):
44 super().__init__("VDUR:{} is already registered".format(vdur_id))
45
46
47 class AccountInUseError(Exception):
48 pass
49
50
51 class UnknownAccountError(Exception):
52 pass
53
54
55 class AccountAlreadyRegisteredError(Exception):
56 def __init__(self, account_name):
57 msg = "'{}' already registered".format(account_name)
58 super().__init__(account_name)
59
60
61 class PluginUnavailableError(Exception):
62 pass
63
64
65 class PluginNotSupportedError(PluginUnavailableError):
66 pass
67
68
69 class AlarmCreateError(Exception):
70 def __init__(self):
71 super().__init__("failed to create alarm")
72
73
74 class AlarmDestroyError(Exception):
75 def __init__(self):
76 super().__init__("failed to destroy alarm")
77
78
79 class PluginFactory(object):
80 __metaclass__ = abc.ABCMeta
81
82 @abc.abstractmethod
83 def create(self, cloud_account, plugin_name):
84 pass
85
86 @property
87 def name(self):
88 return self.__class__.PLUGIN_NAME
89
90 @property
91 def fallbacks(self):
92 try:
93 return list(self.__class__.FALLBACKS)
94 except Exception:
95 return list()
96
97 class MonascaPluginFactory(PluginFactory):
98 PLUGIN_NAME = "monasca"
99 FALLBACKS = ["ceilometer",]
100
101 def create(self, cloud_account):
102 raise PluginUnavailableError()
103
104
105 class CeilometerPluginFactory(PluginFactory):
106 PLUGIN_NAME = "ceilometer"
107 FALLBACKS = ["unavailable",]
108
109 def create(self, cloud_account):
110 plugin = rw_peas.PeasPlugin("rwmon_ceilometer", 'RwMon-1.0')
111 impl = plugin.get_interface("Monitoring")
112
113 # Check that the plugin is available on the platform associated with
114 # the cloud account
115 _, available = impl.nfvi_metrics_available(cloud_account)
116 if not available:
117 raise PluginUnavailableError()
118
119 return impl
120
121 class BrocadeVcpePluginFactory(PluginFactory):
122 PLUGIN_NAME = "brocade_vcpe"
123 FALLBACKS = ["unavailable",]
124
125 def create(self, cloud_account):
126 plugin = rw_peas.PeasPlugin("rwmon_brocade", 'RwMon-1.0')
127 impl = plugin.get_interface("Monitoring")
128
129 # Check that the plugin is available on the platform associated with
130 # the cloud account
131 _, available = impl.nfvi_metrics_available(cloud_account)
132 if not available:
133 raise PluginUnavailableError()
134
135 return impl
136
137 class UnavailablePluginFactory(PluginFactory):
138 PLUGIN_NAME = "unavailable"
139
140 class UnavailablePlugin(object):
141 def nfvi_metrics_available(self, cloud_account):
142 return None, False
143
144 def create(self, cloud_account):
145 return UnavailablePluginFactory.UnavailablePlugin()
146
147
148 class MockPluginFactory(PluginFactory):
149 PLUGIN_NAME = "mock"
150 FALLBACKS = ["unavailable",]
151
152 def create(self, cloud_account):
153 plugin = rw_peas.PeasPlugin("rwmon_mock", 'RwMon-1.0')
154 impl = plugin.get_interface("Monitoring")
155
156 # Check that the plugin is available on the platform associated with
157 # the cloud account
158 _, available = impl.nfvi_metrics_available(cloud_account)
159 if not available:
160 raise PluginUnavailableError()
161
162 return impl
163
164
165 class NfviMetricsPluginManager(object):
166 def __init__(self, log):
167 self._plugins = dict()
168 self._log = log
169 self._factories = dict()
170
171 self.register_plugin_factory(MockPluginFactory())
172 self.register_plugin_factory(CeilometerPluginFactory())
173 self.register_plugin_factory(MonascaPluginFactory())
174 self.register_plugin_factory(UnavailablePluginFactory())
175 self.register_plugin_factory(BrocadeVcpePluginFactory())
176
177
178 @property
179 def log(self):
180 return self._log
181
182 def register_plugin_factory(self, factory):
183 self._factories[factory.name] = factory
184
185 def plugin(self, account_name):
186 return self._plugins[account_name]
187
188 def register(self, cloud_account, plugin_name):
189 # Check to see if the cloud account has already been registered
190 if cloud_account.name in self._plugins:
191 raise AccountAlreadyRegisteredError(cloud_account.name)
192
193 if plugin_name not in self._factories:
194 raise PluginNotSupportedError(plugin_name)
195
196 # Create a plugin from one of the factories
197 fallbacks = [plugin_name,]
198
199 while fallbacks:
200 name = fallbacks.pop(0)
201 try:
202 factory = self._factories[name]
203 plugin = factory.create(cloud_account)
204
205 self._plugins[cloud_account.name] = plugin
206 return
207
208 except PluginUnavailableError as e:
209 self.log.warning("plugin for {} unavailable".format(name))
210 fallbacks.extend(factory.fallbacks)
211
212 raise PluginUnavailableError()
213
214 def unregister(self, account_name):
215 if account_name in self._plugins:
216 del self._plugins[account_name]
217
218
219 class NfviMetrics(object):
220 """
221 The NfviMetrics class contains the logic to retrieve NFVI metrics for a
222 particular VDUR. Of particular importance is that this object caches the
223 metrics until the data become stale so that it does not create excessive
224 load upon the underlying data-source.
225 """
226
227 # The sample interval defines the maximum time (secs) that metrics will be
228 # cached for. This duration should coincide with the sampling interval used
229 # by the underlying data-source to capture metrics.
230 SAMPLE_INTERVAL = 10
231
232 # The maximum time (secs) an instance will wait for a request to the data
233 # source to be completed
234 TIMEOUT = 2
235
236 def __init__(self, log, loop, account, plugin, vdur):
237 """Creates an instance of NfviMetrics
238
239 Arguments:
240 manager - a NfviInterface instance
241 account - a CloudAccount instance
242 plugin - an NFVI plugin
243 vdur - a VDUR instance
244
245 """
246 self._log = log
247 self._loop = loop
248 self._account = account
249 self._plugin = plugin
250 self._timestamp = 0
251 self._metrics = RwVnfrYang.YangData_RwProject_Project_VnfrCatalog_Vnfr_Vdur_NfviMetrics()
252 self._vdur = vdur
253 self._vim_id = vdur.vim_id
254 self._updating = None
255
256 @property
257 def log(self):
258 """The logger used by NfviMetrics"""
259 return self._log
260
261 @property
262 def loop(self):
263 """The current asyncio loop"""
264 return self._loop
265
266 @property
267 def vdur(self):
268 """The VDUR that these metrics are associated with"""
269 return self._vdur
270
271 def retrieve(self):
272 """Return the NFVI metrics for this VDUR
273
274 This function will immediately return the current, known NFVI metrics
275 for the associated VDUR. It will also, if the data are stale, schedule
276 a call to the data-source to retrieve new data.
277
278 """
279 if self.should_update():
280 self._updating = self.loop.create_task(self.update())
281
282 return self._metrics
283
284 def should_update(self):
285 """Return a boolean indicating whether an update should be performed"""
286 running = self._updating is not None and not self._updating.done()
287 overdue = time.time() > self._timestamp + NfviMetrics.SAMPLE_INTERVAL
288
289 return overdue and not running
290
291 @asyncio.coroutine
292 def update(self):
293 """Update the NFVI metrics for the associated VDUR
294
295 This coroutine will request new metrics from the data-source and update
296 the current metrics.
297
298 """
299 try:
300 try:
301 # Make the request to the plugin in a separate thread and do
302 # not exceed the timeout
303 _, metrics = yield from asyncio.wait_for(
304 self.loop.run_in_executor(
305 None,
306 self._plugin.nfvi_metrics,
307 self._account,
308 self._vim_id
309 ),
310 timeout=NfviMetrics.TIMEOUT,
311 loop=self.loop,
312 )
313
314 except asyncio.TimeoutError:
315 msg = "timeout on request for nfvi metrics (vim-id = {})"
316 self.log.warning(msg.format(self._vim_id))
317 return
318
319 except Exception as e:
320 self.log.exception(e)
321 return
322
323 try:
324 # Create uninitialized metric structure
325 vdu_metrics = RwVnfrYang.YangData_RwProject_Project_VnfrCatalog_Vnfr_Vdur_NfviMetrics()
326
327 # VCPU
328 vdu_metrics.vcpu.total = self.vdur.vm_flavor.vcpu_count
329 vdu_metrics.vcpu.utilization = metrics.vcpu.utilization
330
331 # Memory (in bytes)
332 vdu_metrics.memory.used = metrics.memory.used
333 vdu_metrics.memory.total = self.vdur.vm_flavor.memory_mb
334 vdu_metrics.memory.utilization = 100 * vdu_metrics.memory.used / vdu_metrics.memory.total
335
336 # Storage
337 try:
338 vdu_metrics.storage.used = metrics.storage.used
339 if self.vdur.has_field('volumes'):
340 for volume in self.vdur.volumes:
341 if vdu_metrics.storage.total is None:
342 vdu_metrics.storage.total = 1e9 * volume.size
343 else:
344 vdu_metrics.storage.total += (1e9 * volume.size)
345 else:
346 vdu_metrics.storage.total = 1e9 * self.vdur.vm_flavor.storage_gb
347 utilization = 100 * vdu_metrics.storage.used / vdu_metrics.storage.total
348 if utilization > 100:
349 utilization = 100
350 vdu_metrics.storage.utilization = utilization
351 except ZeroDivisionError:
352 vdu_metrics.storage.utilization = 0
353
354 # Network (incoming)
355 vdu_metrics.network.incoming.packets = metrics.network.incoming.packets
356 vdu_metrics.network.incoming.packet_rate = metrics.network.incoming.packet_rate
357 vdu_metrics.network.incoming.bytes = metrics.network.incoming.bytes
358 vdu_metrics.network.incoming.byte_rate = metrics.network.incoming.byte_rate
359
360 # Network (outgoing)
361 vdu_metrics.network.outgoing.packets = metrics.network.outgoing.packets
362 vdu_metrics.network.outgoing.packet_rate = metrics.network.outgoing.packet_rate
363 vdu_metrics.network.outgoing.bytes = metrics.network.outgoing.bytes
364 vdu_metrics.network.outgoing.byte_rate = metrics.network.outgoing.byte_rate
365
366 # External ports
367 vdu_metrics.external_ports.total = len([intf for intf in self.vdur.interface if intf.type_yang == 'EXTERNAL'])
368
369 # Internal ports
370 vdu_metrics.internal_ports.total = len([intf for intf in self.vdur.interface if intf.type_yang == 'INTERNAL'])
371
372 self._metrics = vdu_metrics
373
374 except Exception as e:
375 self.log.exception(e)
376
377 finally:
378 # Regardless of the result of the query, we want to make sure that
379 # we do not poll the data source until another sample duration has
380 # passed.
381 self._timestamp = time.time()
382
383
384 class NfviMetricsCache(object):
385 def __init__(self, log, loop, plugin_manager):
386 self._log = log
387 self._loop = loop
388 self._plugin_manager = plugin_manager
389 self._nfvi_metrics = dict()
390
391 self._vim_to_vdur = dict()
392 self._vdur_to_vim = dict()
393
394 def create_entry(self, account, vdur):
395 plugin = self._plugin_manager.plugin(account.name)
396 metrics = NfviMetrics(self._log, self._loop, account, plugin, vdur)
397 self._nfvi_metrics[vdur.vim_id] = metrics
398
399 self._vim_to_vdur[vdur.vim_id] = vdur.id
400 self._vdur_to_vim[vdur.id] = vdur.vim_id
401
402 def destroy_entry(self, vdur_id):
403 vim_id = self._vdur_to_vim[vdur_id]
404
405 del self._nfvi_metrics[vim_id]
406 del self._vdur_to_vim[vdur_id]
407 del self._vim_to_vdur[vim_id]
408
409 def retrieve(self, vim_id):
410 return self._nfvi_metrics[vim_id].retrieve()
411
412 def to_vim_id(self, vdur_id):
413 return self._vdur_to_vim[vdur_id]
414
415 def to_vdur_id(self, vim_id):
416 return self._vim_to_vdur[vim_id]
417
418 def contains_vdur_id(self, vdur_id):
419 return vdur_id in self._vdur_to_vim
420
421 def contains_vim_id(self, vim_id):
422 return vim_id in self._vim_to_vdur
423
424
425 class NfviInterface(object):
426 """
427 The NfviInterface serves as an interface for communicating with the
428 underlying infrastructure, i.e. retrieving metrics for VDURs that have been
429 registered with it and managing alarms.
430
431 The NfviInterface should only need to be invoked using a cloud account and
432 optionally a VIM ID; It should not need to handle mapping from VDUR ID to
433 VIM ID.
434 """
435
436 def __init__(self, loop, log, plugin_manager, cache):
437 """Creates an NfviInterface instance
438
439 Arguments:
440 loop - an event loop
441 log - a logger
442 plugin_manager - an instance of NfviMetricsPluginManager
443 cache - an instance of NfviMetricsCache
444
445 """
446 self._executor = concurrent.futures.ThreadPoolExecutor(max_workers=16)
447 self._plugin_manager = plugin_manager
448 self._cache = cache
449 self._loop = loop
450 self._log = log
451
452 @property
453 def loop(self):
454 """The event loop used by this NfviInterface"""
455 return self._loop
456
457 @property
458 def log(self):
459 """The event log used by this NfviInterface"""
460 return self._log
461
462 @property
463 def metrics(self):
464 """The list of metrics contained in this NfviInterface"""
465 return list(self._cache._nfvi_metrics.values())
466
467 def nfvi_metrics_available(self, account):
468 plugin = self._plugin_manager.plugin(account.name)
469 _, available = plugin.nfvi_metrics_available(account)
470 return available
471
472 def retrieve(self, vdur_id):
473 """Returns the NFVI metrics for the specified VDUR
474
475 Note, a VDUR must be registered with a NfviInterface before
476 metrics can be retrieved for it.
477
478 Arguments:
479 vdur_id - the ID of the VDUR to whose metrics should be retrieve
480
481 Returns:
482 An NfviMetrics object for the specified VDUR
483
484 """
485 return self._cache.retrieve(self._cache.to_vim_id(vdur_id))
486
487 @asyncio.coroutine
488 def alarm_create(self, account, vim_id, alarm, timeout=5):
489 """Create a new alarm
490
491 Arguments:
492 account - a CloudAccount instance
493 vim_id - the VM to associate with this alarm
494 alarm - an alarm structure
495 timeout - the request timeout (sec)
496
497 Raises:
498 If the data source does not respond in a timely manner, an
499 asyncio.TimeoutError will be raised.
500
501 """
502 plugin = self._plugin_manager.plugin(account.name)
503 status = yield from asyncio.wait_for(
504 self.loop.run_in_executor(
505 None,
506 plugin.do_alarm_create,
507 account,
508 vim_id,
509 alarm,
510 ),
511 timeout=timeout,
512 loop=self.loop,
513 )
514
515 if status == RwTypes.RwStatus.FAILURE:
516 raise AlarmCreateError()
517
518 @asyncio.coroutine
519 def alarm_destroy(self, account, alarm_id, timeout=5):
520 """Destroy an existing alarm
521
522 Arguments:
523 account - a CloudAccount instance
524 alarm_id - the identifier of the alarm to destroy
525 timeout - the request timeout (sec)
526
527 Raises:
528 If the data source does not respond in a timely manner, an
529 asyncio.TimeoutError will be raised.
530
531 """
532 plugin = self._plugin_manager.plugin(account.name)
533 status = yield from asyncio.wait_for(
534 self.loop.run_in_executor(
535 None,
536 plugin.do_alarm_delete,
537 account,
538 alarm_id,
539 ),
540 timeout=timeout,
541 loop=self.loop,
542 )
543
544 if status == RwTypes.RwStatus.FAILURE:
545 raise AlarmDestroyError()
546
547
548 class InstanceConfiguration(object):
549 """
550 The InstanceConfiguration class represents configuration information that
551 affects the behavior of the monitor. Essentially this class should contain
552 not functional behavior but serve as a convenient way to share data amongst
553 the components of the monitoring system.
554 """
555
556 def __init__(self):
557 self.polling_period = None
558 self.max_polling_frequency = None
559 self.min_cache_lifetime = None
560 self.public_ip = None
561
562
563 class Monitor(object):
564 """
565 The Monitor class is intended to act as a unifying interface for the
566 different sub-systems that are used to monitor the NFVI.
567 """
568
569 def __init__(self, loop, log, config, project):
570 """Create a Monitor object
571
572 Arguments:
573 loop - an event loop
574 log - the logger used by this object
575 config - an instance of InstanceConfiguration
576 project - an instance of the project
577
578 """
579 self._loop = loop
580 self._log = log
581 self._project = project
582
583 self._cloud_accounts = dict()
584 self._nfvi_plugins = NfviMetricsPluginManager(log)
585 self._cache = NfviMetricsCache(log, loop, self._nfvi_plugins)
586 self._nfvi_interface = NfviInterface(loop, log, self._nfvi_plugins, self._cache)
587 self._config = config
588 self._vnfrs = dict()
589 self._vnfr_to_vdurs = collections.defaultdict(set)
590 self._alarms = collections.defaultdict(list)
591
592 @property
593 def loop(self):
594 """The event loop used by this object"""
595 return self._loop
596
597 @property
598 def log(self):
599 """The event log used by this object"""
600 return self._log
601
602 @property
603 def project(self):
604 return self._project
605
606 @property
607 def cache(self):
608 """The NFVI metrics cache"""
609 return self._cache
610
611 @property
612 def metrics(self):
613 """The list of metrics contained in this Monitor"""
614 return self._nfvi_interface.metrics
615
616 def nfvi_metrics_available(self, account):
617 """Returns a boolean indicating whether NFVI metrics are available
618
619 Arguments:
620 account - the name of the cloud account to check
621
622 Returns:
623 a boolean indicating availability of NFVI metrics
624
625 """
626 if account not in self._cloud_accounts:
627 return False
628
629 cloud_account = self._cloud_accounts[account]
630 return self._nfvi_interface.nfvi_metrics_available(cloud_account)
631
632 def add_cloud_account(self, account):
633 """Add a cloud account to the monitor
634
635 Arguments:
636 account - a cloud account object
637
638 Raises:
639 If the cloud account has already been added to the monitor, an
640 AccountAlreadyRegisteredError is raised.
641
642 """
643 if account.name in self._cloud_accounts:
644 raise AccountAlreadyRegisteredError(account.name)
645
646 self._cloud_accounts[account.name] = account
647
648 if account.account_type == "openstack":
649 self.register_cloud_account(account, "monasca")
650 elif account.account_type == "prop_cloud1":
651 self.register_cloud_account(account, "brocade_vcpe")
652 else:
653 self.register_cloud_account(account, "mock")
654
655 def remove_cloud_account(self, account_name):
656 """Remove a cloud account from the monitor
657
658 Arguments:
659 account_name - removes the cloud account that has this name
660
661 Raises:
662 If the specified cloud account cannot be found, an
663 UnknownAccountError is raised.
664
665 """
666 if account_name not in self._cloud_accounts:
667 raise UnknownAccountError()
668
669 # Make sure that there are no VNFRs associated with this account
670 for vnfr in self._vnfrs.values():
671 if vnfr.datacenter == account_name:
672 raise AccountInUseError()
673
674 del self._cloud_accounts[account_name]
675 self._nfvi_plugins.unregister(account_name)
676
677 def get_cloud_account(self, account_name):
678 """Returns a cloud account by name
679
680 Arguments:
681 account_name - the name of the account to return
682
683 Raises:
684 An UnknownAccountError is raised if there is not account object
685 associated with the provided name
686
687 Returns:
688 A cloud account object
689
690 """
691 if account_name not in self._cloud_accounts:
692 raise UnknownAccountError()
693
694 return self._cloud_accounts[account_name]
695
696 def register_cloud_account(self, account, plugin_name):
697 """Register a cloud account with an NFVI plugin
698
699 Note that a cloud account can only be registered for one plugin at a
700 time.
701
702 Arguments:
703 account - the cloud account to associate with the plugin
704 plugin_name - the name of the plugin to use
705
706 """
707 self._nfvi_plugins.register(account, plugin_name)
708
709 def add_vnfr(self, vnfr):
710 """Add a VNFR to the monitor
711
712 Arguments:
713 vnfr - a VNFR object
714
715 Raises:
716 An UnknownAccountError is raised if the account name contained in
717 the VNFR does not reference a cloud account that has been added to
718 the monitor.
719
720 """
721 if vnfr.datacenter not in self._cloud_accounts:
722 raise UnknownAccountError()
723
724 account = self._cloud_accounts[vnfr.datacenter]
725
726 for vdur in vnfr.vdur:
727 try:
728 self.add_vdur(account, vdur)
729 self._vnfr_to_vdurs[vnfr.id].add(vdur.id)
730 except (VdurMissingVimIdError, VdurAlreadyRegisteredError):
731 pass
732
733 self._vnfrs[vnfr.id] = vnfr
734
735 def update_vnfr(self, vnfr):
736 """Updates the VNFR information in the monitor
737
738 Arguments:
739 vnfr - a VNFR object
740
741 Raises:
742 An UnknownAccountError is raised if the account name contained in
743 the VNFR does not reference a cloud account that has been added to
744 the monitor.
745
746 """
747 if vnfr.datacenter not in self._cloud_accounts:
748 raise UnknownAccountError()
749
750 account = self._cloud_accounts[vnfr.datacenter]
751
752 for vdur in vnfr.vdur:
753 try:
754 self.add_vdur(account, vdur)
755 self._vnfr_to_vdurs[vnfr.id].add(vdur.id)
756 except (VdurMissingVimIdError, VdurAlreadyRegisteredError):
757 pass
758
759 def remove_vnfr(self, vnfr_id):
760 """Remove a VNFR from the monitor
761
762 Arguments:
763 vnfr_id - the ID of the VNFR to remove
764
765 """
766 vdur_ids = self._vnfr_to_vdurs[vnfr_id]
767
768 for vdur_id in vdur_ids:
769 self.remove_vdur(vdur_id)
770
771 del self._vnfrs[vnfr_id]
772 del self._vnfr_to_vdurs[vnfr_id]
773
774 def add_vdur(self, account, vdur):
775 """Adds a VDUR to the monitor
776
777 Adding a VDUR to the monitor will automatically create a NFVI metrics
778 object that is associated with the VDUR so that the monitor cane
779 provide the NFVI metrics associated with the VDUR.
780
781 Arguments:
782 account - the cloud account associated with the VNFR that contains
783 the provided VDUR
784 vdur - a VDUR object
785
786 Raises:
787 A VdurMissingVimIdError is raised if the provided VDUR does not
788 contain a VIM ID. A VdurAlreadyRegisteredError is raised if the ID
789 associated with the VDUR has already been registered.
790
791 """
792 if not vdur.vim_id:
793 raise VdurMissingVimIdError(vdur.id)
794
795 if self.is_registered_vdur(vdur.id):
796 raise VdurAlreadyRegisteredError(vdur.id)
797
798 self.cache.create_entry(account, vdur)
799
800 def remove_vdur(self, vdur_id):
801 """Removes a VDUR from the monitor
802
803 Arguments:
804 vdur_id - the ID of the VDUR to remove
805
806 """
807 self.cache.destroy_entry(vdur_id)
808
809 # Schedule any alarms associated with the VDUR for destruction
810 for account_name, alarm_id in self._alarms[vdur_id]:
811 self.loop.create_task(self.destroy_alarm(account_name, alarm_id))
812
813 del self._alarms[vdur_id]
814
815 def list_vdur(self, vnfr_id):
816 """Returns a list of VDURs
817
818 Arguments:
819 vnfr_id - the identifier of the VNFR contains the VDURs
820
821 Returns:
822 A list of VDURs
823
824 """
825 return self._vnfrs[vnfr_id].vdur
826
827 def is_registered_vnfr(self, vnfr_id):
828 """Returns True if the VNFR is registered with the monitor
829
830 Arguments:
831 vnfr_id - the ID of the VNFR to check
832
833 Returns:
834 True if the VNFR is registered and False otherwise.
835
836 """
837 return vnfr_id in self._vnfrs
838
839 def is_registered_vdur(self, vdur_id):
840 """Returns True if the VDUR is registered with the monitor
841
842 Arguments:
843 vnfr_id - the ID of the VDUR to check
844
845 Returns:
846 True if the VDUR is registered and False otherwise.
847
848 """
849 return self.cache.contains_vdur_id(vdur_id)
850
851 def retrieve_nfvi_metrics(self, vdur_id):
852 """Retrieves the NFVI metrics associated with a VDUR
853
854 Arguments:
855 vdur_id - the ID of the VDUR whose metrics are to be retrieved
856
857 Returns:
858 NFVI metrics for a VDUR
859
860 """
861 return self._nfvi_interface.retrieve(vdur_id)
862
863 @asyncio.coroutine
864 def create_alarm(self, account_name, vdur_id, alarm):
865 """Create a new alarm
866
867 This function create an alarm and augments the provided endpoints with
868 endpoints to the launchpad if the launchpad has a public IP. The added
869 endpoints are of the form,
870
871 http://{host}:4568/{platform}/{vdur_id}/{action}
872
873 where the 'action' is one of 'ok', 'alarm', or 'insufficient_data'. The
874 messages that are pushed to the launchpad are not defined by RIFT so
875 we need to know which platform an alarm is sent from in order to
876 properly parse it.
877
878
879 Arguments:
880 account_name - the name of the account to use to create the alarm
881 vdur_id - the identifier of the VDUR to associated with the
882 alarm. If the identifier is None, the alarm is not
883 associated with a specific VDUR.
884 alarm - the alarm data
885
886 """
887 account = self.get_cloud_account(account_name)
888 vim_id = self.cache.to_vim_id(vdur_id)
889
890 # If the launchpad has a public IP, augment the action webhooks to
891 # include the launchpad so that the alarms can be broadcast as event
892 # notifications.
893 if self._config.public_ip is not None:
894 url = "http://{host}:4568/{platform}/{vdur_id}".format(
895 host=self._config.public_ip,
896 platform=account.account_type,
897 vdur_id=vudr_id,
898 )
899 alarm.actions.ok.add().url = url + "/ok"
900 alarm.actions.alarm.add().url = url + "/alarm"
901 alarm.actions.alarm.add().url = url + "/insufficient_data"
902
903 yield from self._nfvi_interface.alarm_create(account, vim_id, alarm)
904
905 # Associate the VDUR ID with the alarm ID
906 self._alarms[vdur_id].append((account_name, alarm.alarm_id))
907
908 @asyncio.coroutine
909 def destroy_alarm(self, account_name, alarm_id):
910 """Destroy an existing alarm
911
912 Arugments:
913 account_name - the name of the account that owns the alert
914 alarm_id - the identifier of the alarm to destroy
915
916 """
917 account = self.get_cloud_account(account_name)
918 yield from self._nfvi_interface.alarm_destroy(account, alarm_id)