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 setUp(self): super(TestWildcardMessages, self).setUp() self.tenant_id_1 = 'a8f964d4-6631-11e5-a79f-525400cfc32a' self.tenant_id_2 = 'ef1a6e90-6631-11e5-83cb-525400cfc326' self.w._should_process_message = mock.MagicMock(return_value=self.msg) # Create some tenants for msg in [ event.Event( resource=event.Resource( driver=router.Router.RESOURCE_NAME, id='ABCD', tenant_id=self.tenant_id_1, ), crud=event.CREATE, body={'key': 'value'}, ), event.Event( resource=event.Resource(driver=router.Router.RESOURCE_NAME, id='EFGH', tenant_id=self.tenant_id_2), crud=event.CREATE, body={'key': 'value'}, ) ]: self.w.handle_message(msg.resource.tenant_id, msg)
def test__should_process_no_router_id(self, fake_hash): fake_ring_manager = fake_hash.HashRingManager() fake_ring_manager.ring.get_hosts.return_value = [self.w.host] self.w.hash_ring_mgr = fake_ring_manager 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.assertEqual(expected, self.w._should_process_message(self.target, msg))
def pre_populate_hook(): """Fetch the existing LBs from neutron then and returns list back to populate to be distributed to workers. Wait for neutron to return the list of the existing LBs. Pause up to max_sleep seconds between each attempt and ignore neutron client exceptions. """ nap_time = 1 neutron_client = neutron.Neutron(cfg.CONF) while True: try: resources = [] for lb in neutron_client.get_loadbalancers(): resources.append( event.Resource(driver=LoadBalancer.RESOURCE_NAME, id=lb.id, tenant_id=lb.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 loadbalancers from neutron: %s'), err) LOG.warning(_LW('sleeping %s seconds before retrying'), nap_time) time.sleep(nap_time) nap_time = min(nap_time * 2, cfg.CONF.astara_appliance.max_sleep)
def test__repopulate_sm_added(self, fake_repopulate): fake_ring = mock.Mock(get_hosts=mock.Mock()) fake_hash = mock.Mock(ring=fake_ring) self.w.hash_ring_mgr = fake_hash rsc1 = event.Resource( driver='router', tenant_id='79f418c8-a849-11e5-9c36-df27538e1b7e', id='7f2a1d56-a849-11e5-a0ce-a74ef0b18fa1', ) rsc2 = event.Resource( driver='router', tenant_id='8d55fdb4-a849-11e5-958f-0b870649546d', id='9005cd5a-a849-11e5-a434-27c4c7c70a8b', ) rsc3 = event.Resource( driver='router', tenant_id='455549a4-a851-11e5-a060-df26a5877746', id='4a05c758-a851-11e5-bf9f-0387cfcb8f9b', ) resources = [rsc1, rsc2, rsc3] # create initial, pre-rebalance state machines for r in resources[:-1]: for trm in self.w._get_trms(r.tenant_id): e = event.Event(resource=r, crud=None, body={}) trm.get_state_machines(e, self.w._context) fake_hash.ring.get_hosts.side_effect = [ self.fake_host, self.fake_host, self.fake_host ] fake_repopulate.return_value = resources # mock doesn't like to have its .name overwritten? class FakeWorker(object): name = self.w.proc_name tgt = [{'worker': FakeWorker()}] self.w.scheduler.dispatcher.pick_workers = mock.Mock(return_value=tgt) self.w._repopulate() post_rebalance_sms = self.w._get_all_state_machines() self.assertEqual(len(post_rebalance_sms), 3) rids = [r.id for r in resources] for sm in post_rebalance_sms: self.assertIn(sm.resource_id, rids)
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_delete_not_default_resource(self): r = event.Resource(id='1234', tenant_id=self.tenant_id, driver=router.Router.RESOURCE_NAME) self.trm._default_resource_id = 'abcd' self.trm.state_machines['1234'] = mock.Mock() self.trm._delete_resource(r) self.assertEqual('abcd', self.trm._default_resource_id)
def test_delete_default_resource(self): r = event.Resource(id='1234', tenant_id=self.tenant_id, driver=router.Router.RESOURCE_NAME) self.trm._default_resource_id = '1234' self.trm.state_machines['1234'] = mock.Mock() self.trm._delete_resource(r) self.assertNotIn('1234', self.trm.state_machines) self.assertIs(None, self.trm._default_resource_id)
def test_delete_resource(self): r = event.Resource( id='1234', tenant_id=self.tenant_id, driver=router.Router.RESOURCE_NAME, ) self.trm.state_machines['1234'] = mock.Mock() self.trm._delete_resource(r) self.assertNotIn('1234', self.trm.state_machines) self.assertTrue(self.deleter.called)
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 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 loadbalancer.create.end :param payload: The payload body of the incoming event :returns: A populated Event objet if it should process, or None if not """ if event_type.startswith('loadbalancerstatus.update'): # these are generated when we sync state return lb_id = (payload.get('loadbalancer', {}).get('id') or payload.get('listener', {}).get('loadbalancer_id') or payload.get('loadbalancer_id')) update_notifications = [ 'listener.create.start', 'pool.create.start', 'member.create.end', 'member.delete.end', ] # some events do not contain a lb id. if not lb_id and event_type not in update_notifications: return if event_type == 'loadbalancer.create.end': crud = event.CREATE elif event_type == 'loadbalancer.delete.end': crud = event.DELETE elif event_type in update_notifications: crud = event.UPDATE else: crud = None if not crud: LOG.info('Could not determine CRUD for event: %s ', event_type) return resource = event.Resource(driver=LoadBalancer.RESOURCE_NAME, id=lb_id, tenant_id=tenant_id) e = event.Event( resource=resource, crud=crud, body=payload, ) return e
def test_process_notification_lb_delete(self): payload = {'loadbalancer': {'id': 'fake_lb_id'}} r = event.Resource( driver=loadbalancer.LoadBalancer.RESOURCE_NAME, id='fake_lb_id', tenant_id='fake_tenant_id') e = event.Event( resource=r, crud=event.DELETE, body=payload, ) self._test_notification('loadbalancer.delete.end', payload, e)
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_cluster_changed(self, fake_members, fake_start): fake_members.__get__ = mock.Mock(return_value=['foo', 'bar']) self.coordinator = coordination.RugCoordinator(self.queue) expected_rebalance_event = event.Event( resource=event.Resource('*', '*', '*'), crud=event.REBALANCE, body={'members': ['foo', 'bar']}) self.coordinator.cluster_changed(event=None) expected = ('*', expected_rebalance_event) res = self.queue.get() self.assertEqual(res, expected)
def test__should_process_command_debug_config(self): for cmd in [commands.WORKERS_DEBUG, commands.CONFIG_RELOAD]: r = event.Resource( tenant_id=self.tenant_id, id=self.router_id, driver='router', ) msg = event.Event( resource=r, crud=event.COMMAND, body={'command': cmd}, ) self.assertTrue(self.w._should_process_command(msg))
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_message(self.target, msg))
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('astara.command'): LOG.debug('received a command: %r', payload) crud = event.COMMAND if payload.get('command') == commands.POLL: r = event.Resource(driver='*', id='*', tenant_id='*') e = event.Event(resource=r, 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 test_no_update_deleted_resource(self): r = event.Resource( tenant_id='1234', id='5678', driver=router.Router.RESOURCE_NAME, ) self.trm._default_resource_id = 'abcd' self.trm.state_machines['5678'] = mock.Mock() self.trm._delete_resource(r) 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 setUp(self): super(TestRebalance, self).setUp() self.fake_host = 'fake_host' self.w.host = 'fake_host' self.resource_id = '56232034-a852-11e5-854e-035a3632659f' self.tenant_id = '601128de-a852-11e5-a09d-cf6fa26e6e6b' self.resource = event.Resource('router', self.resource_id, self.tenant_id) self.msg = event.Event( resource=self.resource, crud=None, body={'key': 'value'}, )
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 = 'astara' 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_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) self.assertTrue(self.trm.state_machines.has_been_deleted('5678'))
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'}, ) self.fake_load_resource.return_value = fakes.fake_driver( resource_id='5678') 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_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_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_notification_cmd_poll(self): event_type = 'astara.command' payload = {'command': commands.POLL} self.notifications_endpoint.info(ctxt=CTXT, publisher_id='network.astara', event_type=event_type, payload=payload, metadata={}) expected_event = event.Event( resource=event.Resource(driver='*', id='*', tenant_id='*'), crud=event.POLL, body={}, ) tenant, e = self.queue.get() self.assertEqual('*', tenant) self.assertEqual(expected_event, e)
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 cfg.CONF.router.ipsec_vpn and event_type in _VPN_NOTIFICATIONS: 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_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 _health_inspector(scheduler): """Runs in the thread. """ period = CONF.health_check_period while True: time.sleep(period) LOG.debug('waking up') r = event.Resource( id='*', tenant_id='*', driver='*', ) e = event.Event( resource=r, crud=event.POLL, body={}, ) scheduler.handle_message('*', e)
def test_resource_cache_delete(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={}, ) self.resource_cache.get_by_tenant(resource=r, worker_context=self.worker_context, message=msg) self.assertEqual( self.resource_cache._tenant_resources[r.driver][r.tenant_id], r.id) self.resource_cache.delete(r) self.assertNotIn(r.tenant_id, self.resource_cache._tenant_resources[r.driver])