예제 #1
0
파일: utils.py 프로젝트: omps/pulp
def get_enabled():
    """
    Get schedules that are enabled, that is, their "enabled" attribute is True

    :return:    pymongo cursor of ScheduledCall database objects
    :rtype:     pymongo.cursor.Cursor
    """
    criteria = Criteria(filters={'enabled': True})
    return ScheduledCall.get_collection().query(criteria)
예제 #2
0
파일: tasks.py 프로젝트: aweiteka/pulp
def _delete_worker(name, normal_shutdown=False):
    """
    Delete the Worker with _id name from the database. This Task can only safely be
    performed by the resource manager at this time, so be sure to queue it in the
    RESOURCE_MANAGER_QUEUE.

    If the worker shutdown normally, no message is logged, otherwise an error level message is
    logged. Default is to assume the work did not shut down normally.

    :param name:            The name of the worker you wish to delete. In the database, the _id
                            field is the name.
    :type  name:            basestring
    :param normal_shutdown: True if the worker shutdown normally, False otherwise.  Defaults to
                            False.
    :type normal_shutdown:  bool
    """
    worker_list = list(
        resources.filter_workers(Criteria(filters={'_id': name})))
    if len(worker_list) == 0:
        # Potentially _delete_worker() may be called with the database not containing any entries.
        # https://bugzilla.redhat.com/show_bug.cgi?id=1091922
        return
    worker = worker_list[0]

    if normal_shutdown is False:
        msg = _(
            'The worker named %(name)s is missing. Canceling the tasks in its queue.'
        )
        msg = msg % {'name': worker.name}
        logger.error(msg)

    # Cancel all of the tasks that were assigned to this worker's queue
    for task in TaskStatusManager.find_by_criteria(
            Criteria(
                filters={
                    'queue': worker.queue_name,
                    'state': {
                        '$in': constants.CALL_INCOMPLETE_STATES
                    }
                })):
        cancel(task['task_id'])

    # Finally, delete the worker
    worker.delete()
예제 #3
0
    def test_add_single(self):
        group_id = 'test_group'
        self.manager.create_repo_group(group_id)

        repo = self._create_repo('test_repo')
        criteria = Criteria(filters={'id': repo['id']}, fields=['id'])
        self.manager.associate(group_id, criteria)

        group = self.collection.find_one({'id': group_id})
        self.assertTrue(repo['id'] in group['repo_ids'])
예제 #4
0
    def test_criteria_passed_to_mongo(self, get_collection):
        """
        Assert that the Criteria object is passed on to MongoDB.
        """
        criteria = Criteria(filters={'_id': 'some_id'})

        workers = list(resources.filter_workers(criteria))

        get_collection.return_value.query.assert_called_once_with(criteria)
        self.assertEqual(workers, list())
예제 #5
0
class ConsumerGroupAssociationTests(base.PulpWebserviceTests):
    def setUp(self):
        super(ConsumerGroupAssociationTests, self).setUp()
        self.manager = managers.consumer_group_manager()

    def clean(self):
        super(ConsumerGroupAssociationTests, self).clean()
        ConsumerGroup.get_collection().remove()

    @mock.patch.object(Criteria, 'from_client_input', return_value=Criteria())
    @mock.patch('pulp.server.managers.consumer.group.cud.ConsumerGroupManager.associate')
    def test_associate(self, mock_associate, mock_from_client):
        self.manager.create_consumer_group('cg1')

        post_data = {'criteria': {'filters': {'id': {'$in': ['consumer1']}}}}
        status, body = self.post('/v2/consumer_groups/cg1/actions/associate/', post_data)
        self.assertEqual(status, 200)

        self.assertEqual(mock_associate.call_count, 1)
        call_args = mock_associate.call_args[0]
        self.assertEqual(call_args[0], 'cg1')
        # verify that it created and used a Criteria instance
        self.assertEqual(call_args[1], mock_from_client.return_value)
        self.assertEqual(mock_from_client.call_args[0][0],
                         {'filters': {'id': {'$in': ['consumer1']}}})

    @mock.patch.object(Criteria, 'from_client_input', return_value=Criteria())
    @mock.patch('pulp.server.managers.consumer.group.cud.ConsumerGroupManager.unassociate')
    def test_unassociate(self, mock_unassociate, mock_from_client):
        self.manager.create_consumer_group('cg1')

        post_data = {'criteria': {'filters': {'id': {'$in': ['consumer1']}}}}
        status, body = self.post('/v2/consumer_groups/cg1/actions/unassociate/', post_data)
        self.assertEqual(status, 200)

        self.assertEqual(mock_unassociate.call_count, 1)
        call_args = mock_unassociate.call_args[0]
        self.assertEqual(call_args[0], 'cg1')
        # verify that it created and used a Criteria instance
        self.assertEqual(call_args[1], mock_from_client.return_value)
        self.assertEqual(mock_from_client.call_args[0][0],
                         {'filters': {'id': {'$in': ['consumer1']}}})
예제 #6
0
def load_repo_units(plugin_manager, repo_name, factory):
    for rcu in RepositoryContentUnit.objects.find_by_criteria(
            Criteria(filters={'repo_id': repo_name})):
        # just the RPMs for now O:-)
        if rcu.unit_type_id != 'rpm':
            print('skipping {}'.format(rcu.unit_type_id))
            continue
        model = plugin_manager.unit_models[rcu.unit_type_id]
        unit = model.objects.get(pk=rcu.unit_id)
        print('loaded {}'.format(unit))
        factory(unit)
예제 #7
0
    def test_add_single(self):
        group_id = 'test_group'
        self.manager.create_consumer_group(group_id)

        consumer = self._create_consumer('test_consumer')
        criteria = Criteria(filters={'id': consumer['id']}, fields=['id'])
        matched = self.manager.associate(group_id, criteria)

        group = self.collection.find_one({'id': group_id})
        self.assertEqual(matched, ['test_consumer'])
        self.assertTrue(consumer['id'] in group['consumer_ids'])
예제 #8
0
    def test_find_by_criteria(self, mock_get_collection):
        criteria = Criteria(limit=20)
        units = self.query_manager.find_by_criteria('deb', criteria)

        # make sure it tried to get the correct collection
        mock_get_collection.assert_called_once_with('deb')

        # make sure the query call itself was correct
        mock_query = mock_get_collection.return_value.query
        self.assertEqual(mock_query.call_count, 1)
        self.assertEqual(mock_query.call_args[0][0], criteria)
        self.assertEqual(mock_query.return_value, units)
예제 #9
0
파일: test_cud.py 프로젝트: zjhuntin/pulp
    def test_associate_id_regex(self):
        group_id = 'associate_by_regex'
        self.manager.create_repo_group(group_id)

        repo_1 = self._create_repo('repo_1')
        repo_2 = self._create_repo('repo_2')
        criteria = Criteria(filters={'repo_id': {'$regex': 'repo_[12]'}})
        self.manager.associate(group_id, criteria)

        group = self.collection.find_one({'id': group_id})
        self.assertTrue(repo_1.repo_id in group['repo_ids'])
        self.assertTrue(repo_2.repo_id in group['repo_ids'])
예제 #10
0
    def test_associate_id_regex(self):
        group_id = 'associate_by_regex'
        self.manager.create_consumer_group(group_id)

        consumer_1 = self._create_consumer('consumer_1')
        consumer_2 = self._create_consumer('consumer_2')
        criteria = Criteria(filters={'id': {'$regex': 'consumer_[12]'}})
        self.manager.associate(group_id, criteria)

        group = self.collection.find_one({'id': group_id})
        self.assertTrue(consumer_1['id'] in group['consumer_ids'])
        self.assertTrue(consumer_2['id'] in group['consumer_ids'])
예제 #11
0
def load_repo_units(plugin_manager, repo_name, factory_mapping):
    for rcu in RepositoryContentUnit.objects.find_by_criteria(
            Criteria(filters={'repo_id': repo_name})):
        try:
            factory = factory_mapping[rcu.unit_type_id]
        except KeyError:
            print('skipping {}'.format(rcu.unit_type_id))
            continue
        model = plugin_manager.unit_models[rcu.unit_type_id]
        unit = model.objects.get(pk=rcu.unit_id)
        print('loaded {}'.format(unit))
        factory(unit)
예제 #12
0
def get_by_resource(resource):
    """
    Get schedules by resource

    :param resource:    unique ID for a lockable resource
    :type  resource:    basestring

    :return:    iterator of ScheduledCall instances
    :rtype:     iterator
    """
    criteria = Criteria(filters={'resource': resource})
    schedules = ScheduledCall.get_collection().query(criteria)
    return itertools.imap(ScheduledCall.from_db, schedules)
예제 #13
0
    def test_remove_single(self):
        group_id = 'test_group'
        consumer = self._create_consumer('test_consumer')
        self.manager.create_consumer_group(group_id,
                                           consumer_ids=[consumer['id']])

        group = self.collection.find_one({'id': group_id})
        self.assertTrue(consumer['id'] in group['consumer_ids'])

        criteria = Criteria(filters={'id': consumer['id']}, fields=['id'])
        self.manager.unassociate(group_id, criteria)

        group = self.collection.find_one({'id': group_id})
        self.assertFalse(consumer['id'] in group['consumer_ids'])
예제 #14
0
def get_updated_since(seconds):
    """
    Get schedules that are enabled, that is, their "enabled" attribute is True,
    and that have been updated since the timestamp represented by "seconds".

    :param seconds: seconds since the epoch
    :param seconds: float

    :return:    pymongo cursor of ScheduledCall database objects
    :rtype:     pymongo.cursor.Cursor
    """
    criteria = Criteria(filters={
        'enabled': True,
        'last_updated': {'$gt': seconds},
    })
    return ScheduledCall.get_collection().query(criteria)
예제 #15
0
 def populate(self):
     manager = managers.consumer_manager()
     for consumer_id in CONSUMER_IDS:
         manager.register(consumer_id)
     manager = managers.consumer_group_manager()
     manager.create_consumer_group(GROUP_ID)
     for consumer_id in CONSUMER_IDS:
         criteria = Criteria(filters={'id': consumer_id}, fields=['id'])
         manager.associate(GROUP_ID, criteria)
     manager = managers.repo_manager()
     manager.create_repo(REPO_ID)
     manager = managers.repo_distributor_manager()
     manager.add_distributor(REPO_ID,
                             DISTRIBUTOR_TYPE_ID, {},
                             True,
                             distributor_id=DISTRIBUTOR_ID)
예제 #16
0
    def _get_consumer_profile_map(consumer_ids):
        """
        Create a consumer-profile map:
        {consumer id:
            {'profiles': list of tuples with profile details,
             'all_profiles_hash': hash of all consumer's profile_hashes}}

        :param consumer_ids: consumers for which applicability needs to be regenerated
        :type  consumer_ids: list

        :return: consumer-profile map described above
        :rtype: dict
        """
        consumer_profile_manager = managers.consumer_profile_manager()
        consumer_ids = list(set(consumer_ids))

        # Get all unit profiles associated with given consumers
        unit_profile_criteria = Criteria(
            filters={'consumer_id': {
                '$in': consumer_ids
            }},
            fields=['consumer_id', 'profile_hash', 'content_type', 'id'])
        all_unit_profiles = consumer_profile_manager.find_by_criteria(
            unit_profile_criteria)

        consumer_profiles_map = {}

        for unit_profile in all_unit_profiles:
            profile_hash = unit_profile['profile_hash']
            content_type = unit_profile['content_type']
            consumer_id = unit_profile['consumer_id']
            profile_id = unit_profile['id']

            profile_tuple = (profile_hash, content_type, profile_id)
            # Add this tuple to the list of profile tuples for a consumer
            consumer_profiles_map.setdefault(consumer_id, {})
            consumer_profiles_map[consumer_id].setdefault(
                'profiles', []).append(profile_tuple)

        # Calculate and add all_profiles_hash to the map
        for consumer_id, pdata in consumer_profiles_map.items():
            profile_hashes = [pr_hash for pr_hash, _, _ in pdata['profiles']]
            all_profiles_hash = _calculate_all_profiles_hash(profile_hashes)
            consumer_profiles_map[consumer_id][
                'all_profiles_hash'] = all_profiles_hash

        return consumer_profiles_map
예제 #17
0
def get(schedule_ids):
    """
    Get schedules by ID

    :param schedule_ids:    a list of schedule IDs
    :type  schedule_ids:    list

    :return:    iterator of ScheduledCall instances
    :rtype:     iterator
    """
    try:
        object_ids = map(ObjectId, schedule_ids)
    except InvalidId:
        raise exceptions.InvalidValue(['schedule_ids'])
    criteria = Criteria(filters={'_id': {'$in': object_ids}})
    schedules = ScheduledCall.get_collection().query(criteria)
    return itertools.imap(ScheduledCall.from_db, schedules)
예제 #18
0
    def get(self, request, type_id):
        """
        Return a response with a serialized list of the content units of the specified type.

        :param request: WSGI request object
        :type  request: django.core.handlers.wsgi.WSGIRequest
        :param type_id: the list of content units will be limited to this type
        :type  type_id: str

        :return: response with a serialized list of dicts, one for each unit of the type.
        :rtype: django.http.HttpResponse
        """
        cqm = factory.content_query_manager()
        all_units = cqm.find_by_criteria(type_id, Criteria())
        all_processed_units = [
            _process_content_unit(unit, type_id) for unit in all_units
        ]
        return generate_json_response_with_pulp_encoder(all_processed_units)
예제 #19
0
파일: consumers.py 프로젝트: ipanova/pulp
    def POST(self, consumer_id):
        """
        Creates an async task to regenerate content applicability data for given consumer.

        :param consumer_id: The consumer ID.
        :type consumer_id: basestring
        """
        consumer_query_manager = managers.consumer_query_manager()
        if consumer_query_manager.find_by_id(consumer_id) is None:
            raise MissingResource(consumer_id=consumer_id)
        consumer_criteria = Criteria(filters={'consumer_id': consumer_id})

        task_tags = [tags.action_tag('consumer_content_applicability_regeneration')]
        async_result = regenerate_applicability_for_consumers.apply_async_with_reservation(
            tags.RESOURCE_CONSUMER_TYPE,
            consumer_id,
            (consumer_criteria.as_dict(),),
            tags=task_tags)
        raise OperationPostponed(async_result)
예제 #20
0
    def test_find_by_criteria_with_result(self):
        tags = ['test', 'tags']
        TaskStatus(task_id='1').save()
        TaskStatus(task_id='2', tags=tags).save()

        result = 'done'
        TaskStatus(task_id='3', tags=tags, state=constants.CALL_FINISHED_STATE,
                   result=result).save()

        filters = {'tags': tags, 'task_id': {'$in': ['1', '3']}}
        fields = ['task_id', 'tags', 'result']
        limit = 1
        sort = (('task_id', DESCENDING), )
        criteria = Criteria(filters=filters, fields=fields, limit=limit, sort=sort)
        query_set = TaskStatus.objects.find_by_criteria(criteria)
        self.assertEqual(len(query_set), 1)
        self.assertEqual(query_set[0].task_id, '3')
        self.assertEqual(query_set[0].result, result)
        task_state_default = constants.CALL_WAITING_STATE
        self.assertEqual(query_set[0].state, task_state_default)
예제 #21
0
파일: tasks.py 프로젝트: ipanova/pulp
def _delete_worker(name, normal_shutdown=False):
    """
    Delete the Worker with _id name from the database, cancel any associated tasks and reservations

    If the worker shutdown normally, no message is logged, otherwise an error level message is
    logged. Default is to assume the worker did not shut down normally.

    Any resource reservations associated with this worker are cleaned up by this function.

    Any tasks associated with this worker are explicitly canceled.

    :param name:            The name of the worker you wish to delete. In the database, the _id
                            field is the name.
    :type  name:            basestring
    :param normal_shutdown: True if the worker shutdown normally, False otherwise.  Defaults to
                            False.
    :type normal_shutdown:  bool
    """
    if normal_shutdown is False:
        msg = _(
            'The worker named %(name)s is missing. Canceling the tasks in its queue.'
        )
        msg = msg % {'name': name}
        _logger.error(msg)

    # Delete the worker document
    worker_list = list(
        resources.filter_workers(Criteria(filters={'_id': name})))
    if len(worker_list) > 0:
        worker_document = worker_list[0]
        worker_document.delete()

    # Delete all reserved_resource documents for the worker
    ReservedResource.get_collection().remove({'worker_name': name})

    # Cancel all of the tasks that were assigned to this worker's queue
    worker = Worker.from_bson({'_id': name})
    for task_status in TaskStatus.objects(
            worker_name=worker.name,
            state__in=constants.CALL_INCOMPLETE_STATES):
        cancel(task_status['task_id'])
예제 #22
0
파일: scheduler.py 프로젝트: omps/pulp
    def check_workers(self):
        """
        Look for missing workers, and dispatch a cleanup task if one goes missing.

        To find a missing worker, filter the Workers model for entries older than
        utcnow() - WORKER_TIMEOUT_SECONDS. The heartbeat times are stored in native UTC, so this is
        a comparable datetime.

        For each missing worker found, dispatch a _delete_worker task requesting that the resource
        manager delete the Worker and cleanup any associated work.

        This method logs and the debug and error levels.
        """
        msg = _('Looking for workers missing for more than %s seconds') % self.WORKER_TIMEOUT_SECONDS
        _logger.debug(msg)
        oldest_heartbeat_time = datetime.utcnow() - timedelta(seconds=self.WORKER_TIMEOUT_SECONDS)
        worker_criteria = Criteria(filters={'last_heartbeat': {'$lt': oldest_heartbeat_time}},
                                   fields=('_id', 'last_heartbeat'))
        worker_list = list(resources.filter_workers(worker_criteria))
        for worker in worker_list:
            msg = _("Workers '%s' has gone missing, removing from list of workers") % worker.name
            _logger.error(msg)
            _delete_worker(worker.name)
예제 #23
0
    def test_remove_single_consumer_history(self):
        group_id = 'test_group'
        self.manager.create_consumer_group(group_id)
        group = self.collection.find_one({'id': group_id})

        consumer = self._create_consumer('test_consumer')
        self.assertFalse(consumer['id'] in group['consumer_ids'])
        criteria = Criteria(filters={'id': consumer['id']}, fields=['id'])
        self.manager.unassociate(group_id, criteria)

        collection = ConsumerHistoryEvent.get_collection()
        history = collection.find_one({
            'consumer_id': 'test_consumer',
            'type': 'removed_from_group',
            'details': {
                'group_id': group_id
            }
        })
        self.assertTrue(history is not None)
        self.assertEqual(history['consumer_id'], 'test_consumer')
        self.assertEqual(history['type'], 'removed_from_group')
        self.assertEqual(history['originator'], 'SYSTEM')
        self.assertEqual(history['details'], {'group_id': group_id})
예제 #24
0
    def _add_repo_memberships(units, type_id):
        """
        For a list of units, find what repos each is a member of and add a list
        of repo_ids to each unit.

        :param units:   list of unit documents
        :type  units:   list of dicts
        :param type_id: content type id
        :type  type_id: str
        :return:    same list of units that was passed in, only for convenience.
                    units are modified in-place
        """
        # quick return if there is nothing to do
        if not units:
            return units

        unit_ids = [unit['_id'] for unit in units]
        criteria = Criteria(filters={
            'unit_id': {
                '$in': unit_ids
            },
            'unit_type_id': type_id
        },
                            fields=('repo_id', 'unit_id'))
        associations = factory.repo_unit_association_query_manager(
        ).find_by_criteria(criteria)
        unit_ids = None
        criteria = None
        association_map = {}
        for association in associations:
            association_map.setdefault(association['unit_id'],
                                       set()).add(association['repo_id'])

        for unit in units:
            unit['repository_memberships'] = list(
                association_map.get(unit['_id'], []))
        return units
예제 #25
0
파일: consumers.py 프로젝트: zjhuntin/pulp
def expand_consumers(details, bindings, consumers):
    """
    Expand a list of users based on the flag specified in the query parameters.
    The _href is always added by the serialization function used.
    Supported options:
      details - include details
      bindings - include bindings

    :param details: if True, details will be included in the response
    :type  details: bool
    :param bindings:    if True, bindings will be included with each returned consumer
    :type  bindings:    bool
    :param consumers: A list of consumers
    :type consumers: list

    :return: A list of expanded consumers.
    :rtype: list
    """

    if details:
        bindings = True
    # add bindings
    if bindings:
        ids = [c['id'] for c in consumers]
        manager = factory.consumer_bind_manager()
        criteria = Criteria({'consumer_id': {'$in': ids}})
        bindings = manager.find_by_criteria(criteria)
        collated = {}
        for b in bindings:
            lst = collated.setdefault(b['consumer_id'], [])
            lst.append(b)
        for c in consumers:
            c['bindings'] = [
                serial_binding.serialize(b, False)
                for b in collated.get(c['id'], [])
            ]
    return consumers
예제 #26
0
def expand_consumers(options, consumers):
    """
    Expand a list of users based on the flag specified in the query parameters.
    The _href is always added by the serialization function used.
    Supported options:
      details - include details
      bindings - include bindings

    :param options: The (expanding) options.
    :type options: dict
    :param consumers: A list of consumers
    :type consumers: list

    :return: A list of expanded consumers.
    :rtype: list
    """

    details = options.get('details', 'false').lower() == 'true'
    bindings = options.get('bindings', 'false').lower() == 'true'
    if details:
        bindings = True
    # add bindings
    if bindings:
        ids = [c['id'] for c in consumers]
        manager = factory.consumer_bind_manager()
        criteria = Criteria({'consumer_id': {'$in': ids}})
        bindings = manager.find_by_criteria(criteria)
        collated = {}
        for b in bindings:
            lst = collated.setdefault(b['consumer_id'], [])
            lst.append(b)
        for c in consumers:
            c['bindings'] = [
                serialization.binding.serialize(b, False) for b in collated.get(c['id'], [])
            ]
    return consumers
예제 #27
0
def get_all_existing_units(search_dicts, unit_fields, unit_type, search_method):
    """
    Get all existing units on the server which match given search_dicts using
    given search_method.

    :param search_dicts:  unit keys generator
    :type search_dicts:   iterator of unit keys
    :param unit_fields:   unit fields to be requested to the search_method
    :type unit_fields:    list or tuple
    :param unit_type:     unit type
    :type unit_type:      basestring
    :param search_method: search method to be used to search for non-repo-specific units
    :type search_method:  a search method accepting a unit type and
                          pulp.server.db.criteria.Criteria as parameters
    :return:              generator of Units found using the search_method
    :rtype:               iterator of pulp.plugins.model.Unit
    """
    # Instead of separate query for each unit, we are using paginate to query
    # for a lot of units at once.
    for segment in paginate(search_dicts):
        unit_filters = {'$or': list(segment)}
        criteria = Criteria(filters=unit_filters, fields=unit_fields)
        for result in search_method(unit_type, criteria):
            yield result
예제 #28
0
 def test_find_by_criteria(self, mock_query):
     criteria = Criteria()
     self.query_manager.find_by_criteria(criteria)
     mock_query.assert_called_once_with(criteria)
예제 #29
0
    def regenerate_applicability_for_consumers(consumer_criteria):
        """
        Regenerate and save applicability data for given updated consumers.

        :param consumer_criteria: The consumer selection criteria
        :type consumer_criteria: dict
        """
        consumer_criteria = Criteria.from_dict(consumer_criteria)
        consumer_query_manager = managers.consumer_query_manager()
        bind_manager = managers.consumer_bind_manager()
        consumer_profile_manager = managers.consumer_profile_manager()

        # Process consumer_criteria and get all the consumer ids satisfied by the criteria
        consumer_criteria.fields = ['id']
        consumer_ids = [
            c['id']
            for c in consumer_query_manager.find_by_criteria(consumer_criteria)
        ]

        # Following logic of checking existing applicability and getting required data
        # to generate applicability is a bit more complicated than what it could be 'by design'.
        # It is to optimize the number of db queries and improving applicability generation
        # performance. Please consider the implications for applicability generation time
        # when making any modifications to this code.

        # Get all unit profiles associated with given consumers
        unit_profile_criteria = Criteria(
            filters={'consumer_id': {
                '$in': consumer_ids
            }},
            fields=['consumer_id', 'profile_hash', 'content_type', 'id'])
        all_unit_profiles = consumer_profile_manager.find_by_criteria(
            unit_profile_criteria)

        # Create a consumer-profile map with consumer id as the key and list of tuples
        # with profile details as the value
        consumer_unit_profiles_map = {}
        # Also create a map of profile_id keyed by profile_hash for profile lookup.
        profile_hash_profile_id_map = {}
        for unit_profile in all_unit_profiles:
            profile_hash = unit_profile['profile_hash']
            content_type = unit_profile['content_type']
            consumer_id = unit_profile['consumer_id']
            profile_id = unit_profile['id']

            profile_tuple = (profile_hash, content_type)
            # Add this tuple to the list of profile tuples for a consumer
            consumer_unit_profiles_map.setdefault(consumer_id,
                                                  []).append(profile_tuple)

            # We need just one profile_id per profile_hash to be used in regenerate_applicability
            # method to get the actual profile corresponding to given profile_hash.
            if profile_hash not in profile_hash_profile_id_map:
                profile_hash_profile_id_map[profile_hash] = profile_id

        # Get all repos bound to given consumers
        bind_criteria = Criteria(
            filters={'consumer_id': {
                '$in': consumer_ids
            }},
            fields=['repo_id', 'consumer_id'])
        all_repo_bindings = bind_manager.find_by_criteria(bind_criteria)

        # Create a repo-consumer map with repo_id as the key and consumer_id list as the value
        repo_consumers_map = {}
        for binding in all_repo_bindings:
            repo_consumers_map.setdefault(binding['repo_id'],
                                          []).append(binding['consumer_id'])

        # Create a set of (repo_id, (profile_hash, content_type))
        repo_profile_hashes = set()
        for repo_id, consumer_id_list in repo_consumers_map.items():
            for consumer_id in consumer_id_list:
                if consumer_id in consumer_unit_profiles_map:
                    for unit_profile_tuple in consumer_unit_profiles_map[
                            consumer_id]:
                        repo_profile_hashes.add((repo_id, unit_profile_tuple))

        # Iterate through each tuple in repo_profile_hashes set and regenerate applicability,
        # if it doesn't exist. These are all guaranteed to be unique tuples because of the logic
        # used to create maps and sets above, eliminating multiple unnecessary queries
        # to check for existing applicability for same profiles.
        manager = managers.applicability_regeneration_manager()
        for repo_id, (profile_hash, content_type) in repo_profile_hashes:
            # Check if applicability for given profile_hash and repo_id already exists
            if ApplicabilityRegenerationManager._is_existing_applicability(
                    repo_id, profile_hash):
                continue
            # If applicability does not exist, generate applicability data for given profile
            # and repo id.
            profile_id = profile_hash_profile_id_map[profile_hash]
            manager.regenerate_applicability(profile_hash, content_type,
                                             profile_id, repo_id)
예제 #30
0
    def find_applicable_units(self,
                              consumer_criteria=None,
                              repo_criteria=None,
                              unit_criteria=None,
                              override_config=None):
        """
        Determine and report which of the content units specified by the unit_criteria
        are applicable to consumers specified by the consumer_criteria
        with repos specified by repo_criteria. If consumer_criteria is None,
        all consumers registered to the Pulp server are checked for applicability.
        If repo_criteria is None, all repos bound to the consumer are taken
        into consideration. If unit_criteria contains an empty list for a specific type,
        all units with specific type in the repos bound to the consumer
        are taken into consideration. 

        :param consumer_criteria: The consumer selection criteria.
        :type consumer_criteria: dict

        :param repo_criteria: The repo selection criteria.
        :type repo_criteria: dict

        :param unit_criteria: A dictionary of type_id : unit selection criteria
        :type units: dict
                {<type_id1> : <unit_criteria_for_type_id1>,
                 <type_id2> : <unit_criteria_for_type_id2>}
      
        :param override_config: Additional configuration options to be accepted from user
        :type override_config: dict

        :return: applicability reports dictionary keyed by content type id
        :rtype: dict
        """
        result = {}
        conduit = ProfilerConduit()
        consumer_query_manager = managers.consumer_query_manager()
        bind_manager = managers.consumer_bind_manager()

        # Process Repo Criteria
        if repo_criteria:
            # Get repo ids satisfied by specified repo criteria
            repo_query_manager = managers.repo_query_manager()
            repo_criteria_ids = [
                r['id']
                for r in repo_query_manager.find_by_criteria(repo_criteria)
            ]
            # if repo_criteria is specified and there are no repos satisfying the criteria, return empty result
            if not repo_criteria_ids:
                return result
        else:
            repo_criteria_ids = None

        # Process Consumer Criteria
        if consumer_criteria:
            # Get consumer ids satisfied by specified consumer criteria
            consumer_ids = [
                c['id'] for c in consumer_query_manager.find_by_criteria(
                    consumer_criteria)
            ]
        else:
            if repo_criteria_ids:
                # If repo_criteria is specified, get all the consumers bound to the repos
                # satisfied by repo_criteria
                bind_criteria = Criteria(
                    filters={"repo_id": {
                        "$in": repo_criteria_ids
                    }})
                consumer_ids = [
                    b['consumer_id']
                    for b in bind_manager.find_by_criteria(bind_criteria)
                ]
                # Remove duplicate consumer ids
                consumer_ids = list(set(consumer_ids))
            else:
                # Get all consumer ids registered to the Pulp server
                consumer_ids = [
                    c['id'] for c in consumer_query_manager.find_all()
                ]
        # if there are no relevant consumers, return empty result
        if not consumer_ids:
            return result
        else:
            # Based on the consumers, get all the repos bound to the consumers in consideration
            # and find intersection of repo_criteria_ids and consumer_repo_ids
            bind_criteria = Criteria(
                filters={"consumer_id": {
                    "$in": consumer_ids
                }})
            consumer_repo_ids = [
                b['repo_id']
                for b in bind_manager.find_by_criteria(bind_criteria)
            ]
            if not repo_criteria_ids:
                repo_criteria_ids = list(set(consumer_repo_ids))
            else:
                repo_criteria_ids = list(
                    set(consumer_repo_ids) & set(repo_criteria_ids))
            if not repo_criteria_ids:
                return result

        # Create a dictionary with consumer profile and repo_ids bound to the consumer keyed by consumer id
        consumer_profile_and_repo_ids = {}
        all_relevant_repo_ids = set()
        for consumer_id in consumer_ids:
            # Find repos bound to the consumer in consideration and find an intersection of bound repos to the
            # repos specified by repo_criteria
            consumer_bound_repo_ids = [
                b['repo_id']
                for b in bind_manager.find_by_consumer(consumer_id)
            ]
            consumer_bound_repo_ids = list(set(consumer_bound_repo_ids))
            # If repo_criteria is not specified, use repos bound to the consumer, else take intersection
            # of repos specified in the criteria and repos bound to the consumer.
            if repo_criteria_ids is None:
                repo_ids = consumer_bound_repo_ids
            else:
                repo_ids = list(
                    set(consumer_bound_repo_ids) & set(repo_criteria_ids))

            if repo_ids:
                # Save all eligible repo ids to get relevant plugin unit keys when unit_criteria is not specified
                all_relevant_repo_ids = (all_relevant_repo_ids | set(repo_ids))
                consumer_profile_and_repo_ids[consumer_id] = {
                    'repo_ids': repo_ids
                }
                consumer_profile_and_repo_ids[consumer_id][
                    'profiled_consumer'] = self.__profiled_consumer(
                        consumer_id)

        if not unit_criteria:
            return result

        # Call respective profiler api according to the unit type to check for applicability
        for unit_type_id, criteria in unit_criteria.items():
            # Find a profiler for each type id and find units applicable using that profiler.
            profiler, cfg = self.__profiler(unit_type_id)
            call_config = PluginCallConfiguration(
                plugin_config=cfg,
                repo_plugin_config=None,
                override_config=override_config)
            try:
                report_list = profiler.find_applicable_units(
                    consumer_profile_and_repo_ids, unit_type_id, criteria,
                    call_config, conduit)
            except PulpExecutionException:
                report_list = None

            if report_list is None:
                _LOG.warn(
                    "Profiler for unit type [%s] is not returning applicability reports"
                    % unit_type_id)
            else:
                result[unit_type_id] = report_list

        return result