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)