def fix_no_nat_l3out_ownership(aim_ctx): """Relinquish ownership of no-NAT L3Outs in AIM and APIC.""" saved_l3out_table = sa.Table( 'aim_lib_save_l3out', sa.MetaData(), sa.Column('tenant_name', sa.String(), primary_key=True), sa.Column('name', sa.String(), primary_key=True), sa.Column('monitored', nullable=True), sa.Column('vrf_name', nullable=True)) session = aim_ctx.store.db_session bind = session.get_bind() with session.begin(subtransactions=True): if not saved_l3out_table.exists(bind=bind): return results = session.execute( saved_l3out_table.select(saved_l3out_table.c.monitored.is_(True))) click.echo("Fixing ownership of no-NAT L3Outs") rows = results.fetchall() if rows: cfg_mgr = config.ConfigManager(aim_ctx) system_id = cfg_mgr.get_option('aim_system_id', 'aim') aim_mgr = aim_manager.AimManager() apic = aci_universe.AciUniverse.establish_aci_session(cfg_mgr) for row in rows: l3out = resource.L3Outside(tenant_name=row['tenant_name'], name=row['name']) aim_mgr.update(aim_ctx, l3out, monitored=True) tag_dn = "/mo/" + l3out.dn + "/tag-" + system_id click.echo('Deleting AIM tag %s' % tag_dn) apic.DELETE(tag_dn + ".json") # drop the table after the transaction completes because databases # like MySQL hold locks on the table saved_l3out_table.drop(bind=bind)
def test_poll_and_execute(self): cfg_mgr = config.ConfigManager(self.ctx, 'h1') callback = mock.Mock() # Subscribe to apic hosts cfg_mgr.get_option_and_subscribe(callback, 'apic_hosts', 'apic') # Polling will have no effect at this time, since apic_hosts hasn't # changed cfg_mgr.subs_mgr._poll_and_execute() self.assertFalse(callback.called) # Update apic hosts self.set_override('apic_hosts', ['2.2.2.2'], 'apic') cfg_mgr.subs_mgr._poll_and_execute() callback.assert_called_once_with({ 'key': 'apic_hosts', 'host': '', 'group': 'apic', 'value': ['2.2.2.2'], 'version': mock.ANY }) # Reset mock and verify that the call doesn't happen again callback.reset_mock() cfg_mgr.subs_mgr._poll_and_execute() self.assertFalse(callback.called)
def setUp(self, universe_klass=None): super(TestAciUniverseMixin, self).setUp() self._do_aci_mocks() self.backend_state = {} self.universe = (universe_klass or aci_universe.AciUniverse)().initialize( aim_cfg.ConfigManager(self.ctx, 'h1'), []) self.universe.get_relevant_state_for_read = mock.Mock( return_value=[self.backend_state]) # Mock ACI tenant manager self.mock_start = mock.patch( 'aim.agent.aid.universes.aci.tenant.AciTenantManager.start') self.mock_start.start() self.mock_is_dead = mock.patch( 'aim.agent.aid.universes.aci.tenant.AciTenantManager.is_dead', return_value=False) self.mock_is_dead.start() self.mock_is_warm = mock.patch( 'aim.agent.aid.universes.aci.tenant.AciTenantManager.is_warm', return_value=True) self.mock_is_warm.start() aci_tenant.AciTenantManager.kill = _kill_thread self.addCleanup(self.mock_start.stop) self.addCleanup(self.mock_is_dead.stop) self.addCleanup(self.mock_is_warm.stop)
def setUp(self, klass=aim_universe.AimDbUniverse): super(TestAimDbUniverseBase, self).setUp() self.klass = klass self.universe = self.klass().initialize( aim_cfg.ConfigManager(self.ctx, ''), []) self.tree_mgr = tree_manager.HashTreeManager() self.monitor_universe = False
def __init__(self, conf): self.run_daemon_loop = True self.host = conf.aim.aim_service_identifier aim_ctx = context.AimContext(store=api.get_store()) # This config manager is shared between multiple threads. Therefore # all DB activity through this config manager will use the same # DB session which can result in conflicts. # TODO(amitbose) Fix ConfigManager to not use cached AimContext self.conf_manager = aim_cfg.ConfigManager(aim_ctx, self.host) self.k8s_watcher = None self.single_aid = False if conf.aim.aim_store == 'k8s': self.single_aid = True self.k8s_watcher = k8s_watcher.K8sWatcher() self.k8s_watcher.run() self.multiverse = [] # Define multiverse pairs, First position is desired state self.multiverse += [ # Configuration Universe (AIM to ACI) {DESIRED: aim_universe.AimDbUniverse().initialize( self.conf_manager, self.multiverse), CURRENT: aci_universe.AciUniverse().initialize( self.conf_manager, self.multiverse)}, # Operational Universe (ACI to AIM) {DESIRED: aci_universe.AciOperationalUniverse().initialize( self.conf_manager, self.multiverse), CURRENT: aim_universe.AimDbOperationalUniverse().initialize( self.conf_manager, self.multiverse)}, # Monitored Universe (ACI to AIM) {DESIRED: aci_universe.AciMonitoredUniverse().initialize( self.conf_manager, self.multiverse), CURRENT: aim_universe.AimDbMonitoredUniverse().initialize( self.conf_manager, self.multiverse)}, ] # Operational Universes. ACI operational info will be synchronized into # AIM's self.manager = aim_manager.AimManager() self.tree_manager = tree_manager.HashTreeManager() self.agent_id = 'aid-%s' % self.host self.agent = resource.Agent(id=self.agent_id, agent_type=AGENT_TYPE, host=self.host, binary_file=AGENT_BINARY, description=AGENT_DESCRIPTION, version=AGENT_VERSION) # Register agent self.agent = self.manager.create(aim_ctx, self.agent, overwrite=True) # Report procedure should happen asynchronously self.polling_interval = self.conf_manager.get_option_and_subscribe( self._change_polling_interval, 'agent_polling_interval', group='aim') self.report_interval = self.conf_manager.get_option_and_subscribe( self._change_report_interval, 'agent_report_interval', group='aim') self.squash_time = self.conf_manager.get_option_and_subscribe( self._change_squash_time, 'agent_event_squash_time', group='aim') self._spawn_heartbeat_loop() self.events = event_handler.EventHandler().initialize( self.conf_manager) self.max_down_time = 4 * self.report_interval
def __init__(self, conf): self.host = aim_cfg.CONF.aim.aim_service_identifier self.context = context.AimContext(store=api.get_store()) self.conf_manager = aim_cfg.ConfigManager(self.context, self.host) # TODO(ivar): heartbeat for these services? self.sender = event_handler.EventSender() self.sender.initialize(self.conf_manager) self.run_daemon_loop = True
def setUp(self, initialize_hooks=True): super(TestAimDBBase, self).setUp() self.test_id = uuidutils.generate_uuid() aim_cfg.OPTION_SUBSCRIBER_MANAGER = None aci_universe.ws_context = None if not os.environ.get(K8S_STORE_VENV): CONF.set_override('aim_store', 'sql', 'aim') self.engine = api.get_engine() if not TestAimDBBase._TABLES_ESTABLISHED: model_base.Base.metadata.create_all(self.engine) TestAimDBBase._TABLES_ESTABLISHED = True # Uncomment the line below to log SQL statements. Additionally, to # log results of queries, change INFO to DEBUG # # logging.getLogger('sqlalchemy.engine').setLevel(logging.DEBUG) def clear_tables(): with self.engine.begin() as conn: for table in reversed( model_base.Base.metadata.sorted_tables): conn.execute(table.delete()) self.addCleanup(clear_tables) self.old_add_commit_hook = ( aim_store.SqlAlchemyStore.add_commit_hook) aim_store.SqlAlchemyStore.add_commit_hook = _add_commit_hook def restore_commit_hook(): aim_store.SqlAlchemyStore.add_commit_hook = ( self.old_add_commit_hook) self.addCleanup(restore_commit_hook) aim_store.SqlAlchemyStore._after_transaction_end_2 = ( _after_transaction_end_2) else: CONF.set_override('aim_store', 'k8s', 'aim') CONF.set_override('k8s_namespace', self.test_id, 'aim_k8s') k8s_config_path = os.environ.get(K8S_CONFIG_ENV) if k8s_config_path: CONF.set_override('k8s_config_path', k8s_config_path, 'aim_k8s') aim_store.K8sStore._post_delete = _k8s_post_delete aim_store.K8sStore._post_create = _k8s_post_create global k8s_watcher_instance k8s_watcher_instance = k8s_watcher.K8sWatcher() k8s_watcher_instance.event_handler = mock.Mock() k8s_watcher_instance._renew_klient_watch = mock.Mock() self.addCleanup(self._cleanup_objects) self.store = api.get_store(expire_on_commit=True, initialize_hooks=initialize_hooks) self.ctx = context.AimContext(store=self.store) self.cfg_manager = aim_cfg.ConfigManager(self.ctx, '') self.tt_mgr = tree_manager.HashTreeManager() resource.ResourceBase.__eq__ = resource_equal self.cfg_manager.replace_all(CONF) self.sys_id = self.cfg_manager.get_option('aim_system_id', 'aim')
def test_poll_and_execute_exception(self): cfg_mgr = config.ConfigManager(self.ctx, 'h1') callback = mock.Mock(side_effect=Exception('expected exception')) cfg_mgr.get_option_and_subscribe(callback, 'apic_hosts', 'apic') self.set_override('apic_hosts', ['2.2.2.2'], 'apic') # Doesn't rise cfg_mgr.subs_mgr._poll_and_execute()
def test_polling_interval_changed(self): self._clean_subscriptions() cfg_mgr = config.ConfigManager(self.ctx, 'h1') # Call property before changing the config value cfg_mgr.subs_mgr.polling_interval self.set_override('config_polling_interval', 130, 'aim') self.assertNotEqual(130, cfg_mgr.subs_mgr.polling_interval) cfg_mgr.subs_mgr._poll_and_execute() self.assertEqual(130, cfg_mgr.subs_mgr.polling_interval)
def test_shared_served_tenants(self): operational = aci_universe.AciOperationalUniverse().initialize( aim_cfg.ConfigManager(self.ctx, ''), []) tenant_list = ['tn-%s' % x for x in range(10)] self.universe.serve(self.ctx, tenant_list) self.assertIs(self.universe.serving_tenants, operational.serving_tenants) for key, value in self.universe.serving_tenants.iteritems(): self.assertIs(operational.serving_tenants[key], value)
def test_config_multiple_hosts_same_item_fails(self): cfg_mgr = config.ConfigManager(self.ctx, 'h1') callback = mock.Mock() cfg_mgr.get_option_and_subscribe(callback, 'apic_hosts', 'apic') self.assertRaises(exc.OneHostPerCallbackItemSubscriptionAllowed, cfg_mgr.get_option_and_subscribe, callback, 'apic_hosts', 'apic', host='h2')
def test_config_subscribe_noop_no_host(self): # Subscription fails if no host is specified cfg_mgr = config.ConfigManager(self.ctx) # Clean current map state for testing cfg_mgr.subs_mgr.map_by_callback_id = {} cfg_mgr.subs_mgr.subscription_map = {} self.cfg_mgr.get_option_and_subscribe(mock.Mock(), 'apic_hosts', 'apic') self.assertEqual({}, cfg_mgr.subs_mgr.subscription_map) self.assertEqual({}, cfg_mgr.subs_mgr.map_by_callback_id)
def setUp(self): super(TestAciTenant, self).setUp() self._do_aci_mocks() self.backend_state = {} universe = aci_universe.AciUniverse().initialize( aim_cfg.ConfigManager(self.ctx, 'h1'), []) self.manager = aci_tenant.AciTenantManager( 'tn-tenant-1', self.cfg_manager, aci_universe.AciUniverse.establish_aci_session(self.cfg_manager), aci_universe.get_websocket_context(self.cfg_manager), get_resources=universe.get_resources) self.manager._get_full_state = mock.Mock( return_value=[self.backend_state])
def test_ws_config_changed(self): # Refresh subscriptions self.universe.ws_context = aci_universe.WebSocketContext( aim_cfg.ConfigManager(self.ctx, 'h1')) current_ws = self.universe.ws_context.session self.set_override('apic_hosts', ['3.1.1.1'], 'apic', poll=True) # Callback modified parameters self.assertTrue(current_ws is not self.universe.ws_context.session) self.assertEqual(['3.1.1.1'], self.universe.ws_context.apic_hosts) self.assertTrue('3.1.1.1' in self.universe.ws_context.session.api) # Change again to same value, there'll be no effect current_ws = self.universe.ws_context.session self.set_override('apic_hosts', ['3.1.1.1'], 'apic') self.assertTrue(current_ws is self.universe.ws_context.session)
def setUp(self): super(TestDBConfig, self).setUp() self.manager = config.ConfigManager(self.ctx, '')
def test_subscriber_singleton(self): cfg_mgr1 = config.ConfigManager(self.ctx, 'h1') cfg_mgr2 = config.ConfigManager(self.ctx, 'h2') self.assertTrue(cfg_mgr1 is not cfg_mgr2) self.assertTrue(cfg_mgr1.subs_mgr is cfg_mgr2.subs_mgr)
def config(ctx): aim_ctx = context.AimContext(store=api.get_store(expire_on_commit=True)) ctx.obj['manager'] = aim_cfg.ConfigManager(aim_ctx, '')
def test_config_subscribe(self): # Get a manager with a host cfg_mgr = config.ConfigManager(self.ctx, 'h1') # Clean current map state for testing cfg_mgr.subs_mgr.map_by_callback_id = {} cfg_mgr.subs_mgr.subscription_map = {} callback = mock.Mock() call_id = cfg_mgr.subs_mgr._get_call_id(callback) expected = { 'apic': { 'apic_hosts': { call_id: { 'hosts': set(['h1']), 'version': mock.ANY, 'callback': callback } } } } expected_rev = {call_id: {'apic': set(['apic_hosts'])}} cfg_mgr.get_option_and_subscribe(callback, 'apic_hosts', 'apic') self.assertEqual(expected, cfg_mgr.subs_mgr.subscription_map) self.assertEqual(expected_rev, cfg_mgr.subs_mgr.map_by_callback_id) # Same callback cfg_mgr.get_option_and_subscribe(callback, 'aim_system_id', 'aim') expected.update({ 'aim': { 'aim_system_id': { call_id: { 'hosts': set(['h1']), 'version': mock.ANY, 'callback': callback } } } }) expected_rev[call_id].update({'aim': set(['aim_system_id'])}) self.assertEqual(expected, cfg_mgr.subs_mgr.subscription_map) self.assertEqual(expected_rev, cfg_mgr.subs_mgr.map_by_callback_id) # Different callback on same option callback_2 = mock.Mock() call_id_2 = cfg_mgr.subs_mgr._get_call_id(callback_2) cfg_mgr.get_option_and_subscribe(callback_2, 'aim_system_id', 'aim') expected['aim']['aim_system_id'].update({ call_id_2: { 'hosts': set(['h1']), 'version': mock.ANY, 'callback': callback_2 } }) expected_rev.update({call_id_2: {'aim': set(['aim_system_id'])}}) self.assertEqual(expected, cfg_mgr.subs_mgr.subscription_map) self.assertEqual(expected_rev, cfg_mgr.subs_mgr.map_by_callback_id) # Remove specific option cfg_mgr.option_unsubscribe(callback, 'apic_hosts', 'apic') # This will remove the apic group completely expected.pop('apic') expected_rev[call_id].pop('apic') self.assertEqual(expected, cfg_mgr.subs_mgr.subscription_map) self.assertEqual(expected_rev, cfg_mgr.subs_mgr.map_by_callback_id) # Now unsubscribe an entire callback cfg_mgr.callback_unsubscribe(callback_2) # This removed the callback from both maps expected_rev.pop(call_id_2) expected['aim']['aim_system_id'].pop(call_id_2) self.assertEqual(expected, cfg_mgr.subs_mgr.subscription_map) self.assertEqual(expected_rev, cfg_mgr.subs_mgr.map_by_callback_id) # Unsubscribe last option cfg_mgr.option_unsubscribe(callback, 'aim_system_id', 'aim') # Maps are now empty self.assertEqual({}, cfg_mgr.subs_mgr.subscription_map) self.assertEqual({}, cfg_mgr.subs_mgr.map_by_callback_id)