def _push_resource(self, context, resource, method, monitored): if isinstance(resource, aim_status.AciFault): # Retrieve fault's parent and set/unset the fault if method == 'create': parents = utils.retrieve_fault_parent( resource.external_identifier, converter.resource_map) for parent in parents: if self.manager.get_status(context, parent): LOG.debug("%s for object %s: %s", self.manager.set_fault.__name__, parent, resource) self.manager.set_fault(context, resource=parent, fault=resource) break else: self.manager.delete(context, resource) else: LOG.debug("%s object in AIM %s" % (method, resource)) if method == 'create': if monitored: # We need two more conversions to screen out # unmanaged items resource.monitored = monitored resource = self._converter_aim_to_aci.convert([resource]) resource = self._converter.convert(resource)[0] resource.monitored = monitored with context.store.begin(subtransactions=True): if isinstance(resource, aim_resource.AciRoot): # Roots should not be created by the # AIM monitored universe. # NOTE(ivar): there are contention cases # where a user might delete a Root object # right before the AIM Monitored Universe # pushes an update on it. If we run a # simple "create overwrite" this would # re-create the object and AID would keep # monitoring said root. by only updating # roots and never creating them, we give # full control over which trees to monitor # to the user. ext = context.store.extract_attributes obj = self.manager.update(context, resource, fix_ownership=monitored, **ext(resource, "other")) if obj: # Declare victory for the update self.creation_succeeded(resource) else: self.manager.create(context, resource, overwrite=True, fix_ownership=monitored) # Declare victory for the created object self.creation_succeeded(resource) else: if isinstance(resource, aim_resource.AciRoot) and monitored: # Monitored Universe doesn't delete Tenant # Resources LOG.info('%s skipping delete for object %s' % (self.name, resource)) return if monitored: # Only delete a resource if monitored with context.store.begin(subtransactions=True): existing = self.manager.get(context, resource) if existing and existing.monitored: self.manager.delete(context, resource) else: self.manager.delete(context, resource)
def retrieve_aci_objects(self, events): result = {} for event in events: resource = list(event.values())[0] res_type = list(event.keys())[0] status = (resource['attributes'].get(STATUS_FIELD) or '').lower() raw_dn = resource['attributes'].get('dn') if self.is_child_object(res_type) and res_type != FAULT_KEY: # We need to make sure to retrieve the parent object as well try: decomposed = ( apic_client.DNManager().aci_decompose_dn_guess( raw_dn, res_type)) parent_dn = apic_client.DNManager().build( decomposed[1][:-1]) if parent_dn not in result: events.append({ decomposed[1][-2][0]: { 'attributes': { 'dn': parent_dn, 'status': converter.MODIFIED_STATUS, '_avoid_print_not_found': True } } }) except (apic_client.DNManager.InvalidNameFormat, KeyError): LOG.debug("Object with DN %s is not supported." % raw_dn) continue if res_type == FAULT_KEY: # Make sure we support the parent object try: apic_client.DNManager().aci_decompose_dn_guess( raw_dn, res_type) utils.retrieve_fault_parent(raw_dn, converter.resource_map) except (apic_client.DNManager.InvalidNameFormat, KeyError): LOG.debug("Fault with DN %s is not supported." % raw_dn) continue if res_type == TAG_KEY: # Add to the result and go ahead to the next object result[raw_dn] = event continue if status == converter.DELETED_STATUS: # Add to the result but keep evaluating result[raw_dn] = event if status == converter.MODIFIED_STATUS: event_attrs = copy.deepcopy( list(event.values())[0]['attributes']) event_attrs.pop(STATUS_FIELD) apnf = event_attrs.pop('_avoid_print_not_found', False) if raw_dn in result: # Update with changes list(result[raw_dn].values())[0]['attributes'].update( event_attrs) key = tree_manager.AimHashTreeMaker._dn_to_key( res_type, raw_dn) data = [] if key: # Search within the TenantManager state, which is the most # up to date. data = self.get_resources( [key], desired_state=self._get_full_state()) if not data and not apnf: LOG.debug("Resource %s not found or not supported", raw_dn) for item in data: dn = list(item.values())[0]['attributes']['dn'] if dn not in result: result[dn] = item if dn == raw_dn: list(result[raw_dn].values() )[0]['attributes'].update(event_attrs) if not status or status == converter.CREATED_STATUS: result[raw_dn] = event LOG.debug("Result for retrieving ACI resources: %s\n %s" % (events, result)) return list(result.values())
def _push_resources(self, resources, monitored=False): for method in resources: if method == 'delete': # Use ACI items directly items = resources[method] else: # Convert everything before creating items = self._converter.convert(resources[method]) for resource in items: # Items are in the other universe's format unless deletion try: if isinstance(resource, aim_status.AciFault): # Retrieve fault's parent and set/unset the fault if method == 'create': parents = utils.retrieve_fault_parent( resource.external_identifier, converter.resource_map) for parent in parents: if self.manager.get_status( self.context, parent): LOG.debug("%s for object %s: %s", self.manager.set_fault.__name__, parent, resource) self.manager.set_fault(self.context, resource=parent, fault=resource) break else: self.manager.delete(self.context, resource) else: LOG.debug("%s object in AIM %s" % (method, resource)) if method == 'create': if monitored: # We need two more conversions to screen out # unmanaged items resource.monitored = monitored resource = self._converter_aim_to_aci.convert( [resource]) resource = self._converter.convert(resource)[0] resource.monitored = monitored with self.context.store.begin( subtransactions=True): if isinstance(resource, aim_resource.AciRoot): # Roots should not be created by the # AIM monitored universe. # NOTE(ivar): there are contention cases # where a user might delete a Root object # right before the AIM Monitored Universe # pushes an update on it. If we run a # simple "create overwrite" this would # re-create the object and AID would keep # monitoring said root. by only updating # roots and never creating them, we give # full control over which trees to monitor # to the user. ext = self.context.store.extract_attributes obj = self.manager.update( self.context, resource, fix_ownership=monitored, **ext(resource, "other")) if obj: # Declare victory for the update self.creation_succeeded(resource) else: self.manager.create( self.context, resource, overwrite=True, fix_ownership=monitored) # Declare victory for the created object self.creation_succeeded(resource) else: if isinstance(resource, aim_resource.AciRoot) and monitored: # Monitored Universe doesn't delete Tenant # Resources LOG.info('%s skipping delete for object %s' % (self.name, resource)) continue if monitored: # Only delete a resource if monitored with self.context.store.begin( subtransactions=True): existing = self.manager.get( self.context, resource) if existing and existing.monitored: self.manager.delete( self.context, resource) else: self.manager.delete(self.context, resource) except aim_exc.InvalidMonitoredStateUpdate as e: msg = ("Failed to %s object %s in AIM: %s." % (method, resource, e.message)) LOG.warn(msg) except Exception as e: LOG.error("Failed to %s object %s in AIM: %s." % (method, resource, e.message)) LOG.debug(traceback.format_exc()) self.context.store.fix_session(e) # REVISIT(ivar): can creation on the AIM side fail? If so, # what can the universe do about it? We can't set sync # status of non existing objects, neither we can remove # objects from ACI-side trees (how would the manual # operation for resync be triggered?) if method == 'delete': self.deletion_failed(resource) else: self._monitored_state_update_failures = 0
def retrieve_aci_objects(self, events): result = {} for event in events: resource = event.values()[0] res_type = event.keys()[0] status = (resource['attributes'].get(STATUS_FIELD) or '').lower() raw_dn = resource['attributes'].get('dn') if self.is_child_object(res_type) and res_type != FAULT_KEY: # We need to make sure to retrieve the parent object as well try: decomposed = ( apic_client.DNManager().aci_decompose_dn_guess( raw_dn, res_type)) parent_dn = apic_client.DNManager().build( decomposed[1][:-1]) if parent_dn not in result: events.append( {decomposed[1][-2][0]: {'attributes': { 'dn': parent_dn, 'status': converter.MODIFIED_STATUS, '_avoid_print_not_found': True}}}) except (apic_client.DNManager.InvalidNameFormat, KeyError): LOG.debug("Object with DN %s is not supported." % raw_dn) continue if res_type == FAULT_KEY: # Make sure we support the parent object try: apic_client.DNManager().aci_decompose_dn_guess(raw_dn, res_type) utils.retrieve_fault_parent(raw_dn, converter.resource_map) except (apic_client.DNManager.InvalidNameFormat, KeyError): LOG.debug("Fault with DN %s is not supported." % raw_dn) continue if res_type == TAG_KEY: # Add to the result and go ahead to the next object result[raw_dn] = event continue if status == converter.DELETED_STATUS: # Add to the result but keep evaluating result[raw_dn] = event if status == converter.MODIFIED_STATUS: event_attrs = copy.deepcopy(event.values()[0]['attributes']) event_attrs.pop(STATUS_FIELD) apnf = event_attrs.pop('_avoid_print_not_found', False) if raw_dn in result: # Update with changes result[raw_dn].values()[0]['attributes'].update( event_attrs) key = tree_manager.AimHashTreeMaker._dn_to_key(res_type, raw_dn) data = [] if key: # Search within the TenantManager state, which is the most # up to date. data = self.get_resources( [key], desired_state=self._get_full_state()) if not data and not apnf: LOG.debug("Resource %s not found or not supported", raw_dn) for item in data: dn = item.values()[0]['attributes']['dn'] if dn not in result: result[dn] = item if dn == raw_dn: result[raw_dn].values()[0]['attributes'].update( event_attrs) if not status or status == converter.CREATED_STATUS: result[raw_dn] = event LOG.debug("Result for retrieving ACI resources: %s\n %s" % (events, result)) return result.values()
def _push_resource(self, context, resource, method, monitored): if isinstance(resource, aim_status.AciFault): # Retrieve fault's parent and set/unset the fault if method == 'create': parents = utils.retrieve_fault_parent( resource.external_identifier, converter.resource_map) for parent in parents: if self.manager.get_status(context, parent): LOG.debug("%s for object %s: %s", self.manager.set_fault.__name__, parent, resource) self.manager.set_fault(context, resource=parent, fault=resource) break else: self.manager.delete(context, resource) else: LOG.debug("%s object in AIM %s" % (method, resource)) if method == 'create': if monitored: # We need two more conversions to screen out # unmanaged items resource.monitored = monitored resource = self._converter_aim_to_aci.convert( [resource]) resource = self._converter.convert(resource)[0] resource.monitored = monitored with context.store.begin(subtransactions=True): if isinstance(resource, aim_resource.AciRoot): # Roots should not be created by the # AIM monitored universe. # NOTE(ivar): there are contention cases # where a user might delete a Root object # right before the AIM Monitored Universe # pushes an update on it. If we run a # simple "create overwrite" this would # re-create the object and AID would keep # monitoring said root. by only updating # roots and never creating them, we give # full control over which trees to monitor # to the user. ext = context.store.extract_attributes obj = self.manager.update( context, resource, fix_ownership=monitored, **ext(resource, "other")) if obj: # Declare victory for the update self.creation_succeeded(resource) else: self.manager.create( context, resource, overwrite=True, fix_ownership=monitored) # Declare victory for the created object self.creation_succeeded(resource) else: if isinstance(resource, aim_resource.AciRoot) and monitored: # Monitored Universe doesn't delete Tenant # Resources LOG.info('%s skipping delete for object %s' % (self.name, resource)) return if monitored: # Only delete a resource if monitored with context.store.begin(subtransactions=True): existing = self.manager.get(context, resource) if existing and existing.monitored: self.manager.delete(context, resource) else: self.manager.delete(context, resource)