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