def aim_res_to_nodes(aim_res): result = {} aim_res_dn = AimHashTreeMaker._extract_dn(aim_res) is_error = getattr(aim_res, '_error', False) is_monitored = (getattr(aim_res, 'monitored', False) or getattr(aim_res, 'pre_existing', False)) pending = getattr(aim_res, '_pending', None) to_aci = converter.AimToAciModelConverter() for obj in to_aci.convert([aim_res]): for mo, v in obj.items(): attr = v.get('attributes', {}) dn = attr.pop('dn', None) key = AimHashTreeMaker._build_hash_tree_key_from_dn(dn, mo) if key: attr['_metadata'] = { 'monitored': is_monitored, 'attributes': copy.copy(attr) } if dn != aim_res_dn: attr['_metadata']['related'] = True if pending is not None: attr['_metadata']['pending'] = pending attr['_error'] = is_error result[key] = attr return result
def _objects_transaction_create(self, objs, create=True, tag=None, top_send=True): tag = tag or self.sys_id result = [] for obj in objs: conversion = converter.AimToAciModelConverter().convert([obj]) transaction = apic_client.Transaction(mock.Mock(), top_send=top_send) tags = [] if create: for item in conversion: dn = item.values()[0]['attributes']['dn'] dn += '/tag-%s' % tag tags.append({ "tagInst__%s" % item.keys()[0]: { "attributes": { "dn": dn } } }) for item in conversion + tags: getattr(transaction, item.keys()[0]).add( *self._extract_rns( item.values()[0]['attributes'].pop('dn'), item.keys()[0]), **item.values()[0]['attributes']) result.append(transaction) return result
def _prepare_aim_resource(self, tree, aim_res): result = {} is_error = getattr(aim_res, '_error', False) is_monitored = (getattr(aim_res, 'monitored', False) or getattr(aim_res, 'pre_existing', False)) pending = getattr(aim_res, '_pending', None) to_aci = converter.AimToAciModelConverter() aim_res_dn = AimHashTreeMaker._extract_dn(aim_res) if not aim_res_dn: return result # Remove "related" child-nodes aim_res_key = AimHashTreeMaker._build_hash_tree_key(aim_res) node = tree.find(aim_res_key) if aim_res_key else None self._clean_related(tree, node) for obj in to_aci.convert([aim_res]): for mo, v in obj.iteritems(): attr = v.get('attributes', {}) dn = attr.pop('dn', None) key = AimHashTreeMaker._build_hash_tree_key_from_dn(dn, mo) if key: attr['_metadata'] = { 'monitored': is_monitored, 'attributes': copy.copy(attr) } if dn != aim_res_dn: attr['_metadata']['related'] = True if pending is not None: attr['_metadata']['pending'] = pending attr['_error'] = is_error result[key] = attr return result
def initialize(self, store, conf_mgr, multiverse): super(AimDbUniverse, self).initialize(store, conf_mgr, multiverse) self.tree_manager = tree_manager.HashTreeManager() self.context = context.AimContext(store=store) self._converter = converter.AciToAimModelConverter() self._converter_aim_to_aci = converter.AimToAciModelConverter() self._served_tenants = set() self._monitored_state_update_failures = 0 self._max_monitored_state_update_failures = 5 return self
def test_squash_operations_no_key(self): aim_converter = converter.AimToAciModelConverter() tn = a_res.Tenant(name='tn1', display_name='foo') bd = a_res.BridgeDomain(tenant_name='tn1', name='bd1', display_name='bar') vrf = a_res.VRF(tenant_name='tn1', name='vrf1', display_name='pippo') self.manager.push_aim_resources({'create': [tn, bd]}) self.manager.push_aim_resources( {'delete': aim_converter.convert([vrf])}) self.assertEqual(2, len(self.manager.object_backlog.queue))
def __init__(self, tenant_name, apic_config, apic_session, ws_context, creation_succeeded=None, creation_failed=None, aim_system_id=None, get_resources=None, *args, **kwargs): super(AciTenantManager, self).__init__(*args, **kwargs) LOG.info("Init manager for tenant %s" % tenant_name) self.get_resources = get_resources self.apic_config = apic_config # Each tenant has its own sessions self.aci_session = apic_session self.dn_manager = apic_client.DNManager() self.tenant_name = tenant_name children_mos = get_children_mos(self.aci_session, self.tenant_name) ws_subscription_to = self.apic_config.get_option( 'websocket_subscription_timeout', 'aim') or DEFAULT_WS_TO self.tenant = Root(self.tenant_name, filtered_children=children_mos, rn=self.tenant_name, ws_subscription_to=ws_subscription_to) self._state = structured_tree.StructuredHashTree() self._operational_state = structured_tree.StructuredHashTree() self._monitored_state = structured_tree.StructuredHashTree() self.polling_yield = self.apic_config.get_option( 'aci_tenant_polling_yield', 'aim') self.to_aim_converter = converter.AciToAimModelConverter() self.to_aci_converter = converter.AimToAciModelConverter() self._reset_object_backlog() self.tree_builder = tree_manager.HashTreeBuilder(None) self.tag_name = aim_system_id or self.apic_config.get_option( 'aim_system_id', 'aim') self.tag_set = set() self.failure_log = {} def noop(*args, **kwargs): pass self.creation_succeeded = creation_succeeded or noop self.creation_failed = creation_failed or noop # Warm bit to avoid rushed synchronization before receiving the first # batch of APIC events self._warm = False self.ws_context = ws_context self.recovery_retries = None self.max_retries = 5 self.error_handler = error.APICAPIErrorHandler() # For testing purposes self.num_loop_runs = float('inf')
def initialize(self, conf_mgr, multiverse): super(AimDbUniverse, self).initialize(conf_mgr, multiverse) self.tree_manager = tree_manager.HashTreeManager() self._converter = converter.AciToAimModelConverter() self._converter_aim_to_aci = converter.AimToAciModelConverter() self._served_tenants = set() self._monitored_state_update_failures = 0 self._max_monitored_state_update_failures = 5 self._recovery_interval = conf_mgr.get_option( 'error_state_recovery_interval', 'aim') self.schedule_next_recovery() return self
def test_squash_operations(self): # Craft some objects and push them aim_converter = converter.AimToAciModelConverter() tn = a_res.Tenant(name='tn1', display_name='foo') bd = a_res.BridgeDomain(tenant_name='tn1', name='bd1', display_name='bar') vrf = a_res.VRF(tenant_name='tn1', name='vrf1', display_name='pippo') self.manager.push_aim_resources({ 'create': [tn, bd], 'delete': aim_converter.convert([vrf]) }) self.assertEqual(1, len(self.manager.object_backlog.queue)) old = self.manager.object_backlog.queue[0] # Idempotent self.manager.push_aim_resources({ 'create': [tn, bd], 'delete': aim_converter.convert([vrf]) }) self.assertEqual(1, len(self.manager.object_backlog.queue)) curr = self.manager.object_backlog.queue[0] self.assertEqual(old, curr) # Now replace something bd2 = a_res.BridgeDomain(tenant_name='tn1', name='bd2', display_name='bar') bd = copy.deepcopy(bd) bd.display_name = 'foobar' self.manager.push_aim_resources({'create': [bd2, bd], 'delete': []}) self.assertEqual(2, len(self.manager.object_backlog.queue)) self.assertEqual({ 'create': [bd2], 'delete': [] }, self.manager.object_backlog.queue[1]) self.assertEqual( 'foobar', self.manager.object_backlog.queue[0]['create'][1].display_name) # Add something completely different vrf2 = a_res.VRF(tenant_name='tn1', name='vrf2', display_name='pippo') self.manager.push_aim_resources({ 'create': [vrf2], 'delete': aim_converter.convert([bd]) }) self.assertEqual( { 'create': [vrf2], 'delete': aim_converter.convert([bd]) }, self.manager.object_backlog.queue[2])
def clear(self, tree, resources): """Set AIM resources to dummy in tree :param tree: :param items: :return: """ to_aci = converter.AimToAciModelConverter() for obj in to_aci.convert(resources): for mo, v in obj.items(): attr = v.get('attributes', {}) dn = attr.pop('dn', None) key = AimHashTreeMaker._build_hash_tree_key_from_dn(dn, mo) if key: tree.clear(key) return tree
def test_get_aim_resources(self, tree_type=tree_manager.CONFIG_TREE): tree_mgr = tree_manager.HashTreeManager() aim_mgr = aim_manager.AimManager() t1 = resource.Tenant(name='t1') t2 = resource.Tenant(name='t2') t1_fault = aim_status.AciFault( fault_code='101', external_identifier='uni/tn-t1/fault-101', description='failure101') t2_fault = aim_status.AciFault( fault_code='102', external_identifier='uni/tn-t2/fault-102', description='failure102') # Create Resources on a couple of tenants bd1 = resource.BridgeDomain( tenant_name='t1', name='bd1', display_name='somestuff', vrf_name='vrf') bd1_fault = aim_status.AciFault( fault_code='901', external_identifier='uni/tn-t1/BD-bd1/fault-901', description='failure901') bd1_fault2 = aim_status.AciFault( fault_code='902', external_identifier='uni/tn-t1/BD-bd1/fault-902', description='failure902') bd2 = resource.BridgeDomain( tenant_name='t2', name='bd1', display_name='somestuff', vrf_name='vrf2') dc1 = aim_service_graph.DeviceCluster( tenant_name='t1', name='clus1', devices=[{'name': '1'}]) dc1_fault = aim_status.AciFault( fault_code='901', external_identifier='uni/tn-t1/lDevVip-clus1/fault-901', description='failure901') sg1 = aim_service_graph.ServiceGraph( tenant_name='t1', name='gr1', linear_chain_nodes=[{'name': 'N1', 'device_cluster_name': 'cl1'}]) sg1_fault = aim_status.AciFault( fault_code='901', external_identifier='uni/tn-t1/AbsGraph-gr1/fault-901', description='failure901') srp1 = aim_service_graph.ServiceRedirectPolicy( tenant_name='t1', name='srp1', destinations=[{'ip': '1.1.1.1', 'mac': 'aa:bb:cc:dd:ee:ff'}]) srp1_fault = aim_status.AciFault( fault_code='901', external_identifier=('uni/tn-t1/svcCont/svcRedirectPol-srp1' '/fault-901'), description='failure901') dc_ctx1 = aim_service_graph.DeviceClusterContext( tenant_name='t1', contract_name='contract1', service_graph_name='graph1', node_name='N1', device_cluster_name='cluster1', device_cluster_tenant_name='common', bridge_domain_name='svc_bd', service_redirect_policy_name='srp1') dc_ctx1_fault = aim_status.AciFault( fault_code='901', external_identifier=('uni/tn-t1/ldevCtx-c-contract1-' 'g-graph1-n-N1/fault-901'), description='failure901') if tree_type == tree_manager.MONITORED_TREE: bd1.monitored = True bd2.monitored = True t1.monitored = True t2.monitored = True dc1.monitored = True sg1.monitored = True srp1.monitored = True dc_ctx1.monitored = True aim_mgr.create(self.ctx, t1) aim_mgr.create(self.ctx, t2) aim_mgr.create(self.ctx, bd1) aim_mgr.set_fault(self.ctx, t1, t1_fault) aim_mgr.set_fault(self.ctx, t2, t2_fault) aim_mgr.set_fault(self.ctx, bd1, bd1_fault) aim_mgr.set_fault(self.ctx, bd1, bd1_fault2) aim_mgr.create(self.ctx, bd2) aim_mgr.set_resource_sync_synced(self.ctx, t1) aim_mgr.set_resource_sync_synced(self.ctx, t2) aim_mgr.set_resource_sync_synced(self.ctx, bd2) aim_mgr.set_resource_sync_synced(self.ctx, bd1) aim_mgr.create(self.ctx, dc1) aim_mgr.create(self.ctx, sg1) aim_mgr.create(self.ctx, srp1) aim_mgr.create(self.ctx, dc_ctx1) aim_mgr.set_fault(self.ctx, dc1, dc1_fault) aim_mgr.set_fault(self.ctx, sg1, sg1_fault) aim_mgr.set_fault(self.ctx, srp1, srp1_fault) aim_mgr.set_fault(self.ctx, dc_ctx1, dc_ctx1_fault) aim_mgr.set_resource_sync_synced(self.ctx, dc1) aim_mgr.set_resource_sync_synced(self.ctx, sg1) aim_mgr.set_resource_sync_synced(self.ctx, srp1) aim_mgr.set_resource_sync_synced(self.ctx, dc_ctx1) # Two trees exist trees = tree_mgr.find(self.ctx, tree=tree_type) self.assertEqual(2, len(trees)) # Calculate the different with empty trees to retrieve missing keys diff_tn_1 = trees[0].diff(tree.StructuredHashTree()) diff_tn_2 = trees[1].diff(tree.StructuredHashTree()) self.universe.get_relevant_state_for_read = mock.Mock( return_value=[{'tn-t1': trees[0], 'tn-t2': trees[1]}]) result = self.universe.get_resources(diff_tn_1.get('add', []) + diff_tn_1.get('remove', []) + diff_tn_2.get('add', []) + diff_tn_2.get('remove', [])) converted = converter.AciToAimModelConverter().convert( converter.AimToAciModelConverter().convert( [bd1, bd2, dc1, sg1, srp1, dc_ctx1, t1, t2])) if tree_type == tree_manager.MONITORED_TREE: for x in converted: x.monitored = True if tree_type in [tree_manager.CONFIG_TREE, tree_manager.MONITORED_TREE]: self.assertEqual(len(converted), len(result)) for item in converted: self.assertTrue(item in result) elif tree_type == tree_manager.OPERATIONAL_TREE: self.assertEqual(8, len(result)) self.assertTrue(bd1_fault in result) self.assertTrue(bd1_fault2 in result) self.assertTrue(dc1_fault in result) self.assertTrue(sg1_fault in result) self.assertTrue(srp1_fault in result) self.assertTrue(dc_ctx1_fault in result)