Пример #1
0
    def bind(self, consumer_id, repo_id, distributor_id, options):
        """
        Request the agent to perform the specified bind. This method will be called
        after the server-side representation of the binding has been created.

        :param consumer_id: The consumer ID.
        :type consumer_id: str
        :param repo_id: A repository ID.
        :type repo_id: str
        :param distributor_id: A distributor ID.
        :type distributor_id: str
        :param options: The options are handler specific.
        :type options: dict
        """
        # agent request
        consumer_manager = managers.consumer_manager()
        binding_manager = managers.consumer_bind_manager()

        consumer = consumer_manager.get_consumer(consumer_id)
        binding = binding_manager.get_bind(consumer_id, repo_id, distributor_id)

        agent_bindings = self.__bindings([binding])
        agent = PulpAgent(consumer)
        agent.consumer.bind(agent_bindings, options)

        # request tracking
        action_id = factory.context().call_request_id
        consumer_manager = managers.consumer_bind_manager()
        consumer_manager.action_pending(
            consumer_id,
            repo_id,
            distributor_id,
            Bind.Action.BIND,
            action_id)
Пример #2
0
    def test_bind(self):

        # Setup
        self.populate()

        # Test
        options = {}
        itinerary = bind_itinerary(
            self.CONSUMER_ID,
            self.REPO_ID,
            self.DISTRIBUTOR_ID,
            self.NOTIFY_AGENT,
            self.BINDING_CONFIG,
            options)
        call_reports = self.coordinator.execute_multiple_calls(itinerary)

        # Verify
        self.assertEqual(len(call_reports), 2)
        self.assertEqual(call_reports[0].call_request_tags, self.BIND_TAGS)
        self.assertEqual(call_reports[1].call_request_tags, self.AGENT_BIND_TAGS)
        for call in call_reports:
            self.assertNotEqual(call.state, dispatch_constants.CALL_REJECTED_RESPONSE)

        # run task #1 (actual bind)
        self.run_next()

        # verify bind created
        manager = factory.consumer_bind_manager()
        binds = manager.find_by_consumer(self.CONSUMER_ID)
        self.assertEquals(len(binds), 1)
        bind = binds[0]
        self.assertEqual(bind['consumer_id'], self.CONSUMER_ID)
        self.assertEqual(bind['repo_id'], self.REPO_ID)
        self.assertEqual(bind['distributor_id'], self.DISTRIBUTOR_ID)
        self.assertEqual(bind['notify_agent'], self.NOTIFY_AGENT)
        self.assertEqual(bind['binding_config'], self.BINDING_CONFIG)

        # run task #2 (notify consumer)
        self.run_next()

        # verify pending consumer request (pending)
        request_id = call_reports[1].call_request_id
        bind = manager.get_bind(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID)
        actions = bind['consumer_actions']
        self.assertEqual(len(actions), 1)
        self.assertEqual(actions[0]['id'], request_id)
        self.assertEqual(actions[0]['action'], Bind.Action.BIND)
        self.assertEqual(actions[0]['status'], Bind.Status.PENDING)
        self.assertTrue(isinstance(actions[0]['timestamp'], float))

        # verify agent notified
        self.assertTrue(mock_agent.Consumer.bind.called)
        # simulated asynchronous task result
        report = DispatchReport()
        self.coordinator.complete_call_success(request_id, report.dict())

        # verify pending consumer request (confirmed)
        manager = factory.consumer_bind_manager()
        bind = manager.get_bind(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID)
        self.assertEqual(len(bind['consumer_actions']), 0)
Пример #3
0
    def bind(consumer_id, repo_id, distributor_id, options):
        """
        Request the agent to perform the specified bind. This method will be called
        after the server-side representation of the binding has been created.

        :param consumer_id: The consumer ID.
        :type consumer_id: str
        :param repo_id: A repository ID.
        :type repo_id: str
        :param distributor_id: A distributor ID.
        :type distributor_id: str
        :param options: The options are handler specific.
        :type options: dict
        :return: The task created by the bind
        :rtype: dict
        """
        # track agent operations using a pseudo task
        task_id = str(uuid4())
        tags = [
            resource_tag(dispatch_constants.RESOURCE_CONSUMER_TYPE, consumer_id),
            resource_tag(dispatch_constants.RESOURCE_REPOSITORY_TYPE, repo_id),
            resource_tag(dispatch_constants.RESOURCE_REPOSITORY_DISTRIBUTOR_TYPE, distributor_id),
            action_tag(ACTION_AGENT_BIND)
        ]
        task = TaskStatusManager.create_task_status(task_id, 'agent', tags=tags)

        # agent request
        consumer_manager = managers.consumer_manager()
        binding_manager = managers.consumer_bind_manager()
        consumer = consumer_manager.get_consumer(consumer_id)
        binding = binding_manager.get_bind(consumer_id, repo_id, distributor_id)
        agent_bindings = AgentManager._bindings([binding])
        context = Context(
            consumer,
            task_id=task_id,
            action='bind',
            consumer_id=consumer_id,
            repo_id=repo_id,
            distributor_id=distributor_id)
        agent = PulpAgent()
        agent.consumer.bind(context, agent_bindings, options)

        # bind action tracking
        consumer_manager = managers.consumer_bind_manager()
        consumer_manager.action_pending(
            consumer_id,
            repo_id,
            distributor_id,
            Bind.Action.BIND,
            task_id)

        return task
Пример #4
0
 def test_consumer_unregister_cleanup(self):
     # Setup
     self.test_bind()
     manager = factory.consumer_bind_manager()
     binds = manager.find_by_consumer(self.CONSUMER_ID)
     self.assertEquals(len(binds), 1)
     # Test
     manager = factory.consumer_manager()
     manager.unregister(self.CONSUMER_ID)
     # Verify
     manager = factory.consumer_bind_manager()
     binds = manager.find_by_consumer(self.CONSUMER_ID)
     self.assertEquals(len(binds), 0)
Пример #5
0
 def test_remove_repo_cleanup(self):
     # Setup
     self.test_bind()
     manager = factory.consumer_bind_manager()
     binds = manager.find_by_repo(self.REPO_ID)
     self.assertEquals(len(binds), 1)
     # Test
     manager = factory.repo_manager()
     manager.delete_repo(self.REPO_ID)
     # Verify
     manager = factory.consumer_bind_manager()
     binds = manager.find_by_repo(self.REPO_ID)
     self.assertEquals(len(binds), 0)
Пример #6
0
 def test_remove_distributor_cleanup(self):
     # Setup
     self.test_bind()
     manager = factory.consumer_bind_manager()
     binds = manager.find_by_distributor(self.REPO_ID, self.DISTRIBUTOR_ID)
     self.assertEquals(len(binds), 1)
     # Test
     manager = factory.repo_distributor_manager()
     manager.remove_distributor(self.REPO_ID, self.DISTRIBUTOR_ID)
     # Verify
     manager = factory.consumer_bind_manager()
     binds = manager.find_by_distributor(self.REPO_ID, self.DISTRIBUTOR_ID)
     self.assertEquals(len(binds), 0)
Пример #7
0
 def test_consumer_unregister_cleanup(self, *unused):
     self.populate()
     manager = factory.consumer_bind_manager()
     manager.bind(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID, self.NOTIFY_AGENT, self.BINDING_CONFIG)
     manager = factory.consumer_bind_manager()
     binds = manager.find_by_consumer(self.CONSUMER_ID)
     self.assertEqual(len(binds), 1)
     # Test
     manager = factory.consumer_manager()
     manager.unregister(self.CONSUMER_ID)
     # Verify
     manager = factory.consumer_bind_manager()
     binds = manager.find_by_consumer(self.CONSUMER_ID)
     self.assertEqual(len(binds), 0)
Пример #8
0
    def test_unbind(self, mock_repo_qs):
        # Setup
        self.populate()
        manager = factory.consumer_bind_manager()
        manager.bind(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID, self.NOTIFY_AGENT, self.BINDING_CONFIG)
        # Test
        manager = factory.consumer_bind_manager()
        manager.unbind(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID)

        # Verify
        collection = Bind.get_collection()
        bind_id = dict(consumer_id=self.CONSUMER_ID, repo_id=self.REPO_ID, distributor_id=self.DISTRIBUTOR_ID)
        bind = collection.find_one(bind_id)
        self.assertTrue(bind is not None)
        self.assertTrue(bind["deleted"])
 def test_get_with_bindings(self):
     """
     Test consumer with bindings.
     """
     # Setup
     manager = factory.repo_manager()
     repo = manager.create_repo(self.REPO_ID)
     manager = factory.repo_distributor_manager()
     manager.add_distributor(self.REPO_ID, self.DISTRIBUTOR_TYPE_ID, {}, True, distributor_id=self.DISTRIBUTOR_ID)
     manager = factory.consumer_manager()
     manager.register(self.CONSUMER_ID)
     manager = factory.consumer_bind_manager()
     bind = manager.bind(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID)
     # Test
     params = {"bindings": True}
     path = "/v2/consumers/%s/" % self.CONSUMER_ID
     status, body = self.get(path, params=params)
     # Verify
     self.assertEqual(200, status)
     self.assertEqual(self.CONSUMER_ID, body["id"])
     self.assertTrue("_href" in body)
     self.assertTrue(body["_href"].endswith(path))
     self.assertTrue("bindings" in body)
     bindings = body["bindings"]
     self.assertEquals(len(bindings), 1)
     self.assertEquals(bindings[0], self.REPO_ID)
Пример #10
0
def force_unbind(consumer_id, repo_id, distributor_id, options):
    """
    Get the unbind itinerary.
    A forced unbind immediately deletes the binding instead
    of marking it deleted and going through that lifecycle.
    It is intended to be used to clean up orphaned bindings
    caused by failed/unconfirmed unbind actions on the consumer.
    The itinerary is:
      1. Delete the binding on the server.
      2. Request that the consumer (agent) perform the unbind.
    :param consumer_id: A consumer ID.
    :type consumer_id: str
    :param repo_id: A repository ID.
    :type repo_id: str
    :param distributor_id: A distributor ID.
    :type distributor_id: str
    :param options: Unbind options passed to the agent handler.
    :type options: dict
    :returns TaskResult containing the result of the unbind & any spawned tasks or a dictionary
             of the unbind result if no tasks were spawned.
    :rtype: TaskResult
    """

    bind_manager = managers.consumer_bind_manager()
    binding = bind_manager.get_bind(consumer_id, repo_id, distributor_id)
    bind_manager.delete(consumer_id, repo_id, distributor_id, True)
    response = None

    if binding['notify_agent']:
        agent_manager = managers.consumer_agent_manager()
        task = agent_manager.unbind(consumer_id, repo_id, distributor_id, options)
        response = TaskResult(spawned_tasks=[task])

    return response
Пример #11
0
 def test_delete(self):
     # Setup
     self.populate()
     manager = factory.consumer_bind_manager()
     bind = manager.bind(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID)
     # Test
     manager.delete(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID)
Пример #12
0
 def test_bind_action_failed(self, mock_repo_qs):
     self.populate()
     manager = factory.consumer_bind_manager()
     manager.bind(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID, self.NOTIFY_AGENT, self.BINDING_CONFIG)
     bind = manager.get_bind(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID)
     self.assertEqual(bind["consumer_actions"], [])
     for action_id in self.ACTION_IDS:
         manager.action_pending(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID, Bind.Action.BIND, action_id)
     bind = manager.get_bind(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID)
     actions = bind["consumer_actions"]
     for i in range(0, len(self.ACTION_IDS)):
         self.assertEqual(actions[i]["id"], self.ACTION_IDS[i])
         self.assertEqual(actions[i]["action"], Bind.Action.BIND)
         self.assertEqual(actions[i]["status"], Bind.Status.PENDING)
     manager.action_failed(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID, self.ACTION_IDS[5])
     bind = manager.get_bind(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID)
     actions = bind["consumer_actions"]
     self.assertEqual(len(actions), 9)
     for i in range(0, len(self.ACTION_IDS)):
         if i == 5:
             status = Bind.Status.FAILED
         else:
             status = Bind.Status.PENDING
         self.assertEqual(actions[i]["id"], self.ACTION_IDS[i])
         self.assertEqual(actions[i]["action"], Bind.Action.BIND)
         self.assertEqual(actions[i]["status"], status)
     manager.action_succeeded(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID, self.ACTION_IDS[6])
     bind = manager.get_bind(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID)
     actions = bind["consumer_actions"]
     self.assertEqual(len(actions), 2)
Пример #13
0
 def test_get_bind_not_found(self, mock_repo_qs):
     # Setup
     self.populate()
     manager = factory.consumer_bind_manager()
     manager.bind(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID, self.NOTIFY_AGENT, self.BINDING_CONFIG)
     # Test
     self.assertRaises(MissingResource, manager.get_bind, "A", "B", "C")
Пример #14
0
def expand_consumers(options, consumers):
    """
    Expand a list of users based on flags specified in the
    post body or query parameters.  The _href is always added by the
    serialization function used.
    Supported options:
      details - synonym for: (bindings=True,)
      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
    """
    if options.get('details', False):
        options['bindings'] = True
    # add bindings
    if options.get('bindings', False):
        ids = [c['id'] for c in consumers]
        manager = managers.consumer_bind_manager()
        bindings = manager.find_by_consumer_list(ids)
        for consumer in consumers:
            id = consumer['id']
            consumer['bindings'] = \
                [b['repo_id'] for b in bindings.get(id, [])]
    return consumers
Пример #15
0
    def test_forced_unbind(self, mock_unbind_itinerary):

        # Setup
        self.populate()
        manager = factory.consumer_bind_manager()
        bind = manager.bind(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID)

        # Test
        path = '/v2/consumers/%s/bindings/%s/%s/' %\
               (self.CONSUMER_ID,
                self.REPO_ID,
                self.DISTRIBUTOR_ID)
        body = {'force':True}
        status, body = self.delete(path, body)

        # Verify
        self.assertEquals(status, 202)
        self.assertEqual(len(body), 3)
        for call in body:
            self.assertNotEqual(call['state'], dispatch_constants.CALL_REJECTED_RESPONSE)

        # verify itinerary called
        mock_unbind_itinerary.assert_called_with(
            self.CONSUMER_ID,
            self.REPO_ID,
            self.DISTRIBUTOR_ID,
            {},
            True)
Пример #16
0
 def populate(self, strategy=constants.DEFAULT_STRATEGY, ssl=False):
     PluginTestBase.populate(self)
     # register child
     manager = managers.consumer_manager()
     manager.register(self.PULP_ID, notes={constants.STRATEGY_NOTE_KEY: strategy})
     manager = managers.repo_importer_manager()
     # add importer
     importer_conf = {
         constants.MANIFEST_URL_KEYWORD: 'http://redhat.com',
         constants.STRATEGY_KEYWORD: constants.DEFAULT_STRATEGY,
         constants.PROTOCOL_KEYWORD: 'file',
     }
     manager.set_importer(self.REPO_ID, constants.HTTP_IMPORTER, importer_conf)
     # add distributors
     if ssl:
         dist_conf = self.dist_conf_with_ssl()
     else:
         dist_conf = self.dist_conf()
     manager = managers.repo_distributor_manager()
     manager.add_distributor(
         self.REPO_ID,
         constants.HTTP_DISTRIBUTOR,
         dist_conf,
         False,
         constants.HTTP_DISTRIBUTOR)
     manager.add_distributor(self.REPO_ID, FAKE_DISTRIBUTOR, {}, False, FAKE_DISTRIBUTOR)
     # bind
     conf = {constants.STRATEGY_KEYWORD: strategy}
     manager = managers.consumer_bind_manager()
     manager.bind(self.PULP_ID, self.REPO_ID, constants.HTTP_DISTRIBUTOR, False, conf)
Пример #17
0
def expand_consumers(options, consumers):
    """
    Expand a list of users based on flags specified in the
    post body or query parameters.  The _href is always added by the
    serialization function used.
    Supported options:
      details - synonym for: (bindings=True,)
      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
    """
    if options.get('details', False):
        options['bindings'] = True
    # add bindings
    if options.get('bindings', False):
        ids = [c['id'] for c in consumers]
        manager = managers.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 _consumer in consumers:
            _consumer['bindings'] = \
                [serialization.binding.serialize(b, False)
                    for b in collated.get(_consumer['id'], [])]
    return consumers
Пример #18
0
    def GET(self, consumer_id, repo_id=None):
        """
        Fetch all bind objects referencing the specified consumer_id. Optionally,
        specify a repo_id to fetch all bind objects for the consumer_id to the repo_id

        :param consumer_id: The specified consumer.
        :type  consumer_id: str
        :param repo_id:     The repository to retrieve bindings for (optional)
        :type  repo_id:     str

        :return: A list of dictionaries that represent pulp.server.db.model.consumer.Bind objects
        :rtype:  list
        """
        # Check to make sure the resources exist
        missing_resources = {}
        if repo_id is not None:
            repo = managers.repo_query_manager().find_by_id(repo_id)
            if repo is None:
                missing_resources['repo_id'] = repo_id
        # If get_consumer raises MissingResource we might miss reporting a bad repo_id
        try:
            managers.consumer_manager().get_consumer(consumer_id)
        except MissingResource:
            missing_resources['consumer_id'] = consumer_id

        if len(missing_resources) > 0:
            raise MissingResource(**missing_resources)

        manager = managers.consumer_bind_manager()
        bindings = manager.find_by_consumer(consumer_id, repo_id)
        bindings = [serialization.binding.serialize(b) for b in bindings]
        return self.ok(bindings)
Пример #19
0
def delete(repo_id):
    """
    Get the itinerary for deleting a repository.
      1. Delete the repository on the sever.
      2. Unbind any bound consumers.
    :param repo_id: A repository ID.
    :type repo_id: str
    :return: A TaskRequest object with the details of any errors or spawned tasks
    :rtype TaskRequest
    """
    # delete repository
    manager = managers.repo_manager()
    manager.delete_repo(repo_id)

    # append unbind itineraries foreach bound consumer
    options = {}
    manager = managers.consumer_bind_manager()

    additional_tasks = []
    errors = []
    for bind in manager.find_by_repo(repo_id):
        try:
            report = consumer.unbind(bind["consumer_id"], bind["repo_id"], bind["distributor_id"], options)
            if report:
                additional_tasks.extend(report.spawned_tasks)
        except Exception, e:
            errors.append(e)
Пример #20
0
 def test_bind_request_succeeded(self):
     # Setup
     self.populate()
     # Test
     manager = factory.consumer_bind_manager()
     manager.bind(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID)
     bind = manager.get_bind(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID)
     self.assertEqual(bind['consumer_actions'], [])
     for action_id in self.ACTION_IDS:
         manager.action_pending(
             self.CONSUMER_ID,
             self.REPO_ID,
             self.DISTRIBUTOR_ID,
             Bind.Action.BIND,
             action_id)
     bind = manager.get_bind(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID)
     actions = bind['consumer_actions']
     for i in range(0, len(self.ACTION_IDS)):
         self.assertEqual(actions[i]['id'], self.ACTION_IDS[i])
         self.assertEqual(actions[i]['action'], Bind.Action.BIND)
         self.assertEqual(actions[i]['status'], Bind.Status.PENDING)
     manager.action_succeeded(
         self.CONSUMER_ID,
         self.REPO_ID,
         self.DISTRIBUTOR_ID,
         self.ACTION_IDS[4])
     bind = manager.get_bind(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID)
     actions = bind['consumer_actions']
     self.assertEqual(len(actions), 4)
Пример #21
0
def distributor_delete(repo_id, distributor_id):
    """
    Get the itinerary for deleting a repository distributor.
      1. Delete the distributor on the sever.
      2. Unbind any bound consumers.
    :param repo_id: A repository ID.
    :type repo_id: str
    :param distributor_id: A distributor id
    :type distributor_id: str
    :return: Any errors that may have occurred and the list of tasks spawned for each consumer
    :rtype TaskResult
    """
    # delete distributor

    manager = managers.repo_distributor_manager()
    manager.remove_distributor(repo_id, distributor_id)

    # append unbind itineraries foreach bound consumer

    unbind_errors = []
    additional_tasks = []
    options = {}
    manager = managers.consumer_bind_manager()
    for bind in manager.find_by_distributor(repo_id, distributor_id):
        try:
            report = consumer.unbind(bind["consumer_id"], bind["repo_id"], bind["distributor_id"], options)
            if report:
                additional_tasks.extend(report.spawned_tasks)
        except Exception, e:
            unbind_errors.append(e)
Пример #22
0
def repo_delete_itinerary(repo_id):
    """
    Get the itinerary for deleting a repository.
      1. Delete the repository on the sever.
      2. Unbind any bound consumers.
    @param repo_id: A repository ID.
    @type repo_id: str
    @return: A list of call_requests known as an itinerary.
    @rtype list
    """

    call_requests = []

    # delete repository

    manager = managers.repo_manager()
    resources = {dispatch_constants.RESOURCE_REPOSITORY_TYPE: {repo_id: dispatch_constants.RESOURCE_DELETE_OPERATION}}

    tags = [resource_tag(dispatch_constants.RESOURCE_REPOSITORY_TYPE, repo_id), action_tag("delete")]

    delete_request = CallRequest(manager.delete_repo, [repo_id], resources=resources, tags=tags, archive=True)

    call_requests.append(delete_request)

    # append unbind itineraries foreach bound consumer

    options = {}
    manager = managers.consumer_bind_manager()
    for bind in manager.find_by_repo(repo_id):
        unbind_requests = unbind_itinerary(bind["consumer_id"], bind["repo_id"], bind["distributor_id"], options)
        if unbind_requests:
            unbind_requests[0].depends_on(delete_request.id)
            call_requests.extend(unbind_requests)

    return call_requests
Пример #23
0
 def test_get_bind_not_found(self):
     # Setup
     self.populate()
     manager = factory.consumer_bind_manager()
     manager.bind(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID)
     # Test
     self.assertRaises(MissingResource, manager.get_bind, 'A', 'B', 'C')
Пример #24
0
 def test_consumer_unregister_cleanup(self):
     # Setup
     self.populate()
     # Test
     manager = factory.consumer_bind_manager()
     manager.bind(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID)
     manager = factory.consumer_bind_manager()
     binds = manager.find_by_consumer(self.CONSUMER_ID)
     self.assertEquals(len(binds), 1)
     # Test
     manager = factory.consumer_manager()
     manager.unregister(self.CONSUMER_ID)
     # Verify
     manager = factory.consumer_bind_manager()
     binds = manager.find_by_consumer(self.CONSUMER_ID)
     self.assertEquals(len(binds), 0)
Пример #25
0
def delete(repo_id, dist_id):
    """
    Removes a distributor from a repository and unbinds any bound consumers.

    :param distributor: distributor to be deleted
    :type  distributor: pulp.server.db.model.Distributor

    :return: result containing any errors and tasks spawned
    :rtype pulp.server.async.tasks.TaskResult
    """

    distributor = model.Distributor.objects.get_or_404(repo_id=repo_id, distributor_id=dist_id)
    managers.repo_publish_schedule_manager().delete_by_distributor_id(repo_id, dist_id)

    # Call the distributor's cleanup method
    dist_instance, plugin_config = plugin_api.get_distributor_by_id(distributor.distributor_type_id)

    call_config = PluginCallConfiguration(plugin_config, distributor.config)
    repo = model.Repository.objects.get_repo_or_missing_resource(repo_id)
    dist_instance.distributor_removed(repo.to_transfer_repo(), call_config)
    distributor.delete()

    unbind_errors = []
    additional_tasks = []
    options = {}

    bind_manager = managers.consumer_bind_manager()
    for bind in bind_manager.find_by_distributor(repo_id, dist_id):
        try:
            report = bind_manager.unbind(bind['consumer_id'], bind['repo_id'],
                                         bind['distributor_id'], options)
            if report:
                additional_tasks.extend(report.spawned_tasks)
        except Exception, e:
            unbind_errors.append(e)
Пример #26
0
 def unbind(self, consumer_id, repo_id, distributor_id, options):
     """
     Request the agent to perform the specified unbind.
     @param consumer_id: The consumer ID.
     @type consumer_id: str
     @param repo_id: A repository ID.
     @type repo_id: str
     @param distributor_id: A distributor ID.
     @type distributor_id: str
     @param options: The options are handler specific.
     @type options: dict
     """
     # agent request
     manager = managers.consumer_manager()
     consumer = manager.get_consumer(consumer_id)
     binding = dict(repo_id=repo_id, distributor_id=distributor_id)
     bindings = self.__unbindings([binding])
     agent = PulpAgent(consumer)
     agent.consumer.unbind(bindings, options)
     # request tracking
     action_id = factory.context().call_request_id
     manager = managers.consumer_bind_manager()
     manager.action_pending(
         consumer_id,
         repo_id,
         distributor_id,
         Bind.Action.UNBIND,
         action_id)
Пример #27
0
    def test_forced_unbind_agent_not_notified(self):

        # Setup
        self.populate()
        manager = factory.consumer_bind_manager()
        bind = manager.bind(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID,
                            False, self.BINDING_CONFIG)

        # Test
        options = {}
        itinerary = forced_unbind_itinerary(
            self.CONSUMER_ID,
            self.REPO_ID,
            self.DISTRIBUTOR_ID,
            options)

        call_reports = self.coordinator.execute_multiple_calls(itinerary)

        # Verify
        self.assertEqual(len(call_reports), 1)
        self.assertEqual(call_reports[0].call_request_tags, self.UNBIND_TAGS)
        for call in call_reports:
            self.assertNotEqual(call.state, dispatch_constants.CALL_REJECTED_RESPONSE)

        # run task #1 (actual delete)
        self.run_next()

        # verify bind deleted
        collection = Bind.get_collection()
        bind = collection.find_one(self.QUERY)
        self.assertTrue(bind is None)

        # verify agent notified
        self.assertFalse(mock_agent.Consumer.unbind.called)
Пример #28
0
 def DELETE(self, consumer_id, repo_id, distributor_id):
     """
     Delete a bind association between the specified
     consumer and repo-distributor.  Designed to be idempotent.
     @param consumer_id: A consumer ID.
     @type consumer_id: str
     @param repo_id: A repo ID.
     @type repo_id: str
     @param distributor_id: A distributor ID.
     @type distributor_id: str
     @return: The list of call_reports
     @rtype: list
     """
     body = self.params()
     # validate resources
     manager = managers.consumer_bind_manager()
     binding = manager.get_bind(consumer_id, repo_id, distributor_id)
     notify_agent = binding['notify_agent']
     # delete (unbind)
     forced = body.get('force', False)
     options = body.get('options', {})
     if forced or not notify_agent:
         call_requests = forced_unbind_itinerary(
             consumer_id,
             repo_id,
             distributor_id,
             options)
     else:
         call_requests = unbind_itinerary(
             consumer_id,
             repo_id,
             distributor_id,
             options)
     execution.execute_multiple(call_requests)
Пример #29
0
 def test_find_by_criteria(self, mock_repo_qs):
     self.populate()
     manager = factory.consumer_bind_manager()
     manager.bind(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID,
                  self.NOTIFY_AGENT, self.BINDING_CONFIG)
     # Test
     criteria = Criteria({'consumer_id': self.CONSUMER_ID})
     bindings = manager.find_by_criteria(criteria)
     bind = bindings[0]
     self.assertEqual(len(bindings), 1)
     self.assertEqual(bind['consumer_id'], self.CONSUMER_ID)
     self.assertEqual(bind['repo_id'], self.REPO_ID)
     self.assertEqual(bind['distributor_id'], self.DISTRIBUTOR_ID)
     self.assertEqual(bind['notify_agent'], self.NOTIFY_AGENT)
     self.assertEqual(bind['binding_config'], self.BINDING_CONFIG)
     # Test ($in)
     criteria = Criteria({'consumer_id': {'$in': [self.CONSUMER_ID]}})
     bindings = manager.find_by_criteria(criteria)
     bind = bindings[0]
     self.assertEqual(len(bindings), 1)
     self.assertEqual(bind['consumer_id'], self.CONSUMER_ID)
     self.assertEqual(bind['repo_id'], self.REPO_ID)
     self.assertEqual(bind['distributor_id'], self.DISTRIBUTOR_ID)
     self.assertEqual(bind['notify_agent'], self.NOTIFY_AGENT)
     self.assertEqual(bind['binding_config'], self.BINDING_CONFIG)
Пример #30
0
 def test_get_with_bindings(self):
     """
     Test consumer with bindings.
     """
     # Setup
     manager = factory.repo_manager()
     repo = manager.create_repo(self.REPO_ID)
     manager = factory.repo_distributor_manager()
     manager.add_distributor(
         self.REPO_ID,
         self.DISTRIBUTOR_TYPE_ID,
         {},
         True,
         distributor_id=self.DISTRIBUTOR_ID)
     manager = factory.consumer_manager()
     manager.register(self.CONSUMER_ID)
     manager = factory.consumer_bind_manager()
     bind = manager.bind(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID)
     # Test
     params = {'bindings':True}
     path = '/v2/consumers/%s/' % self.CONSUMER_ID
     status, body = self.get(path, params=params)
     # Verify
     self.assertEqual(200, status)
     self.assertEqual(self.CONSUMER_ID, body['id'])
     self.assertTrue('_href' in body)
     self.assertTrue(body['_href'].endswith(path))
     self.assertTrue('bindings' in body)
     bindings = body['bindings']
     self.assertEquals(len(bindings), 1)
     self.assertEquals(bindings[0]['repo_id'], self.REPO_ID)
     self.assertEquals(bindings[0]['distributor_id'], self.DISTRIBUTOR_ID)
     self.assertEquals(bindings[0]['consumer_actions'], [])
Пример #31
0
 def test_delete(self):
     # Setup
     self.populate()
     manager = factory.consumer_bind_manager()
     for consumer_id in self.ALL_CONSUMERS:
         manager.bind(consumer_id, self.REPO_ID, self.DISTRIBUTOR_ID,
                      self.NOTIFY_AGENT, self.BINDING_CONFIG)
     manager.action_pending(self.EXTRA_CONSUMER_1, self.REPO_ID,
                            self.DISTRIBUTOR_ID, Bind.Action.BIND, '1')
     manager.action_pending(self.EXTRA_CONSUMER_2, self.REPO_ID,
                            self.DISTRIBUTOR_ID, Bind.Action.BIND, '2')
     # Test
     manager.mark_deleted(self.CONSUMER_ID, self.REPO_ID,
                          self.DISTRIBUTOR_ID)
     manager.delete(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID)
     # Verify
     self.assertRaises(MissingResource, manager.get_bind, self.CONSUMER_ID,
                       self.REPO_ID, self.DISTRIBUTOR_ID)
     manager.get_bind(self.EXTRA_CONSUMER_1, self.REPO_ID,
                      self.DISTRIBUTOR_ID)
     manager.get_bind(self.EXTRA_CONSUMER_2, self.REPO_ID,
                      self.DISTRIBUTOR_ID)
Пример #32
0
    def get(self, request, consumer_id, repo_id, distributor_id):
        """
        Fetch a specific bind object which represents a specific association
        between a consumer and repo-distributor.

        :param request: WSGI request object
        :type request: django.core.handlers.wsgi.WSGIRequest
        :param consumer_id: A consumer ID.
        :type consumer_id: str
        :param repo_id: A repo ID.
        :type repo_id: str
        :param distributor_id: A distributor ID.
        :type distributor_id: str

        :return: Response representing the binding
        :rtype: django.http.HttpResponse
        """

        manager = factory.consumer_bind_manager()
        bind = manager.get_bind(consumer_id, repo_id, distributor_id)
        serialized_bind = serialization.binding.serialize(bind)
        return generate_json_response_with_pulp_encoder(serialized_bind)
Пример #33
0
def bind(consumer_id, repo_id, distributor_id, notify_agent, binding_config,
         agent_options):
    """
    Bind a repo to a consumer:
      1. Create the binding on the server.
      2. Request that the consumer (agent) perform the bind.
    :param consumer_id: A consumer ID.
    :type consumer_id: str
    :param repo_id: A repository ID.
    :type repo_id: str
    :param distributor_id: A distributor ID.
    :type distributor_id: str
    :param agent_options: Bind options passed to the agent handler.
    :type agent_options: dict
    :param notify_agent: indicates if the agent should be sent a message about the new binding
    :type  notify_agent: bool
    :param binding_config: configuration options to use when generating the payload for this binding

    :returns TaskResult containing the result of the bind & any spawned tasks or a dictionary
             of the bind result if no tasks were spawned.
    :rtype: TaskResult

    :raises pulp.server.exceptions.MissingResource: when given consumer does not exist
    """
    # Create the binding on the server
    bind_manager = managers.consumer_bind_manager()
    binding = bind_manager.bind(consumer_id, repo_id, distributor_id,
                                notify_agent, binding_config)

    response = TaskResult(result=binding)

    # Notify the agents of the binding
    if notify_agent:
        agent_manager = managers.consumer_agent_manager()
        task = agent_manager.bind(consumer_id, repo_id, distributor_id,
                                  agent_options)
        response.spawned_tasks.append(task)

    return response
Пример #34
0
def delete(repo_id, dist_id):
    """
    Removes a distributor from a repository and unbinds any bound consumers.

    :param distributor: distributor to be deleted
    :type  distributor: pulp.server.db.model.Distributor

    :return: result containing any errors and tasks spawned
    :rtype pulp.server.async.tasks.TaskResult
    """

    distributor = model.Distributor.objects.get_or_404(repo_id=repo_id,
                                                       distributor_id=dist_id)
    managers.repo_publish_schedule_manager().delete_by_distributor_id(
        repo_id, dist_id)

    # Call the distributor's cleanup method
    dist_instance, plugin_config = plugin_api.get_distributor_by_id(
        distributor.distributor_type_id)

    call_config = PluginCallConfiguration(plugin_config, distributor.config)
    repo = model.Repository.objects.get_repo_or_missing_resource(repo_id)
    dist_instance.distributor_removed(repo.to_transfer_repo(), call_config)
    distributor.delete()

    unbind_errors = []
    additional_tasks = []
    options = {}

    bind_manager = managers.consumer_bind_manager()
    for bind in bind_manager.find_by_distributor(repo_id, dist_id):
        try:
            report = bind_manager.unbind(bind['consumer_id'], bind['repo_id'],
                                         bind['distributor_id'], options)
            if report:
                additional_tasks.extend(report.spawned_tasks)
        except Exception, e:
            unbind_errors.append(e)
Пример #35
0
    def get(self, request, consumer_id, repo_id=None):
        """
        Fetch all bind objects referencing the specified consumer_id. Optionally,
        specify a repo_id to fetch all bind objects for the consumer_id to the repo_id.

        :param request: WSGI request object
        :type request: django.core.handlers.wsgi.WSGIRequest
        :param consumer_id: The specified consumer.
        :type  consumer_id: str
        :param repo_id: The repository to retrieve bindings for (optional)
        :type  repo_id: str

        :raises MissingResource: if some resource is missing

        :return: Response representing the bindings
        :rtype: django.http.HttpResponse
        """

        # Check to make sure the resources exist
        missing_resources = {}
        if repo_id is not None:
            repo = model.Repository.objects(repo_id).first()
            if repo is None:
                missing_resources['repo_id'] = repo_id

        # If get_consumer raises MissingResource we might miss reporting a bad repo_id
        try:
            factory.consumer_manager().get_consumer(consumer_id)
        except MissingResource:
            missing_resources['consumer_id'] = consumer_id

        if missing_resources:
            raise MissingResource(**missing_resources)

        manager = factory.consumer_bind_manager()
        bindings = manager.find_by_consumer(consumer_id, repo_id)
        bindings = [serial_binding.serialize(b) for b in bindings]
        return generate_json_response_with_pulp_encoder(bindings)
Пример #36
0
 def GET(self, consumer_id, repo_id, distributor_id):
     """
     Fetch a specific bind object which represents a specific association
     between a consumer and repo-distributor.
     @param consumer_id: A consumer ID.
     @type consumer_id: str
     @param repo_id: A repo ID.
     @type repo_id: str
     @param distributor_id: A distributor ID.
     @type distributor_id: str
     @return: A specific bind object:
         {consumer_id:<str>,
          repo_id:<str>,
          distributor_id:<str>,
          href:<str>,
          type_id:<str>,
          details:<dict>}
     @rtype: dict
     """
     manager = managers.consumer_bind_manager()
     bind = manager.get_bind(consumer_id, repo_id, distributor_id)
     serialized_bind = serialization.binding.serialize(bind)
     return self.ok(serialized_bind)
Пример #37
0
def force_unbind(consumer_id, repo_id, distributor_id, options):
    """
    Get the unbind itinerary.
    A forced unbind immediately deletes the binding instead
    of marking it deleted and going through that lifecycle.
    It is intended to be used to clean up orphaned bindings
    caused by failed/unconfirmed unbind actions on the consumer.
    The itinerary is:
      1. Delete the binding on the server.
      2. Request that the consumer (agent) perform the unbind.
    :param consumer_id: A consumer ID.
    :type consumer_id: str
    :param repo_id: A repository ID.
    :type repo_id: str
    :param distributor_id: A distributor ID.
    :type distributor_id: str
    :param options: Unbind options passed to the agent handler.
    :type options: dict
    :returns TaskResult containing the result of the unbind & any spawned tasks or a dictionary
             of the unbind result if no tasks were spawned.
    :rtype: TaskResult
    """

    bind_manager = managers.consumer_bind_manager()
    binding = bind_manager.get_bind(consumer_id, repo_id, distributor_id)
    bind_manager.delete(consumer_id, repo_id, distributor_id, True)

    response = TaskResult()

    if binding['notify_agent']:
        agent_manager = managers.consumer_agent_manager()
        task = agent_manager.unbind(consumer_id, repo_id, distributor_id,
                                    options)
        # we only want the task's ID, not the full task
        response.spawned_tasks.append({'task_id': task['task_id']})

    return response
Пример #38
0
    def test_forced_unbind(self):

        # Setup
        self.populate()
        manager = factory.consumer_bind_manager()
        bind = manager.bind(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID,
                            self.NOTIFY_AGENT, self.BINDING_CONFIG)

        # Test
        options = {}
        itinerary = forced_unbind_itinerary(
            self.CONSUMER_ID,
            self.REPO_ID,
            self.DISTRIBUTOR_ID,
            options)
        call_reports = self.coordinator.execute_multiple_calls(itinerary)

        # Verify
        self.assertEqual(len(call_reports), 2)
        self.assertEqual(call_reports[0].call_request_tags, self.UNBIND_TAGS)
        self.assertEqual(call_reports[1].call_request_tags, self.AGENT_UNBIND_TAGS)
        for call in call_reports:
            self.assertNotEqual(call.state, dispatch_constants.CALL_REJECTED_RESPONSE)

        # run task #1 (actual delete)
        self.run_next()

        # verify bind marked deleted
        collection = Bind.get_collection()
        bind = collection.find_one(self.QUERY)
        self.assertTrue(bind is None)

        # run task #2 (notify consumer)
        self.run_next()

        # verify agent notified
        self.assertTrue(mock_agent.Consumer.unbind.called)
Пример #39
0
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
Пример #40
0
 def unbind(self, consumer_id, repo_id, distributor_id, options):
     """
     Request the agent to perform the specified unbind.
     :param consumer_id: The consumer ID.
     :type consumer_id: str
     :param repo_id: A repository ID.
     :type repo_id: str
     :param distributor_id: A distributor ID.
     :type distributor_id: str
     :param options: The options are handler specific.
     :type options: dict
     """
     # agent request
     manager = managers.consumer_manager()
     consumer = manager.get_consumer(consumer_id)
     binding = dict(repo_id=repo_id, distributor_id=distributor_id)
     bindings = self.__unbindings([binding])
     agent = PulpAgent(consumer)
     agent.consumer.unbind(bindings, options)
     # request tracking
     action_id = factory.context().call_request_id
     manager = managers.consumer_bind_manager()
     manager.action_pending(consumer_id, repo_id, distributor_id,
                            Bind.Action.UNBIND, action_id)
Пример #41
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
Пример #42
0
    def test_search(self):
        # Setup
        self.populate()
        manager = factory.consumer_bind_manager()
        manager.bind(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID,
                     self.NOTIFY_AGENT, self.BINDING_CONFIG)
        manager.action_pending(self.CONSUMER_ID, self.REPO_ID,
                               self.DISTRIBUTOR_ID, Bind.Action.BIND, '0')

        # Test
        criteria = {
            'filters': {
                'consumer_actions.status': {
                    '$in': ['pending', 'failed']
                }
            }
        }
        path = '/v2/consumers/binding/search/'
        body = dict(criteria=criteria)
        status, body = self.post(path, body)

        # Verify
        self.assertEqual(status, 200)
        self.assertEqual(len(body), 1)
Пример #43
0
def update(repo_id, dist_id, config=None, delta=None):
    """
    Update the distributor and (re)bind any bound consumers.

    :param distributor: distributor to be updated
    :type  distributor: pulp.server.db.model.Distributor
    :param config: A configuration dictionary for a distributor instance. The contents of this dict
                   depends on the type of distributor. Values of None will remove they key from the
                   config. Keys ommited from this dictionary will remain unchanged.
    :type  config: dict
    :param delta: A dictionary used to change conf values for a distributor instance. This currently
                  only supports the 'auto_publish' keyword, which should have a value of type bool
    :type  delta: dict or None

    :return: result containing any errors and tasks spawned
    :rtype pulp.server.async.tasks.TaskResult
    """
    repo = model.Repository.objects.get_repo_or_missing_resource(repo_id)
    distributor = model.Distributor.objects.get_or_404(repo_id=repo_id, distributor_id=dist_id)

    for k, v in config.iteritems():
        if v is None:
            distributor.config.pop(k)
        else:
            distributor.config[k] = v

    auto_publish = delta.get('auto_publish') if delta else None
    if isinstance(auto_publish, bool):
        distributor.auto_publish = auto_publish
    elif not isinstance(auto_publish, type(None)):
        raise exceptions.InvalidValue(['auto_publish'])

    # Let the distributor plugin verify the configuration
    distributor_instance, plugin_config = plugin_api.get_distributor_by_id(
        distributor.distributor_type_id)
    call_config = PluginCallConfiguration(plugin_config, distributor.config)
    transfer_repo = repo.to_transfer_repo()
    config_conduit = RepoConfigConduit(distributor.distributor_type_id)

    result = distributor_instance.validate_config(transfer_repo, call_config,
                                                  config_conduit)

    # For backward compatibility with plugins that don't yet return the tuple
    if isinstance(result, bool):
        valid_config = result
        message = None
    else:
        valid_config, message = result

    if not valid_config:
        raise exceptions.PulpDataException(message)
    distributor.save()

    unbind_errors = []
    additional_tasks = []
    options = {}
    bind_manager = managers.consumer_bind_manager()
    for bind in bind_manager.find_by_distributor(distributor.repo_id, distributor.distributor_id):
        try:
            report = bind_manager.bind(bind['consumer_id'], bind['repo_id'], bind['distributor_id'],
                                       bind['notify_agent'], bind['binding_config'], options)
            if report:
                additional_tasks.extend(report.spawned_tasks)
        except Exception, e:
            unbind_errors.append(e)
Пример #44
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)
Пример #45
0
def bind_itinerary(consumer_id, repo_id, distributor_id, notify_agent,
                   binding_config, agent_options):
    """
    Get the bind itinerary:
      1. Create the binding on the server.
      2. Request that the consumer (agent) perform the bind.
    @param consumer_id: A consumer ID.
    @type consumer_id: str
    @param repo_id: A repository ID.
    @type repo_id: str
    @param distributor_id: A distributor ID.
    @type distributor_id: str
    @param agent_options: Bind options passed to the agent handler.
    @type agent_options: dict
    @param notify_agent: indicates if the agent should be sent a message about the new binding
    @type  notify_agent: bool
    @param binding_config: configuration options to use when generating the payload for this binding

    @return: A list of call_requests.
    @rtype list
    """

    call_requests = []
    bind_manager = managers.consumer_bind_manager()
    agent_manager = managers.consumer_agent_manager()

    # bind

    tags = [
        resource_tag(dispatch_constants.RESOURCE_CONSUMER_TYPE, consumer_id),
        resource_tag(dispatch_constants.RESOURCE_REPOSITORY_TYPE, repo_id),
        resource_tag(dispatch_constants.RESOURCE_REPOSITORY_DISTRIBUTOR_TYPE,
                     distributor_id),
        action_tag(ACTION_BIND)
    ]

    args = [
        consumer_id,
        repo_id,
        distributor_id,
        notify_agent,
        binding_config,
    ]

    bind_request = CallRequest(bind_manager.bind, args, weight=0, tags=tags)

    bind_request.reads_resource(dispatch_constants.RESOURCE_CONSUMER_TYPE,
                                consumer_id)
    bind_request.reads_resource(dispatch_constants.RESOURCE_REPOSITORY_TYPE,
                                repo_id)
    bind_request.reads_resource(
        dispatch_constants.RESOURCE_REPOSITORY_DISTRIBUTOR_TYPE,
        distributor_id)

    call_requests.append(bind_request)

    # notify agent

    if notify_agent:
        tags = [
            resource_tag(dispatch_constants.RESOURCE_CONSUMER_TYPE,
                         consumer_id),
            resource_tag(dispatch_constants.RESOURCE_REPOSITORY_TYPE, repo_id),
            resource_tag(
                dispatch_constants.RESOURCE_REPOSITORY_DISTRIBUTOR_TYPE,
                distributor_id),
            action_tag(ACTION_AGENT_BIND)
        ]

        args = [consumer_id, repo_id, distributor_id, agent_options]

        agent_request = CallRequest(agent_manager.bind,
                                    args,
                                    weight=0,
                                    asynchronous=True,
                                    archive=True,
                                    tags=tags)

        agent_request.add_life_cycle_callback(
            dispatch_constants.CALL_SUCCESS_LIFE_CYCLE_CALLBACK,
            bind_succeeded)

        agent_request.add_life_cycle_callback(
            dispatch_constants.CALL_FAILURE_LIFE_CYCLE_CALLBACK, bind_failed)

        call_requests.append(agent_request)

        agent_request.depends_on(bind_request.id)

    return call_requests
Пример #46
0
        msg = msg % {'r': repo_id}
        _logger.exception(msg)
        error_tuples.append(e)

    # remove the repo from any groups it was a member of
    group_manager = manager_factory.repo_group_manager()
    group_manager.remove_repo_from_groups(repo_id)

    if len(error_tuples) > 0:
        pe = pulp_exceptions.PulpExecutionException()
        pe.child_exceptions = error_tuples
        raise pe

    # append unbind itineraries foreach bound consumer
    options = {}
    consumer_bind_manager = manager_factory.consumer_bind_manager()

    additional_tasks = []
    errors = []
    for bind in consumer_bind_manager.find_by_repo(repo_id):
        try:
            report = consumer_controller.unbind(bind['consumer_id'],
                                                bind['repo_id'],
                                                bind['distributor_id'],
                                                options)
            if report:
                additional_tasks.extend(report.spawned_tasks)
        except Exception, e:
            errors.append(e)

    error = None
Пример #47
0
 def populate_bindings(self):
     manager = factory.consumer_bind_manager()
     manager.bind(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID,
                  self.NOTIFY_AGENT, self.BINDING_CONFIG)
Пример #48
0
    def test_unbind_failed_on_consumer(self):

        # Setup
        self.populate()
        manager = factory.consumer_bind_manager()
        bind = manager.bind(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID,
                            self.NOTIFY_AGENT, self.BINDING_CONFIG)

        # Test
        options = {}
        itinerary = unbind_itinerary(
            self.CONSUMER_ID,
            self.REPO_ID,
            self.DISTRIBUTOR_ID,
            options)
        call_reports = self.coordinator.execute_multiple_calls(itinerary)

        # Verify
        self.assertEqual(len(call_reports), 3)
        for call in call_reports:
            self.assertNotEqual(call.state, dispatch_constants.CALL_REJECTED_RESPONSE)

        # run task #1 (actual unbind)
        self.run_next()

        # verify bind marked deleted
        collection = Bind.get_collection()
        bind = collection.find_one(self.QUERY)
        self.assertTrue(bind['deleted'])

        # run task #2 (notify consumer)
        self.run_next()

        # verify agent notified
        self.assertTrue(mock_agent.Consumer.unbind.called)

        # verify consumer request (pending)
        request_id = call_reports[1].call_request_id
        collection = Bind.get_collection()
        bind = collection.find_one(self.QUERY)
        self.assertTrue(bind is not None)
        actions = bind['consumer_actions']
        self.assertEqual(len(actions), 1)
        self.assertEqual(actions[0]['id'], request_id)
        self.assertEqual(actions[0]['action'], Bind.Action.UNBIND)
        self.assertEqual(actions[0]['status'], Bind.Status.PENDING)
        self.assertTrue(isinstance(actions[0]['timestamp'], float))

        # simulated asynchronous task result
        report = DispatchReport()
        report.succeeded = False
        self.coordinator.complete_call_success(request_id, report.dict())

        # verify not found (marked deleted)
        binds = manager.find_by_consumer(self.CONSUMER_ID)
        self.assertEquals(len(binds), 0)

        # run task #3 (bind actually deleted)
        self.run_next()

        # verify bind not deleted
        collection = Bind.get_collection()
        bind = collection.find_one(self.QUERY)
        self.assertTrue(bind is not None)
        actions = bind['consumer_actions']
        self.assertEqual(len(actions), 1)
        self.assertEqual(actions[0]['id'], request_id)
        self.assertEqual(actions[0]['action'], Bind.Action.UNBIND)
        self.assertEqual(actions[0]['status'], Bind.Status.FAILED)
        self.assertTrue(isinstance(actions[0]['timestamp'], float))
Пример #49
0
def forced_unbind_itinerary(consumer_id, repo_id, distributor_id, options):
    """
    Get the unbind itinerary.
    A forced unbind immediately deletes the binding instead
    of marking it deleted and going through that lifecycle.
    It is intended to be used to clean up orphaned bindings
    caused by failed/unconfirmed unbind actions on the consumer.
    The itinerary is:
      1. Delete the binding on the server.
      2. Request that the consumer (agent) perform the unbind.
    @param consumer_id: A consumer ID.
    @type consumer_id: str
    @param repo_id: A repository ID.
    @type repo_id: str
    @param distributor_id: A distributor ID.
    @type distributor_id: str
    @param options: Unbind options passed to the agent handler.
    @type options: dict
    @return: A list of call_requests
    @rtype list
    """

    call_requests = []
    bind_manager = managers.consumer_bind_manager()
    agent_manager = managers.consumer_agent_manager()

    # unbind

    tags = [
        resource_tag(dispatch_constants.RESOURCE_CONSUMER_TYPE, consumer_id),
        resource_tag(dispatch_constants.RESOURCE_REPOSITORY_TYPE, repo_id),
        resource_tag(dispatch_constants.RESOURCE_REPOSITORY_DISTRIBUTOR_TYPE,
                     distributor_id),
        action_tag(ACTION_UNBIND)
    ]

    args = [
        consumer_id,
        repo_id,
        distributor_id,
        True,
    ]

    delete_request = CallRequest(bind_manager.delete, args=args, tags=tags)

    delete_request.reads_resource(dispatch_constants.RESOURCE_CONSUMER_TYPE,
                                  consumer_id)

    call_requests.append(delete_request)

    # notify agent

    tags = [
        resource_tag(dispatch_constants.RESOURCE_CONSUMER_TYPE, consumer_id),
        resource_tag(dispatch_constants.RESOURCE_REPOSITORY_TYPE, repo_id),
        resource_tag(dispatch_constants.RESOURCE_REPOSITORY_DISTRIBUTOR_TYPE,
                     distributor_id),
        action_tag(ACTION_AGENT_UNBIND)
    ]

    args = [
        consumer_id,
        repo_id,
        distributor_id,
        options,
    ]

    agent_request = CallRequest(agent_manager.unbind,
                                args,
                                weight=0,
                                asynchronous=True,
                                archive=True,
                                tags=tags)

    call_requests.append(agent_request)

    agent_request.depends_on(delete_request.id)

    return call_requests
Пример #50
0
 def __init__(self):
     SearchController.__init__(self, managers.consumer_bind_manager().find_by_criteria)
Пример #51
0
def unbind_itinerary(consumer_id, repo_id, distributor_id, options):
    """
    Get the unbind itinerary.
    The tasks in the itinerary are as follows:
      1. Mark the binding as (deleted) on the server.
      2. Request that the consumer (agent) perform the unbind.
      3. Delete the binding on the server.
    @param consumer_id: A consumer ID.
    @type consumer_id: str
    @param repo_id: A repository ID.
    @type repo_id: str
    @param distributor_id: A distributor ID.
    @type distributor_id: str
    @param options: Unbind options passed to the agent handler.
    @type options: dict
    @return: A list of call_requests.
    @rtype list
    """

    call_requests = []
    bind_manager = managers.consumer_bind_manager()
    agent_manager = managers.consumer_agent_manager()

    # unbind

    tags = [
        resource_tag(dispatch_constants.RESOURCE_CONSUMER_TYPE, consumer_id),
        resource_tag(dispatch_constants.RESOURCE_REPOSITORY_TYPE, repo_id),
        resource_tag(dispatch_constants.RESOURCE_REPOSITORY_DISTRIBUTOR_TYPE,
                     distributor_id),
        action_tag(ACTION_UNBIND)
    ]

    args = [
        consumer_id,
        repo_id,
        distributor_id,
    ]

    unbind_request = CallRequest(bind_manager.unbind, args=args, tags=tags)
    unbind_request.reads_resource(dispatch_constants.RESOURCE_CONSUMER_TYPE,
                                  consumer_id)
    call_requests.append(unbind_request)

    # notify agent

    tags = [
        resource_tag(dispatch_constants.RESOURCE_CONSUMER_TYPE, consumer_id),
        resource_tag(dispatch_constants.RESOURCE_REPOSITORY_TYPE, repo_id),
        resource_tag(dispatch_constants.RESOURCE_REPOSITORY_DISTRIBUTOR_TYPE,
                     distributor_id),
        action_tag(ACTION_AGENT_UNBIND)
    ]

    args = [
        consumer_id,
        repo_id,
        distributor_id,
        options,
    ]

    agent_request = CallRequest(agent_manager.unbind,
                                args,
                                weight=0,
                                asynchronous=True,
                                archive=True,
                                tags=tags)

    agent_request.add_life_cycle_callback(
        dispatch_constants.CALL_SUCCESS_LIFE_CYCLE_CALLBACK, unbind_succeeded)

    agent_request.add_life_cycle_callback(
        dispatch_constants.CALL_FAILURE_LIFE_CYCLE_CALLBACK, unbind_failed)

    call_requests.append(agent_request)

    agent_request.depends_on(unbind_request.id)

    # delete the binding

    tags = [
        resource_tag(dispatch_constants.RESOURCE_CONSUMER_TYPE, consumer_id),
        resource_tag(dispatch_constants.RESOURCE_REPOSITORY_TYPE, repo_id),
        resource_tag(dispatch_constants.RESOURCE_REPOSITORY_DISTRIBUTOR_TYPE,
                     distributor_id),
        action_tag(ACTION_DELETE_BINDING)
    ]

    args = [consumer_id, repo_id, distributor_id]

    delete_request = CallRequest(bind_manager.delete, args=args, tags=tags)
    unbind_request.reads_resource(dispatch_constants.RESOURCE_CONSUMER_TYPE,
                                  consumer_id)
    call_requests.append(delete_request)

    delete_request.depends_on(agent_request.id)

    return call_requests
Пример #52
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
Пример #53
0
    def test_bind_failed_on_consumer(self):

        # Setup
        self.populate()

        # Test
        options = {}
        itinerary = bind_itinerary(
            self.CONSUMER_ID,
            self.REPO_ID,
            self.DISTRIBUTOR_ID,
            self.NOTIFY_AGENT,
            self.BINDING_CONFIG,
            options)
        call_reports = self.coordinator.execute_multiple_calls(itinerary)

        # Verify
        self.assertEqual(len(call_reports), 2)
        for call in call_reports:
            self.assertNotEqual(call.state, dispatch_constants.CALL_REJECTED_RESPONSE)

        # run task #1 (actual bind)
        self.run_next()

        # verify bind created
        manager = factory.consumer_bind_manager()
        binds = manager.find_by_consumer(self.CONSUMER_ID)
        self.assertEquals(len(binds), 1)
        bind = binds[0]
        self.assertEqual(bind['consumer_id'], self.CONSUMER_ID)
        self.assertEqual(bind['repo_id'], self.REPO_ID)
        self.assertEqual(bind['distributor_id'], self.DISTRIBUTOR_ID)
        self.assertEqual(bind['notify_agent'], self.NOTIFY_AGENT)
        self.assertEqual(bind['binding_config'], self.BINDING_CONFIG)

        # run task #2 (notify consumer)
        self.run_next()

        # verify pending consumer request (pending)
        request_id = call_reports[1].call_request_id
        bind = manager.get_bind(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID)
        actions = bind['consumer_actions']
        self.assertEqual(len(actions), 1)
        self.assertEqual(actions[0]['id'], request_id)
        self.assertEqual(actions[0]['action'], Bind.Action.BIND)
        self.assertEqual(actions[0]['status'], Bind.Status.PENDING)
        self.assertTrue(isinstance(actions[0]['timestamp'], float))

        # verify agent notified
        self.assertTrue(mock_agent.Consumer.bind.called)

        # simulated asynchronous task result
        report = DispatchReport()
        report.succeeded = False
        self.coordinator.complete_call_success(request_id, report.dict())

        # verify pending consumer request (failed)
        manager = factory.consumer_bind_manager()
        bind = manager.get_bind(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID)
        actions = bind['consumer_actions']
        self.assertEqual(len(actions), 1)
        self.assertEqual(actions[0]['id'], request_id)
        self.assertEqual(actions[0]['action'], Bind.Action.BIND)
        self.assertEqual(actions[0]['status'], Bind.Status.FAILED)
        self.assertTrue(isinstance(actions[0]['timestamp'], float))
Пример #54
0
import sys

from optparse import OptionParser
from pulp.server.auth.cert_generator import SerialNumber
from pulp.server.db import connection
from pulp.server.db.model.consumer import UnitProfile
from pulp.server.exceptions import DuplicateResource, MissingResource
from pulp.server.managers import factory
from pulp_rpm.common.ids import TYPE_ID_RPM, TYPE_ID_DISTRIBUTOR_YUM

SerialNumber.PATH = '/tmp/sn.dat'
connection.initialize()
factory.initialize()
CONSUMER_MGR = factory.consumer_manager()
PROFILE_MGR = factory.consumer_profile_manager()
CONSUMER_BIND_MGR = factory.consumer_bind_manager()


def get_consumer_id(prefix, index, count):
    value = str(index)
    desired_length = len(str(count))
    num_length = len(value)
    needed_padding = desired_length - num_length
    for i in range(0, needed_padding):
        value = "0" + value
    return "%s_%s" % (prefix, value)


def get_even_profile():
    random_num = random.randint(0, 1000)
    profile = [{