def clean(self): Bind.get_collection().remove() Repo.get_collection().remove() RepoDistributor.get_collection().remove() RepoImporter.get_collection().remove() RepoContentUnit.get_collection().remove() unit_db.clean()
def tearDown(self): PulpItineraryTests.tearDown(self) Consumer.get_collection().remove() Repo.get_collection().remove() RepoDistributor.get_collection().remove() Bind.get_collection().remove() mock_plugins.reset()
def tearDown(self): super(ConsumerTest, self).tearDown() Consumer.get_collection().remove(safe=True) Repo.get_collection().remove(safe=True) RepoDistributor.get_collection().remove(safe=True) Bind.get_collection().remove(safe=True) mock_plugins.reset()
def tearDown(self): super(BindManagerTests, self).tearDown() Consumer.get_collection().remove() Repo.get_collection().remove() RepoDistributor.get_collection().remove() Bind.get_collection().remove() mock_plugins.reset()
def tearDown(self): base.PulpWebserviceTests.tearDown(self) Consumer.get_collection().remove() Repo.get_collection().remove() RepoDistributor.get_collection().remove() Bind.get_collection().remove() mock_plugins.reset()
def setUp(self): super(BindManagerTests, self).setUp() Consumer.get_collection().remove() model.Distributor.objects.delete() Bind.get_collection().remove() ConsumerHistoryEvent.get_collection().remove() plugin_api._create_manager() mock_plugins.install()
def setUp(self): base.PulpWebserviceTests.setUp(self) Consumer.get_collection().remove() Repo.get_collection().remove() RepoDistributor.get_collection().remove() Bind.get_collection().remove() plugin_api._create_manager() mock_plugins.install()
def tearDown(self): super(self.__class__, self).tearDown() Consumer.get_collection().remove() ConsumerGroup.get_collection().remove() Repo.get_collection().remove() RepoDistributor.get_collection().remove() Bind.get_collection().remove() mock_plugins.reset()
def setUp(self): super(BindManagerTests, self).setUp() Consumer.get_collection().remove() Repo.get_collection().remove() RepoDistributor.get_collection().remove() Bind.get_collection().remove() plugin_api._create_manager() mock_plugins.install()
def tearDown(self): super(BindManagerTests, self).tearDown() Consumer.get_collection().remove() model.Repository.objects.delete() model.Distributor.objects.delete() Bind.get_collection().remove() ConsumerHistoryEvent.get_collection().remove() mock_plugins.reset()
def setUp(self): PulpItineraryTests.setUp(self) Consumer.get_collection().remove() Repo.get_collection().remove() RepoDistributor.get_collection().remove() Bind.get_collection().remove() plugin_api._create_manager() mock_plugins.install() mock_agent.install()
def setUp(self): super(self.__class__, self).setUp() Consumer.get_collection().remove() ConsumerGroup.get_collection().remove() Repo.get_collection().remove() RepoDistributor.get_collection().remove() Bind.get_collection().remove() plugin_api._create_manager() mock_plugins.install()
def tearDown(self): super(BaseProfilerConduitTests, self).tearDown() Consumer.get_collection().remove() Repo.get_collection().remove() RepoDistributor.get_collection().remove() Bind.get_collection().remove() RepoContentUnit.get_collection().remove() UnitProfile.get_collection().remove() typedb.clean() factory.reset()
def setUp(self): super(BaseProfilerConduitTests, self).setUp() Consumer.get_collection().remove() RepoDistributor.get_collection().remove() Bind.get_collection().remove() RepoContentUnit.get_collection().remove() UnitProfile.get_collection().remove() plugin_api._create_manager() typedb.update_database([self.TYPE_1_DEF, self.TYPE_2_DEF]) mock_plugins.install()
def tearDown(self): super(BaseProfilerConduitTests, self).tearDown() Consumer.get_collection().remove() model.Repository.objects.delete() model.Distributor.objects.delete() Bind.get_collection().remove() RepoContentUnit.get_collection().remove() UnitProfile.get_collection().remove() typedb.clean() factory.reset() mock_plugins.reset()
def clean(self, units_only=False, plugins=False): RepoContentUnit.get_collection().remove() unit_db.clean() if units_only: return Bind.get_collection().remove() Repo.get_collection().remove() RepoDistributor.get_collection().remove() RepoImporter.get_collection().remove() if plugins: plugin_api._MANAGER.distributors.plugins = {}
def tearDown(self): ServerTests.tearDown(self) shutil.rmtree(self.parentfs) shutil.rmtree(self.childfs) Consumer.get_collection().remove() Bind.get_collection().remove() model.Repository.objects.delete() model.Distributor.objects.delete() model.Importer.objects.delete() RepoContentUnit.get_collection().remove() unit_db.clean()
def tearDown(self): WebTest.tearDown(self) shutil.rmtree(self.parentfs) shutil.rmtree(self.childfs) Consumer.get_collection().remove() Bind.get_collection().remove() Repo.get_collection().remove() RepoDistributor.get_collection().remove() RepoImporter.get_collection().remove() RepoContentUnit.get_collection().remove() unit_db.clean()
def clean(self, just_units=False, purge_plugins=False): RepoContentUnit.get_collection().remove() unit_db.clean() if just_units: return Bind.get_collection().remove() Repo.get_collection().remove() RepoDistributor.get_collection().remove() RepoImporter.get_collection().remove() if purge_plugins: plugin_api._MANAGER.importers.plugins = {} plugin_api._MANAGER.distributors.plugins = {}
def test_migration(self): # setup collection = Bind.get_collection() for n in range(0, MAX_BINDINGS): if n % 2 == 0: conf = {ID: n} else: conf = None binding = { ID: n, CONSUMER_ID: n, REPO_ID: n, DISTRIBUTOR_ID: n, BINDING_CONFIG: conf, NOTIFY_AGENT: True, } collection.save(binding, safe=True) # migrate module = MigrationModule(MIGRATION)._module module.migrate() # verify bindings = list(collection.find({})) self.assertEqual(len(bindings), MAX_BINDINGS) for binding in bindings: conf = binding[BINDING_CONFIG] bind_id = binding[ID] if bind_id % 2 == 0: # untouched self.assertEqual(conf, {ID: bind_id}) else: # fixed self.assertEqual(conf, {})
def get_bind(consumer_id, repo_id, distributor_id): """ Get a specific bind. This method ignores the deleted flag. :param consumer_id: uniquely identifies the consumer. :type consumer_id: str :param repo_id: uniquely identifies the repository. :type repo_id: str :param distributor_id: uniquely identifies a distributor. :type distributor_id: str :return: A specific bind. :rtype: SON :raise MissingResource: if the binding doesn't exist """ collection = Bind.get_collection() bind_id = BindManager.bind_id(consumer_id, repo_id, distributor_id) bind = collection.find_one(bind_id) if bind is None: # If the binding doesn't exist, report which values are not present missing_values = BindManager._validate_consumer_repo(consumer_id, repo_id, distributor_id) if missing_values: raise MissingResource(**missing_values) else: # In this case, every resource is present, but the consumer isn't bound to that # repo/distributor raise MissingResource(bind_id=bind_id) return bind
def action_pending(self, consumer_id, repo_id, distributor_id, action, action_id): """ Add pending action for tracking. @param consumer_id: uniquely identifies the consumer. @type consumer_id: str @param repo_id: uniquely identifies the repository. @type repo_id: str @param distributor_id: uniquely identifies a distributor. @type distributor_id: str @param action: The action (bind|unbind). @type action: str @param action_id: The ID of the action to begin tracking. @type action_id: str @see Bind.Action """ collection = Bind.get_collection() assert action in (Bind.Action.BIND, Bind.Action.UNBIND) bind_id = self.bind_id(consumer_id, repo_id, distributor_id) entry = dict( id=action_id, timestamp=time(), action=action, status=Bind.Status.PENDING) update = {'$push':{'consumer_actions':entry}} collection.update(bind_id, update, safe=True)
def bind(self, consumer_id, repo_id, distributor_id): """ Bind consumer to a specific distributor associated with a repository. This call is idempotent. @param consumer_id: uniquely identifies the consumer. @type consumer_id: str @param repo_id: uniquely identifies the repository. @type repo_id: str @param distributor_id: uniquely identifies a distributor. @type distributor_id: str @return: The Bind object @rtype: SON @raise MissingResource: when given consumer does not exist. """ # ensure the consumer is valid manager = factory.consumer_manager() manager.get_consumer(consumer_id) # ensure the repository & distributor are valid manager = factory.repo_distributor_manager() manager.get_distributor(repo_id, distributor_id) # perform the bind collection = Bind.get_collection() try: bind = Bind(consumer_id, repo_id, distributor_id) collection.save(bind, safe=True) except DuplicateKeyError: self.__reset_bind(consumer_id, repo_id, distributor_id) # fetch the inserted/updated bind bind = self.get_bind(consumer_id, repo_id, distributor_id) # update history details = {'repo_id':repo_id, 'distributor_id':distributor_id} manager = factory.consumer_history_manager() manager.record_event(consumer_id, 'repo_bound', details) return bind
def unbind(self, consumer_id, repo_id, distributor_id): """ Unbind a consumer from a specific distributor associated with a repository. This call is idempotent. @param consumer_id: uniquely identifies the consumer. @type consumer_id: str @param repo_id: uniquely identifies the repository. @type repo_id: str @param distributor_id: uniquely identifies a distributor. @type distributor_id: str @return: The Bind object @rtype: SON """ collection = Bind.get_collection() query = self.bind_id(consumer_id, repo_id, distributor_id) query['deleted'] = False bind = collection.find_one(query) if bind is None: # idempotent return self.mark_deleted(consumer_id, repo_id, distributor_id) details = { 'repo_id':repo_id, 'distributor_id':distributor_id } manager = factory.consumer_history_manager() manager.record_event(consumer_id, 'repo_unbound', details) return bind
def delete(self, consumer_id, repo_id, distributor_id, force=False): """ Delete the bind. @param consumer_id: uniquely identifies the consumer. @type consumer_id: str @param repo_id: uniquely identifies the repository. @type repo_id: str @param distributor_id: uniquely identifies a distributor. @type distributor_id: str @param force: Delete without validation. @type force: bool """ collection = Bind.get_collection() if not force: query = { 'consumer_actions.status':{ '$in':[Bind.Status.PENDING, Bind.Status.FAILED]} } pending = collection.find(query) if len(list(pending)): raise Exception, 'outstanding actions, not deleted' query = self.bind_id(consumer_id, repo_id, distributor_id) if not force: query['deleted'] = True collection.remove(query, safe=True)
def action_succeeded(self, consumer_id, repo_id, distributor_id, action_id): """ A tracked consumer action has succeeded. Since consumer actions are queue to the agent and performed in the order, previous actions are considered irrelevant and thus purged. @param consumer_id: uniquely identifies the consumer. @type consumer_id: str @param repo_id: uniquely identifies the repository. @type repo_id: str @param distributor_id: uniquely identifies a distributor. @type distributor_id: str @param action_id: The ID of the action to begin tracking. @type action_id: str """ collection = Bind.get_collection() bind_id = self.bind_id(consumer_id, repo_id, distributor_id) action = self.find_action(action_id) if action is None: _LOG.warn('action %s not found', action_id) return # delete the action update = {'$pull':{'consumer_actions':{'id':action_id}}} collection.update(bind_id, update, safe=True) # purge all previous actions update = {'$pull': {'consumer_actions':{'timestamp':{'$lt':action['timestamp']}}} } collection.update(bind_id, update, safe=True)
def bind(self, consumer_id, repo_id, distributor_id): """ Bind consumer to a specific distributor associated with a repository. This call is idempotent. @param consumer_id: uniquely identifies the consumer. @type consumer_id: str @param repo_id: uniquely identifies the repository. @type repo_id: str @param distributor_id: uniquely identifies a distributor. @type distributor_id: str @return: The Bind object @rtype: SON @raise MissingResource: when given consumer does not exist. """ manager = factory.consumer_manager() manager.get_consumer(consumer_id) manager = factory.repo_distributor_manager() distributor = manager.get_distributor(repo_id, distributor_id) bind = Bind(consumer_id, repo_id, distributor_id) collection = Bind.get_collection() try: collection.save(bind, safe=True) bind = self.get_bind(consumer_id, repo_id, distributor_id) except DuplicateKeyError: # idempotent pass manager = factory.consumer_agent_manager() manager.bind(consumer_id, repo_id) consumer_event_details = {"repo_id": repo_id, "distributor_id": distributor_id} factory.consumer_history_manager().record_event(consumer_id, "repo_bound", consumer_event_details) return bind
def unbind(self, consumer_id, repo_id, distributor_id): """ Unbind consumer to a specifiec distirbutor associated with a repository. This call is idempotent. @param consumer_id: uniquely identifies the consumer. @type consumer_id: str @param repo_id: uniquely identifies the repository. @type repo_id: str @param distributor_id: uniquely identifies a distributor. @type distributor_id: str @return: The Bind object @rtype: SON """ query = dict(consumer_id=consumer_id, repo_id=repo_id, distributor_id=distributor_id) collection = Bind.get_collection() bind = collection.find_one(query) if bind is None: # idempotent return collection.remove(bind, safe=True) manager = factory.consumer_agent_manager() manager.unbind(consumer_id, repo_id) consumer_event_details = {"repo_id": repo_id, "distributor_id": distributor_id} factory.consumer_history_manager().record_event(consumer_id, "repo_unbound", consumer_event_details) return bind
def test_upgrade_idempotency(self): """ Simplest way to check the migration can run twice is simply to run it twice. The primary goal is to make sure an exception isn't raised. """ # Setup coll = Bind.get_collection() for counter in range(0, 3): bind_dict = { 'consumer_id': 'consumer_%s' % counter, 'repo_id': 'repo_%s' % counter, 'distributor_id': 'distributor_%s' % counter, } coll.insert(bind_dict) # Test module = MigrationModule('pulp.server.db.migrations.0003_bind_additions')._module module.migrate() module.migrate() # Verify bindings = coll.find() for b in bindings: self.assertTrue('notify_agent' in b) self.assertEqual(b['notify_agent'], True) self.assertTrue('binding_config' in b) self.assertEqual(b['binding_config'], None)
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)
def setUp(self): ServerTests.setUp(self) self.parentfs = self.tmpdir('parent-') self.childfs = self.tmpdir('child-') self.alias = (self.parentfs, self.parentfs) Consumer.get_collection().remove() Bind.get_collection().remove() Repo.get_collection().remove() RepoDistributor.get_collection().remove() RepoImporter.get_collection().remove() RepoContentUnit.get_collection().remove() unit_db.clean() self.define_plugins() plugin_api._create_manager() imp_conf = dict(strategy=constants.MIRROR_STRATEGY) plugin_api._MANAGER.importers.add_plugin(constants.HTTP_IMPORTER, NodesHttpImporter, imp_conf) plugin_api._MANAGER.distributors.add_plugin(constants.HTTP_DISTRIBUTOR, NodesHttpDistributor, {}) plugin_api._MANAGER.distributors.add_plugin(FAKE_DISTRIBUTOR, FakeDistributor, FAKE_DISTRIBUTOR_CONFIG) plugin_api._MANAGER.profilers.add_plugin(constants.PROFILER_ID, NodeProfiler, {})
def _update_binding(consumer_id, repo_id, distributor_id, notify_agent, binding_config): """ Workaround to the way bindings rely on a duplicate key error for supporting rebind. This call makes sure the existing binding is updated with the new values for notifying the agent and the binding's configuration. The parameters are the values passed to the bind() call. """ collection = Bind.get_collection() query = BindManager.bind_id(consumer_id, repo_id, distributor_id) binding = collection.find_one(query) binding['notify_agent'] = notify_agent binding['binding_config'] = binding_config collection.save(binding)
def find_action(self, action_id): """ Find a consumer action by ID. @param action_id: An action ID. @type action_id: str @return: The action if found, else None """ collection = Bind.get_collection() query = {'consumer_actions.id': action_id} binding = collection.find_one(query) if binding is None: return for action in binding['consumer_actions']: if action['id'] == action_id: return action
def bind(consumer_id, repo_id, distributor_id, notify_agent, binding_config): """ Bind consumer to a specific distributor associated with a repository. This call is idempotent. :param consumer_id: uniquely identifies the consumer. :type consumer_id: str :param repo_id: uniquely identifies the repository. :type repo_id: str :param distributor_id: uniquely identifies a distributor. :type distributor_id: str :return: The Bind object :rtype: SON :raise MissingResource: when given consumer does not exist. :raise InvalidValid: when the repository or distributor id is invalid, or if the notify_agent value is invalid """ # Validation missing_values = BindManager._validate_consumer_repo(consumer_id, repo_id, distributor_id) if missing_values: if 'consumer_id' in missing_values: # This is passed in via the URL so a 404 should be raised raise MissingResource(consumer_id=missing_values['consumer_id']) else: # Everything else is a parameter so raise a 400 raise InvalidValue(missing_values.keys()) # ensure notify_agent is a boolean if not isinstance(notify_agent, bool): raise InvalidValue(['notify_agent']) # perform the bind collection = Bind.get_collection() try: bind = Bind(consumer_id, repo_id, distributor_id, notify_agent, binding_config) collection.save(bind) except DuplicateKeyError: BindManager._update_binding(consumer_id, repo_id, distributor_id, notify_agent, binding_config) BindManager._reset_bind(consumer_id, repo_id, distributor_id) # fetch the inserted/updated bind bind = BindManager.get_bind(consumer_id, repo_id, distributor_id) # update history details = {'repo_id': repo_id, 'distributor_id': distributor_id} manager = factory.consumer_history_manager() manager.record_event(consumer_id, 'repo_bound', details) return bind
def test_hard_delete(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 manager.delete(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID) manager.action_pending(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID, Bind.Action.BIND, '0') manager.delete(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID, True) collection = Bind.get_collection() bind_id = manager.bind_id(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID) bind = collection.find_one(bind_id) self.assertTrue(bind is None)
def test_bind(self): # Setup self.populate() # Test manager = factory.consumer_bind_manager() manager.bind(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID, self.NOTIFY_AGENT, self.BINDING_CONFIG) # Verify collection = Bind.get_collection() bind = collection.find_one(self.QUERY) self.assertTrue(bind is not None) 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)
def mark_deleted(self, consumer_id, repo_id, distributor_id): """ Mark the bind as deleted. @param consumer_id: uniquely identifies the consumer. @type consumer_id: str @param repo_id: uniquely identifies the repository. @type repo_id: str @param distributor_id: uniquely identifies a distributor. @type distributor_id: str """ # validate self.get_bind(consumer_id, repo_id, distributor_id) # update document collection = Bind.get_collection() query = self.bind_id(consumer_id, repo_id, distributor_id) collection.update(query, {'$set': {'deleted': True}}, safe=True)
def find_by_distributor(self, repo_id, distributor_id): """ Find all non-deleted binds by Distributor ID. @param repo_id: A Repo ID. @type repo_id: str @param distributor_id: A Distributor ID. @type distributor_id: str @return: A list of Bind. @rtype: list """ collection = Bind.get_collection() query = dict(repo_id=repo_id, distributor_id=distributor_id, deleted=False) cursor = collection.find(query) return list(cursor)
def __reset_bind(self, consumer_id, repo_id, distributor_id): """ Reset the bind. This means resetting the deleted flag and consumer requests. Only deleted bindings will be reset. @param consumer_id: uniquely identifies the consumer. @type consumer_id: str @param repo_id: uniquely identifies the repository. @type repo_id: str @param distributor_id: uniquely identifies a distributor. @type distributor_id: str """ collection = Bind.get_collection() query = self.bind_id(consumer_id, repo_id, distributor_id) query['deleted'] = True update = {'$set': {'deleted': False, 'consumer_actions': []}} collection.update(query, update, safe=True)
def test_bind_missing_consumer(self, mock_repo_qs): self.populate() collection = Consumer.get_collection() collection.remove({}) manager = factory.consumer_bind_manager() try: manager.bind(self.CONSUMER_ID, self.REPO_ID, self.DISTRIBUTOR_ID, self.NOTIFY_AGENT, self.BINDING_CONFIG) self.fail(msg='MissingResource <Consumer>, expected') except MissingResource: # expected pass # Verify collection = Bind.get_collection() binds = collection.find({}) binds = [b for b in binds] self.assertEqual(len(binds), 0)
def action_failed(self, consumer_id, repo_id, distributor_id, action_id): """ A tracked consumer action has failed. @param consumer_id: uniquely identifies the consumer. @type consumer_id: str @param repo_id: uniquely identifies the repository. @type repo_id: str @param distributor_id: uniquely identifies a distributor. @type distributor_id: str @param action_id: The ID of the request to begin tracking. @type action_id: str """ collection = Bind.get_collection() query = self.bind_id(consumer_id, repo_id, distributor_id) query['consumer_actions.id'] = action_id update = {'$set': {'consumer_actions.$.status': Bind.Status.FAILED}} collection.update(query, update, safe=True)
def find_by_consumer(self, id, repo_id=None): """ Find all non-deleted bindings by Consumer ID. @param id: A consumer ID. @type id: str @param repo_id: An (optional) repository ID. @type repo_id: str @return: A list of Bind. @rtype: list """ collection = Bind.get_collection() if repo_id: query = dict(consumer_id=id, repo_id=repo_id, deleted=False) else: query = dict(consumer_id=id, deleted=False) cursor = collection.find(query) return list(cursor)
def bind(self, consumer_id, repo_id, distributor_id, notify_agent, binding_config): """ Bind consumer to a specific distributor associated with a repository. This call is idempotent. @param consumer_id: uniquely identifies the consumer. @type consumer_id: str @param repo_id: uniquely identifies the repository. @type repo_id: str @param distributor_id: uniquely identifies a distributor. @type distributor_id: str @return: The Bind object @rtype: SON @raise MissingResource: when given consumer does not exist. """ # Validation # ensure notify_agent is a boolean if not isinstance(notify_agent, bool): raise InvalidValue(['notify_agent']) # ensure the consumer is valid manager = factory.consumer_manager() manager.get_consumer(consumer_id) # ensure the repository & distributor are valid manager = factory.repo_distributor_manager() manager.get_distributor(repo_id, distributor_id) # perform the bind collection = Bind.get_collection() try: bind = Bind(consumer_id, repo_id, distributor_id, notify_agent, binding_config) collection.save(bind, safe=True) except DuplicateKeyError: self._update_binding(consumer_id, repo_id, distributor_id, notify_agent, binding_config) self.__reset_bind(consumer_id, repo_id, distributor_id) # fetch the inserted/updated bind bind = self.get_bind(consumer_id, repo_id, distributor_id) # update history details = {'repo_id': repo_id, 'distributor_id': distributor_id} manager = factory.consumer_history_manager() manager.record_event(consumer_id, 'repo_bound', details) return bind
def migrate(*args, **kwargs): """ Add new fields needed for consumer action(s) tracking. """ additions = ( ('deleted', False), ('consumer_actions', []), ) collection = Bind.get_collection() for bind in collection.find({}): dirty = False for key, value in additions: if key not in bind: bind[key] = value dirty = True if dirty: collection.save(bind)
def test_unbind(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) # 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 migrate(*args, **kwargs): """ Adds attributes needed for binding configurations. To maintain backward compatibility, the notify_agent field is set to True. """ additions = ( ('notify_agent', True), ('binding_config', None), ) collection = Bind.get_collection() for bind in collection.find({}): dirty = False for key, value in additions: if key not in bind: bind[key] = value dirty = True if dirty: collection.save(bind)
def _add_repo_ids_to_consumer_map(consumer_ids, consumer_map): """ Query for all bindings for the given list of consumer_ids, and for each one add the bound repo_ids to the consumer_map's entry for the consumer. :param consumer_ids: The list of consumer_ids. We could pull this from the consumer_map, but since we already have this list it's probably more performant to use it as is. :type consumer_ids: list :param consumer_map: A dictionary mapping consumer_ids to a dictionary with key 'profiles', which indexes a list that this method will append the found profiles to. :type consumer_map: dict """ bindings = Bind.get_collection().find( {'consumer_id': {'$in': consumer_ids}}, fields=['consumer_id', 'repo_id']) for b in bindings: consumer_map[b['consumer_id']]['repo_ids'].append(b['repo_id'])
def get_bind(self, consumer_id, repo_id, distributor_id): """ Get a specific bind. This method ignores the deleted flag. @param consumer_id: uniquely identifies the consumer. @type consumer_id: str @param repo_id: uniquely identifies the repository. @type repo_id: str @param distributor_id: uniquely identifies a distributor. @type distributor_id: str @return: A specific bind. @rtype: SON @raise MissingResource: When not found """ collection = Bind.get_collection() bind_id = self.bind_id(consumer_id, repo_id, distributor_id) bind = collection.find_one(bind_id) if bind is None: raise MissingResource(bind_id=bind_id) return bind
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)
def unbind(consumer_id, repo_id, distributor_id): """ Unbind a consumer from a specific distributor associated with a repository. This call is idempotent. :param consumer_id: uniquely identifies the consumer. :type consumer_id: str :param repo_id: uniquely identifies the repository. :type repo_id: str :param distributor_id: uniquely identifies a distributor. :type distributor_id: str :return: The Bind object :rtype: SON :raise MissingResource: if the binding does not exist """ # Validate that the binding exists at all before continuing. # This will raise an exception if it it does not. BindManager.get_bind(consumer_id, repo_id, distributor_id) collection = Bind.get_collection() query = BindManager.bind_id(consumer_id, repo_id, distributor_id) query['deleted'] = False bind = collection.find_one(query) if bind is None: # idempotent return BindManager.mark_deleted(consumer_id, repo_id, distributor_id) details = { 'repo_id': repo_id, 'distributor_id': distributor_id } manager = factory.consumer_history_manager() manager.record_event(consumer_id, 'repo_unbound', details) return bind
def test_upgrade(self): # Setup coll = Bind.get_collection() for counter in range(0, 3): bind_dict = { 'consumer_id' : 'consumer_%s' % counter, 'repo_id' : 'repo_%s' % counter, 'distributor_id' : 'distributor_%s' % counter, } coll.insert(bind_dict, safe=True) # Test module = MigrationModule('pulp.server.db.migrations.0003_bind_additions')._module module.migrate() # Verify bindings = coll.find() for b in bindings: self.assertTrue('notify_agent' in b) self.assertEqual(b['notify_agent'], True) self.assertTrue('binding_config' in b) self.assertEqual(b['binding_config'], None)
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))
def clean(self): super(BindAdditionMigrationTests, self).clean() Bind.get_collection().remove()
def tearDown(self): super(TestMigration_0006, self).tearDown() collection = Bind.get_collection() collection.remove()
def setUp(self): self.clean() super(TestMigration_0006, self).setUp() collection = Bind.get_collection() collection.remove()