def test_existing_resource_of_many(self): sms = {} for resource_id in ['5678', 'ABCD', 'EFGH']: r = event.Resource( tenant_id=self.tenant_id, id=resource_id, driver=router.Router.RESOURCE_NAME, ) msg = event.Event( resource=r, crud=event.CREATE, body={'key': 'value'}, ) # First time creates... sm1 = self.trm.get_state_machines(msg, self.ctx)[0] sms[resource_id] = sm1 # Second time should return the same objects... r = event.Resource( id='5678', tenant_id=self.tenant_id, driver=router.Router.RESOURCE_NAME, ) msg = event.Event( resource=r, crud=event.CREATE, body={'key': 'value'}, ) sm2 = self.trm.get_state_machines(msg, self.ctx)[0] self.assertIs(sm2, sms['5678'])
def test_all_resources(self): for i in range(5): rid = str(uuid.uuid4()) driver = fakes.fake_driver(rid) sm = state.Automaton(driver=driver, worker_context=self.ctx, resource_id=driver.id, tenant_id=self.tenant_id, delete_callback=None, bandwidth_callback=None, queue_warning_threshold=5, reboot_error_threshold=5) self.trm.state_machines[rid] = sm r = event.Resource( tenant_id=self.tenant_id, id='*', driver=router.Router.RESOURCE_NAME, ) msg = event.Event( resource=r, crud=event.CREATE, body={'key': 'value'}, ) sms = self.trm.get_state_machines(msg, self.ctx) self.assertEqual(5, len(sms))
def router_deleted(self, ctxt, router_id): tenant_id = _get_tenant_id_for_message(ctxt) resource = event.Resource('router', router_id, tenant_id) crud = event.DELETE e = event.Event(resource, crud, None) self.notification_queue.put((e.resource.tenant_id, e))
def test_process_notification_router_delete(self): payload = {'router_id': 'fake_router_id'} r = event.Resource( driver=router.Router.RESOURCE_NAME, id='fake_router_id', tenant_id='fake_tenant_id') e = event.Event( resource=r, crud=event.DELETE, body=payload, ) self._test_notification('router.delete.end', payload, e)
def test_process_notification_arbitrary_end_event(self): payload = {'router': {'id': 'fake_router_id'}} r = event.Resource( driver=router.Router.RESOURCE_NAME, id='fake_router_id', tenant_id='fake_tenant_id') e = event.Event( resource=r, crud=event.UPDATE, body=payload, ) self._test_notification('foo.bar.end', payload, e)
def test_get_state_machine_no_resoruce_id(self): r = event.Resource( tenant_id=self.tenant_id, id=None, driver=router.Router.RESOURCE_NAME, ) msg = event.Event( resource=r, crud=event.CREATE, body={'key': 'value'}, ) self.assertRaises(tenant.InvalidIncomingMessage, self.trm.get_state_machines, msg, self.ctx)
def test__should_process_no_router_id_no_router_found(self): self.fake_cache.get_by_tenant.return_value = None r = event.Resource( driver=router.Router.RESOURCE_NAME, id=None, tenant_id='fake_tenant_id', ) msg = event.Event( resource=r, crud=event.CREATE, body={'key': 'value'}, ) self.assertFalse(self.w._should_process(msg))
def test_process_notification_interesting_notifications(self): for notification in router._ROUTER_INTERESTING_NOTIFICATIONS: payload = {'router': {'id': 'fake_router_id'}} r = event.Resource( driver=router.Router.RESOURCE_NAME, id='fake_router_id', tenant_id='fake_tenant_id') e = event.Event( resource=r, crud=event.UPDATE, body=payload, ) self._test_notification(notification, payload, e)
def test_new_resource(self): r = event.Resource( tenant_id=self.tenant_id, id='5678', driver=router.Router.RESOURCE_NAME, ) msg = event.Event( resource=r, crud=event.CREATE, body={'key': 'value'}, ) sm = self.trm.get_state_machines(msg, self.ctx)[0] self.assertEqual(sm.resource_id, '5678') self.assertIn('5678', self.trm.state_machines)
def test_deleter_callback(self): r = event.Resource( tenant_id='1234', id='5678', driver=router.Router.RESOURCE_NAME, ) msg = event.Event( resource=r, crud=event.CREATE, body={'key': 'value'}, ) sm = self.trm.get_state_machines(msg, self.ctx)[0] self.assertIn('5678', self.trm.state_machines) sm._do_delete() self.assertNotIn('5678', self.trm.state_machines)
def setUp(self): super(TestWorker, self).setUp() self.target = self.tenant_id self.resource = event.Resource( self.driver, self.resource_id, self.tenant_id) self.msg = event.Event( resource=self.resource, crud=event.CREATE, body={'key': 'value'}, ) self.fake_cache = worker.TenantResourceCache() self.fake_cache.get_by_tenant = mock.MagicMock() self.w.resource_cache = self.fake_cache
def test__should_process_no_router_id(self): self.fake_cache.get_by_tenant.return_value = ( '9846d012-3c75-11e5-b476-8321b3ff1a1d') r = event.Resource( driver=router.Router.RESOURCE_NAME, id=None, tenant_id='fake_tenant_id', ) expected_r = event.Resource( driver=router.Router.RESOURCE_NAME, id='9846d012-3c75-11e5-b476-8321b3ff1a1d', tenant_id='fake_tenant_id', ) msg = event.Event( resource=r, crud=event.CREATE, body={'key': 'value'}, ) expected = event.Event( resource=expected_r, crud=event.CREATE, body={'key': 'value'}, ) self.assertEquals(expected, self.w._should_process(msg))
def setUp(self): super(TestCreatingResource, self).setUp() self.tenant_id = '98dd9c41-d3ac-4fd6-8927-567afa0b8fc3' self.router_id = 'ac194fc5-f317-412e-8611-fb290629f624' self.hostname = 'akanda' self.resource = event.Resource(router.Router.RESOURCE_NAME, self.router_id, self.tenant_id) self.msg = event.Event( resource=self.resource, crud=event.CREATE, body={'key': 'value'}, ) self.w._should_process_message = mock.MagicMock(return_value=self.msg)
def test_resource_cache_hit(self): self.resource_cache._tenant_resources = { router.Router.RESOURCE_NAME: { 'fake_tenant_id': 'fake_cached_resource_id', } } r = event.Resource( tenant_id='fake_tenant_id', id='fake_resource_id', driver=router.Router.RESOURCE_NAME, ) msg = event.Event(resource=r, crud=event.UPDATE, body={}) res = self.resource_cache.get_by_tenant( resource=r, worker_context=self.worker_context, message=msg) self.assertEqual(res, 'fake_cached_resource_id') self.assertFalse(self.w._context.neutron.get_router_for_tenant.called)
def test_existing_resource(self): r = event.Resource( tenant_id=self.tenant_id, id='5678', driver=router.Router.RESOURCE_NAME, ) msg = event.Event( resource=r, crud=event.CREATE, body={'key': 'value'}, ) # First time creates... sm1 = self.trm.get_state_machines(msg, self.ctx)[0] # Second time should return the same objects... sm2 = self.trm.get_state_machines(msg, self.ctx)[0] self.assertIs(sm1, sm2) self.assertIs(sm1._queue, sm2._queue)
def process_notification(tenant_id, event_type, payload): """Process an incoming notification event This gets called from the notifications layer to determine whether this driver should process an incoming notification event. It is responsible for translating an incoming notificatino to an Event object appropriate for this driver. :param tenant_id: str The UUID tenant_id for the incoming event :param event_type: str event type, for example router.create.end :param payload: The payload body of the incoming event :returns: A populated Event objet if it should process, or None if not """ router_id = payload.get('router', {}).get('id') crud = event.UPDATE if event_type.startswith('routerstatus.update'): # We generate these events ourself, so ignore them. return if event_type == 'router.create.end': crud = event.CREATE elif event_type == 'router.delete.end': crud = event.DELETE router_id = payload.get('router_id') elif event_type in _ROUTER_INTERFACE_NOTIFICATIONS: crud = event.UPDATE router_id = payload.get('router.interface', {}).get('id') elif event_type in _ROUTER_INTERESTING_NOTIFICATIONS: crud = event.UPDATE elif event_type.endswith('.end'): crud = event.UPDATE else: LOG.debug('Not processing event: %s' % event_type) return resource = event.Resource(driver=DRIVER_NAME, id=router_id, tenant_id=tenant_id) e = event.Event( resource=resource, crud=crud, body=payload, ) return e
def test_resource_cache_miss(self): r = event.Resource( tenant_id='fake_tenant_id', id='fake_fetched_resource_id', driver=router.Router.RESOURCE_NAME, ) msg = event.Event( resource=r, crud=event.UPDATE, body={}, ) res = self.resource_cache.get_by_tenant( resource=r, worker_context=self.worker_context, message=msg) self.assertEqual(res, 'fake_fetched_resource_id') self.w._context.neutron.get_router_for_tenant.assert_called_with( 'fake_tenant_id')
def test_no_update_deleted_resource(self): self.trm._default_resource_id = 'abcd' self.trm.state_machines['5678'] = mock.Mock() self.trm._delete_resource('5678') self.assertEqual(self.trm.state_machines.values(), []) r = event.Resource( tenant_id='1234', id='5678', driver=router.Router.RESOURCE_NAME, ) msg = event.Event( resource=r, crud=event.CREATE, body={'key': 'value'}, ) sms = self.trm.get_state_machines(msg, self.ctx) self.assertEqual(sms, []) self.assertIn('5678', self.trm.state_machines.deleted)
def test_health_inspector(self, fake_sleep): fake_scheduler = mock.Mock(handle_message=mock.Mock()) # raise the exception to break out of the while loop. fake_scheduler.handle_message.side_effect = BreakLoop() try: health._health_inspector(fake_scheduler) except BreakLoop: pass exp_res = event.Resource( id='*', tenant_id='*', driver='*', ) exp_event = event.Event( resource=exp_res, crud=event.POLL, body={}, ) fake_scheduler.handle_message.assert_called_with('*', exp_event)
def test_errored_routers(self): self.trm.state_machines.state_machines = {} for i in range(5): rid = str(uuid.uuid4()) driver = fakes.fake_driver(rid) sm = state.Automaton(driver=driver, worker_context=self.ctx, resource_id=i, tenant_id=self.tenant_id, delete_callback=None, bandwidth_callback=None, queue_warning_threshold=5, reboot_error_threshold=5) self.trm.state_machines[rid] = sm # Replace the default mock with one that has 'state' set. if i == 2: status = states.ERROR else: status = states.UP sm.instance = mock.Mock(state=status) self.trm.state_machines.state_machines[str(i)] = sm r = event.Resource( tenant_id=self.tenant_id, id='2', driver=router.Router.RESOURCE_NAME, ) msg = event.Event( resource=r, crud=event.CREATE, body={'key': 'value'}, ) sms = self.trm.get_state_machines(msg, self.ctx) self.assertEqual(1, len(sms)) self.assertEqual(2, sms[0].resource_id) self.assertIs(self.trm.state_machines.state_machines['2'], sms[0])
def test_pre_populate_retry_loop_logging( self, mocked_neutron_api, log_debug, log_warning): neutron_client = mock.Mock() message = mock.Mock(tenant_id='1', id='2') returned_value = [ neutron_exceptions.NeutronClientException, [message] ] neutron_client.get_routers.side_effect = returned_value mocked_neutron_api.return_value = neutron_client rtr = self._init_driver() with mock.patch('time.sleep'): res = rtr.pre_populate_hook() self.assertEqual(2, log_warning.call_count) expected_resource = event.Resource( driver=rtr.RESOURCE_NAME, id='2', tenant_id='1', ) self.assertEqual(res, [expected_resource])
def info(self, ctxt, publisher_id, event_type, payload, metadata): tenant_id = _get_tenant_id_for_message(ctxt, payload) crud = event.UPDATE e = None events = [] if event_type.startswith('akanda.rug.command'): LOG.debug('received a command: %r', payload) crud = event.COMMAND if payload.get('command') == commands.POLL: e = event.Event(resource='*', crud=event.POLL, body={}) self.notification_queue.put(('*', e)) return else: # If the message does not specify a tenant, send it to everyone tenant_id = payload.get('tenant_id', '*') router_id = payload.get('router_id') resource = event.Resource(driver='*', id=router_id, tenant_id=tenant_id) events.append(event.Event(resource, crud, payload)) else: for driver in drivers.enabled_drivers(): driver_event = driver.process_notification( tenant_id, event_type, payload) if driver_event: events.append(driver_event) if not events: LOG.debug('Could not construct any events from %s /w payload: %s', event_type, payload) return LOG.debug('Generated %s events from %s /w payload: %s', len(events), event_type, payload) for e in events: self.notification_queue.put((e.resource.tenant_id, e))
def pre_populate_hook(): """Fetch the existing routers from neutrom then and returns list back to populate to be distributed to workers. Wait for neutron to return the list of the existing routers. Pause up to max_sleep seconds between each attempt and ignore neutron client exceptions. """ nap_time = 1 max_sleep = 15 neutron_client = neutron.Neutron(cfg.CONF) while True: try: neutron_routers = neutron_client.get_routers(detailed=False) resources = [] for router in neutron_routers: resources.append( event.Resource(driver=DRIVER_NAME, id=router.id, tenant_id=router.tenant_id)) return resources except (q_exceptions.Unauthorized, q_exceptions.Forbidden) as err: LOG.warning(_LW('PrePopulateWorkers thread failed: %s'), err) return except Exception as err: LOG.warning(_LW('Could not fetch routers from neutron: %s'), err) LOG.warning(_LW('sleeping %s seconds before retrying'), nap_time) time.sleep(nap_time) # FIXME(rods): should we get max_sleep from the config file? nap_time = min(nap_time * 2, max_sleep)