def test_vnfr_add_update_delete(self): """ When a VNFR is added to the Monitor a record is created of the relationship between the VNFR and any VDURs that it contains. Each VDUR is then registered with the VdurNfviMetricsManager. A VNFR can also be updated so that it contains more of less VDURs. Any VDURs that are added to the VNFR are registered with the NdurNfviMetricsManager, and any that are removed are unregistered. When a VNFR is deleted, all of the VDURs contained in the VNFR are unregistered. """ # Define the VDUR to be registered vdur = RwVnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr_Vdur() vdur.vim_id = 'test-vim-id-1' vdur.id = 'test-vdur-id-1' vnfr = RwVnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr() vnfr.cloud_account = self.account.name vnfr.id = 'test-vnfr-id' vnfr.vdur.append(vdur) self.monitor.add_cloud_account(self.account) # Add the VNFR to the monitor. This will also register VDURs contained # in the VNFR with the monitor. self.monitor.add_vnfr(vnfr) self.assertTrue(self.monitor.is_registered_vdur('test-vdur-id-1')) # Add another VDUR to the VNFR and update the monitor. Both VDURs # should now be registered vdur = RwVnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr_Vdur() vdur.vim_id = 'test-vim-id-2' vdur.id = 'test-vdur-id-2' vnfr.vdur.append(vdur) self.monitor.update_vnfr(vnfr) self.assertTrue(self.monitor.is_registered_vdur('test-vdur-id-1')) self.assertTrue(self.monitor.is_registered_vdur('test-vdur-id-2')) # Delete the VNFR from the monitor. This should remove the VNFR and all # of the associated VDURs from the monitor. self.monitor.remove_vnfr(vnfr.id) self.assertFalse(self.monitor.is_registered_vnfr('test-vnfr-id')) self.assertFalse(self.monitor.is_registered_vdur('test-vdur-id-1')) self.assertFalse(self.monitor.is_registered_vdur('test-vdur-id-2')) with self.assertRaises(KeyError): self.monitor.retrieve_nfvi_metrics('test-vdur-id-1') with self.assertRaises(KeyError): self.monitor.retrieve_nfvi_metrics('test-vdur-id-2')
def test_vnfr_crash(self): vnf_handler = store.VnfrCatalogSubscriber(self.log, self.dts, self.loop) def get_reg_flags(self): from gi.repository import RwDts as rwdts return rwdts.Flag.SUBSCRIBER | rwdts.Flag.DELTA_READY | rwdts.Flag.CACHE vnf_handler.get_reg_flags = types.MethodType(get_reg_flags, vnf_handler) # publish yield from vnf_handler.register() mock_vnfr = RwVnfrYang.YangData_RwProject_Project_VnfrCatalog_Vnfr() mock_vnfr.id = str(uuid.uuid1()) def mon_xpath(param_id=None): """ Monitoring params xpath """ return ("D,/rw-project:project/vnfr:vnfr-catalog" + "/vnfr:vnfr[vnfr:id={}]".format(quoted_key(mock_vnfr.id)) + "/vnfr:monitoring-param" + ("[vnfr:id={}]".format( quoted_key(param_id)) if param_id else "")) w_xpath = "D,/rw-project:project/vnfr:vnfr-catalog/vnfr:vnfr" xpath = "{}[vnfr:id={}]".format(w_xpath, quoted_key(mock_vnfr.id)) yield from self.publisher.publish(w_xpath, xpath, mock_vnfr) mock_param = VnfrYang.YangData_RwProject_Project_VnfrCatalog_Vnfr_MonitoringParam.from_dict( {"id": "1"}) mock_vnfr.monitoring_param.append(mock_param) yield from self.publisher.publish(w_xpath, xpath, mock_vnfr)
def start(self): """ The task start callback """ super(RwLogTestTasklet, self).start() self._dts = rift.tasklets.DTS(self.tasklet_info, RwVnfrYang.get_schema(), self.loop, self.on_dts_state_change)
def __init__(self, log, loop, account, plugin, vdur): """Creates an instance of NfviMetrics Arguments: manager - a NfviInterface instance account - a CloudAccount instance plugin - an NFVI plugin vdur - a VDUR instance """ self._log = log self._loop = loop self._account = account self._plugin = plugin self._timestamp = 0 self._metrics = RwVnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr_Vdur_NfviMetrics() self._vdur = vdur self._vim_id = vdur.vim_id self._updating = None
def test_monitor_cloud_accounts_illegal_removal(self): """ A cloud account may not be removed while there are plugins or records that are associated with it. Attempting to delete such a cloud account will raise an exception. """ # Add the cloud account to the monitor self.monitor.add_cloud_account(self.account) # Create a VNFR associated with the cloud account vnfr = RwVnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr() vnfr.cloud_account = self.account.name vnfr.id = 'test-vnfr-id' # Add a VDUR to the VNFR vdur = vnfr.vdur.add() vdur.vim_id = 'test-vim-id-1' vdur.id = 'test-vdur-id-1' # Now add the VNFR to the monitor self.monitor.add_vnfr(vnfr) # Check that the monitor contains the VNFR, VDUR, and metrics self.assertTrue(self.monitor.is_registered_vdur(vdur.id)) self.assertTrue(self.monitor.is_registered_vnfr(vnfr.id)) self.assertEqual(1, len(self.monitor.metrics)) # Deleting the cloud account now should raise an exception because the # VNFR and VDUR are associated with the cloud account. with self.assertRaises(AccountInUseError): self.monitor.remove_cloud_account(self.account.name) # Now remove the VNFR from the monitor self.monitor.remove_vnfr(vnfr.id) self.assertFalse(self.monitor.is_registered_vdur(vdur.id)) self.assertFalse(self.monitor.is_registered_vnfr(vnfr.id)) self.assertEqual(0, len(self.monitor.metrics)) # Safely delete the cloud account self.monitor.remove_cloud_account(self.account.name)
def test_vnfr_handler(self): yield from self.store.register() mock_vnfr = RwVnfrYang.YangData_RwProject_Project_VnfrCatalog_Vnfr() mock_vnfr.id = str(uuid.uuid1()) w_xpath = "D,/rw-project:project/vnfr:vnfr-catalog/vnfr:vnfr" xpath = "{}[vnfr:id={}]".format(w_xpath, quoted_key(mock_vnfr.id)) yield from self.publisher.publish(w_xpath, xpath, mock_vnfr) yield from asyncio.sleep(5, loop=self.loop) assert len(self.store.vnfr) == 1 assert self.store.get_vnfr(self.store.vnfr[0].id) is not None yield from self.dts.query_update(xpath, rwdts.XactFlag.ADVISE, mock_vnfr) yield from asyncio.sleep(5, loop=self.loop) assert len(self.store.vnfr) == 1 yield from self.dts.query_delete(xpath, flags=rwdts.XactFlag.ADVISE) yield from asyncio.sleep(5, loop=self.loop) assert len(self.store.vnfr) == 0
def update(self): """Update the NFVI metrics for the associated VDUR This coroutine will request new metrics from the data-source and update the current metrics. """ try: try: # Make the request to the plugin in a separate thread and do # not exceed the timeout _, metrics = yield from asyncio.wait_for( self.loop.run_in_executor( None, self._plugin.nfvi_metrics, self._account, self._vim_id, ), timeout=NfviMetrics.TIMEOUT, loop=self.loop, ) except asyncio.TimeoutError: msg = "timeout on request for nfvi metrics (vim-id = {})" self.log.warning(msg.format(self._vim_id)) return except Exception as e: self.log.exception(e) return try: # Create uninitialized metric structure vdu_metrics = RwVnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr_Vdur_NfviMetrics() # VCPU vdu_metrics.vcpu.total = self.vdur.vm_flavor.vcpu_count vdu_metrics.vcpu.utilization = metrics.vcpu.utilization # Memory (in bytes) vdu_metrics.memory.used = metrics.memory.used vdu_metrics.memory.total = self.vdur.vm_flavor.memory_mb vdu_metrics.memory.utilization = 100 * vdu_metrics.memory.used / vdu_metrics.memory.total # Storage vdu_metrics.storage.used = metrics.storage.used vdu_metrics.storage.total = 1e9 * self.vdur.vm_flavor.storage_gb vdu_metrics.storage.utilization = 100 * vdu_metrics.storage.used / vdu_metrics.storage.total # Network (incoming) vdu_metrics.network.incoming.packets = metrics.network.incoming.packets vdu_metrics.network.incoming.packet_rate = metrics.network.incoming.packet_rate vdu_metrics.network.incoming.bytes = metrics.network.incoming.bytes vdu_metrics.network.incoming.byte_rate = metrics.network.incoming.byte_rate # Network (outgoing) vdu_metrics.network.outgoing.packets = metrics.network.outgoing.packets vdu_metrics.network.outgoing.packet_rate = metrics.network.outgoing.packet_rate vdu_metrics.network.outgoing.bytes = metrics.network.outgoing.bytes vdu_metrics.network.outgoing.byte_rate = metrics.network.outgoing.byte_rate # External ports vdu_metrics.external_ports.total = len(self.vdur.external_interface) # Internal ports vdu_metrics.internal_ports.total = len(self.vdur.internal_interface) self._metrics = vdu_metrics except Exception as e: self.log.exception(e) finally: # Regardless of the result of the query, we want to make sure that # we do not poll the data source until another sample duration has # passed. self._timestamp = time.time()
def update(loop, log, executor, account, plugin, vim_id): """Update the NFVI metrics for the associated VDUR This coroutine will request new metrics from the data-source and update the current metrics. """ try: # Make the request to the plugin in a separate thread and do # not exceed the timeout _, metrics = yield from asyncio.wait_for( loop.run_in_executor( executor, plugin.nfvi_metrics, account, vim_id ), timeout=10, loop=loop, ) except asyncio.TimeoutError: msg = "timeout on request for nfvi metrics (vim-id = {})" log.warning(msg.format(vim_id)) return except Exception as e: log.exception(e) return try: # Create uninitialized metric structure vdu_metrics = RwVnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr_Vdur_NfviMetrics() # VCPU vdu_metrics.vcpu.total = 5 vdu_metrics.vcpu.utilization = metrics.vcpu.utilization # Memory (in bytes) vdu_metrics.memory.used = metrics.memory.used vdu_metrics.memory.total = 5000 vdu_metrics.memory.utilization = 100 * vdu_metrics.memory.used / vdu_metrics.memory.total # Storage try: vdu_metrics.storage.used = metrics.storage.used utilization = 100 * vdu_metrics.storage.used / vdu_metrics.storage.total if utilization > 100: utilization = 100 vdu_metrics.storage.utilization = utilization except ZeroDivisionError: vdu_metrics.storage.utilization = 0 # Network (incoming) vdu_metrics.network.incoming.packets = metrics.network.incoming.packets vdu_metrics.network.incoming.packet_rate = metrics.network.incoming.packet_rate vdu_metrics.network.incoming.bytes = metrics.network.incoming.bytes vdu_metrics.network.incoming.byte_rate = metrics.network.incoming.byte_rate # Network (outgoing) vdu_metrics.network.outgoing.packets = metrics.network.outgoing.packets vdu_metrics.network.outgoing.packet_rate = metrics.network.outgoing.packet_rate vdu_metrics.network.outgoing.bytes = metrics.network.outgoing.bytes vdu_metrics.network.outgoing.byte_rate = metrics.network.outgoing.byte_rate # External ports vdu_metrics.external_ports.total = 5 # Internal ports vdu_metrics.internal_ports.total = 5 return vdu_metrics except Exception as e: log.exception(e)
def test_complete(self): """ This test simulates the addition of a VNFR to the Monitor (along with updates), and retrieves NFVI metrics from the VDUR. The VNFR is then deleted, which should result in a cleanup of all the data in the Monitor. """ # Create the VNFR vnfr = RwVnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr() vnfr.cloud_account = self.account.name vnfr.id = 'test-vnfr-id' # Create 2 VDURs vdur = vnfr.vdur.add() vdur.id = 'test-vdur-id-1' vdur.vim_id = 'test-vim-id-1' vdur.vm_flavor.vcpu_count = 4 vdur.vm_flavor.memory_mb = 100 vdur.vm_flavor.storage_gb = 2 vdur = vnfr.vdur.add() vdur.id = 'test-vdur-id-2' vdur.vim_id = 'test-vim-id-2' vdur.vm_flavor.vcpu_count = 4 vdur.vm_flavor.memory_mb = 100 vdur.vm_flavor.storage_gb = 2 class MockPlugin(object): def __init__(self): self._metrics = dict() self._metrics['test-vim-id-1'] = RwmonYang.NfviMetrics() self._metrics['test-vim-id-2'] = RwmonYang.NfviMetrics() def nfvi_metrics(self, account, vim_id): metrics = self._metrics[vim_id] if vim_id == 'test-vim-id-1': metrics.memory.used += 1000 else: metrics.memory.used += 2000 return metrics class MockFactory(PluginFactory): PLUGIN_NAME = "mock" def create(self, cloud_account): plugin = rw_peas.PeasPlugin("rwmon_mock", 'RwMon-1.0') impl = plugin.get_interface("Monitoring") impl.set_impl(MockPlugin()) return impl # Modify the mock plugin factory self.monitor._nfvi_plugins._factories["mock"] = MockFactory() # Add the cloud account the monitor self.monitor.add_cloud_account(self.account) # Add the VNFR to the monitor. self.monitor.add_vnfr(vnfr) @wait_for_pending_tasks(self.loop) @asyncio.coroutine def call1(): # call #1 (time = 0.00s) # The metrics for these VDURs have not been populated yet so a # default metrics object (all zeros) is returned, and a request is # scheduled with the data source to retrieve the metrics. metrics1 = self.monitor.retrieve_nfvi_metrics('test-vdur-id-1') metrics2 = self.monitor.retrieve_nfvi_metrics('test-vdur-id-2') self.assertEqual(0, metrics1.memory.used) self.assertEqual(0, metrics2.memory.used) self.loop.run_until_complete(call1()) @wait_for_pending_tasks(self.loop) @asyncio.coroutine def call2(): # call #2 (wait 0.05s) # The metrics have been populated with data from the data source # due to the request made during call #1. yield from asyncio.sleep(0.05) metrics1 = self.monitor.retrieve_nfvi_metrics('test-vdur-id-1') metrics2 = self.monitor.retrieve_nfvi_metrics('test-vdur-id-2') self.assertEqual(1000, metrics1.memory.used) self.assertEqual(2000, metrics2.memory.used) self.loop.run_until_complete(call2()) @wait_for_pending_tasks(self.loop) @asyncio.coroutine def call3(): # call #3 (wait 0.50s) # This call exceeds 0.1s (the sample interval of the plugin) # from when the data was retrieved. The cached metrics are # immediately returned, but a request is made to the data source to # refresh these metrics. yield from asyncio.sleep(0.10) metrics1 = self.monitor.retrieve_nfvi_metrics('test-vdur-id-1') metrics2 = self.monitor.retrieve_nfvi_metrics('test-vdur-id-2') self.assertEqual(1000, metrics1.memory.used) self.assertEqual(2000, metrics2.memory.used) self.loop.run_until_complete(call3()) @wait_for_pending_tasks(self.loop) @asyncio.coroutine def call4(): # call #4 (wait 1.00s) # The metrics retrieved differ from those in call #3 because the # cached metrics have been updated. yield from asyncio.sleep(0.10) metrics1 = self.monitor.retrieve_nfvi_metrics('test-vdur-id-1') metrics2 = self.monitor.retrieve_nfvi_metrics('test-vdur-id-2') self.assertEqual(2000, metrics1.memory.used) self.assertEqual(4000, metrics2.memory.used) self.loop.run_until_complete(call4())
def nfvi_metrics(self, account, vim_id): metrics = RwVnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr_Vdur_NfviMetrics( ) metrics.vcpu.utilization = 0.5 return None, metrics
def __init__(self, *args, **kwargs): super(RwLogTestTasklet, self).__init__(*args, **kwargs) self._dts = None self.rwlog.set_category("rw-logtest-log") self._metrics = RwVnfrYang.YangData_Vnfr_VnfrCatalog_Vnfr_Vdur_NfviMetrics( )
def configure_schema(cls): return RwVnfrYang.get_schema()