예제 #1
0
    def test_consumer_create_exists_different_consumer_type_supplied(self):
        """Tests that we update a consumer's type ID if the one supplied by a
        racing request is different than the one in the existing (recently
        created) record.
        """
        proj = project_obj.Project(self.ctx, id=1, external_id=self.project_id)
        self.mock_project_get.return_value = proj
        user = user_obj.User(self.ctx, id=1, external_id=self.user_id)
        self.mock_user_get.return_value = user
        # Request A recently created consumer has type ID = 1
        consumer = consumer_obj.Consumer(
            self.ctx, id=1, project=proj, user=user, generation=1,
            consumer_type_id=1, uuid=uuidsentinel.consumer)
        self.mock_consumer_get.return_value = consumer
        # Request B will encounter ConsumerExists as Request A just created it
        self.mock_consumer_create.side_effect = (
            exception.ConsumerExists(uuid=uuidsentinel.consumer))

        consumer_gen = 1
        consumer, created_new_consumer, request_attr = util.ensure_consumer(
            self.ctx, self.consumer_id, self.project_id, self.user_id,
            consumer_gen, 'TYPE', self.cons_type_req_version)
        util.update_consumers([consumer], {consumer.uuid: request_attr})
        # Expect 1 call to update() to update to the supplied consumer type ID
        self.mock_consumer_update.assert_called_once_with()
        # Consumer should have the new consumer type from the cache
        self.assertEqual(
            self.ctx.ct_cache.id_from_string.return_value,
            consumer.consumer_type_id)
예제 #2
0
def get_all_by_resource_provider(context, rp):
    _create_incomplete_consumers_for_provider(context, rp.id)
    db_allocs = _get_allocations_by_provider_id(context, rp.id)
    # Build up a list of Allocation objects, setting the Allocation object
    # fields to the same-named database record field we got from
    # _get_allocations_by_provider_id(). We already have the
    # ResourceProvider object so we just pass that object to the Allocation
    # object constructor as-is
    objs = []
    for rec in db_allocs:
        consumer = consumer_obj.Consumer(
            context,
            id=rec['consumer_id'],
            uuid=rec['consumer_uuid'],
            generation=rec['consumer_generation'],
            project=project_obj.Project(
                context,
                id=rec['project_id'],
                external_id=rec['project_external_id']),
            user=user_obj.User(context,
                               id=rec['user_id'],
                               external_id=rec['user_external_id']))
        objs.append(
            Allocation(id=rec['id'],
                       resource_provider=rp,
                       resource_class=rc_cache.RC_CACHE.string_from_id(
                           rec['resource_class_id']),
                       consumer=consumer,
                       used=rec['used'],
                       created_at=rec['created_at'],
                       updated_at=rec['updated_at']))
    return objs
예제 #3
0
    def test_update(self):
        """Tests the scenario where a user supplies a different project/user ID
        for an allocation's consumer and we call Consumer.update() to save that
        information to the consumers table.
        """
        # First, create the consumer with the "fake-user" and "fake-project"
        # user/project in the base test class's setUp
        c = consumer_obj.Consumer(self.ctx,
                                  uuid=uuids.consumer,
                                  user=self.user_obj,
                                  project=self.project_obj)
        c.create()
        c = consumer_obj.Consumer.get_by_uuid(self.ctx, uuids.consumer)
        self.assertEqual(self.project_obj.id, c.project.id)
        self.assertEqual(self.user_obj.id, c.user.id)

        # Now change the consumer's project and user to a different project
        another_user = user_obj.User(self.ctx, external_id='another-user')
        another_user.create()
        another_proj = project_obj.Project(self.ctx,
                                           external_id='another-project')
        another_proj.create()

        c.project = another_proj
        c.user = another_user
        c.update()
        c = consumer_obj.Consumer.get_by_uuid(self.ctx, uuids.consumer)
        self.assertEqual(another_proj.id, c.project.id)
        self.assertEqual(another_user.id, c.user.id)
예제 #4
0
    def test_existing_consumer_different_consumer_type_supplied(self):
        """Tests that we update a consumer's type ID if the one supplied by the
        user is different than the one in the existing record.
        """
        proj = project_obj.Project(self.ctx, id=1, external_id=self.project_id)
        self.mock_project_get.return_value = proj
        user = user_obj.User(self.ctx, id=1, external_id=self.user_id)
        self.mock_user_get.return_value = user
        # Consumer currently has type ID = 1
        consumer = consumer_obj.Consumer(
            self.ctx, id=1, project=proj, user=user, generation=1,
            consumer_type_id=1)
        self.mock_consumer_get.return_value = consumer

        consumer_gen = 1
        consumer, created_new_consumer, request_attr = util.ensure_consumer(
            self.ctx, self.consumer_id, self.project_id, self.user_id,
            consumer_gen, 'TYPE', self.cons_type_req_version)
        util.update_consumers([consumer], {consumer.uuid: request_attr})
        # Expect 1 call to update() to update to the supplied consumer type ID
        self.mock_consumer_update.assert_called_once_with()
        # Consumer should have the new consumer type from the cache
        self.assertEqual(
            self.ctx.ct_cache.id_from_string.return_value,
            consumer.consumer_type_id)
예제 #5
0
 def test_create_and_get(self):
     p = project_obj.Project(self.ctx, external_id='another-project')
     p.create()
     p = project_obj.Project.get_by_external_id(self.ctx, 'another-project')
     # Project ID == 1 is fake-project created in setup
     self.assertEqual(2, p.id)
     self.assertRaises(exception.ProjectExists, p.create)
예제 #6
0
 def fake_get_project(cls, ctx, external_id):
     if not hasattr(fake_get_project, 'called'):
         proj = project_obj.Project(ctx, external_id=external_id)
         proj.create()
         fake_get_project.called = True
         raise exception.ProjectNotFound(external_id)
     else:
         return real_get_project(ctx, external_id)
예제 #7
0
    def _from_db_object(ctx, target, source):
        target.uuid = source['uuid']
        target.generation = source['generation']
        target.created_at = source['created_at']
        target.updated_at = source['updated_at']

        target.project = project_obj.Project(ctx, uuid=source["project_uuid"])
        target.user = user_obj.User(ctx, uuid=source["user_uuid"])
        target._context = ctx
        return target
예제 #8
0
    def start_fixture(self):
        super(AllocationFixture, self).start_fixture()

        # For use creating and querying allocations/usages
        os.environ['ALT_USER_ID'] = uuidutils.generate_uuid()
        project_id = os.environ['PROJECT_ID']
        user_id = os.environ['USER_ID']
        alt_user_id = os.environ['ALT_USER_ID']

        user = user_obj.User(self.context, uuid=user_id)
        user.create()
        alt_user = user_obj.User(self.context, uuid=alt_user_id)
        alt_user.create()
        project = project_obj.Project(self.context, uuid=project_id)
        project.create()

        # Stealing from the super
        rp_name = os.environ['RP_NAME']
        rp_uuid = os.environ['RP_UUID']
        # Create the rp with VCPU and DISK_GB inventory
        rp = tb.create_provider(self.context, rp_name, uuid=rp_uuid)
        tb.add_inventory(rp,
                         'DISK_GB',
                         2048,
                         step_size=10,
                         min_unit=10,
                         max_unit=1000)
        tb.add_inventory(rp, 'VCPU', 10, max_unit=10)

        # Create a first consumer for the DISK_GB allocations

        consumer1 = tb.ensure_consumer(self.context, user, project)
        tb.set_allocation(self.context, rp, consumer1, {'DISK_GB': 1000})
        os.environ['CONSUMER_0'] = consumer1.uuid

        # Create a second consumer for the VCPU allocations
        consumer2 = tb.ensure_consumer(self.context, user, project)
        tb.set_allocation(self.context, rp, consumer2, {'VCPU': 6})
        os.environ['CONSUMER_ID'] = consumer2.uuid

        # Create a consumer object for a different user
        alt_consumer = tb.ensure_consumer(self.context, alt_user, project)
        os.environ['ALT_CONSUMER_ID'] = alt_consumer.uuid

        # Create a couple of allocations for a different user.
        tb.set_allocation(self.context, rp, alt_consumer, {
            'DISK_GB': 20,
            'VCPU': 1
        })

        # The ALT_RP_XXX variables are for a resource provider that has
        # not been created in the Allocation fixture
        os.environ['ALT_RP_UUID'] = uuidutils.generate_uuid()
        os.environ['ALT_RP_NAME'] = uuidutils.generate_uuid()
예제 #9
0
 def setUp(self):
     super(PlacementDbBaseTestCase, self).setUp()
     # we use context in some places and ctx in other. We should only use
     # context, but let's paper over that for now.
     self.ctx = self.context
     self.user_obj = user_obj.User(self.ctx, uuid=uuids.user)
     self.user_obj.create()
     self.project_obj = project_obj.Project(self.ctx, uuid=uuids.project)
     self.project_obj.create()
     # For debugging purposes, populated by _create_provider and used by
     # _validate_allocation_requests to make failure results more readable.
     self.rp_uuid_to_name = {}
예제 #10
0
def _get_or_create_project(ctx, project_id):
    try:
        proj = project_obj.Project.get_by_external_id(ctx, project_id)
    except exception.NotFound:
        # Auto-create the project if we found no record of it...
        try:
            proj = project_obj.Project(ctx, external_id=project_id)
            proj.create()
        except exception.ProjectExists:
            # No worries, another thread created this project already
            proj = project_obj.Project.get_by_external_id(ctx, project_id)
    return proj
예제 #11
0
 def test_create_and_get(self):
     u = user_obj.User(self.ctx, external_id='another-user')
     u.create()
     p = project_obj.Project(self.ctx, external_id='another-project')
     p.create()
     c = consumer_obj.Consumer(
         self.ctx, uuid=uuids.consumer, user=u, project=p)
     c.create()
     c = consumer_obj.Consumer.get_by_uuid(self.ctx, uuids.consumer)
     self.assertEqual(1, c.id)
     # Project ID == 1 is fake-project created in setup
     self.assertEqual(2, c.project.id)
     # User ID == 1 is fake-user created in setup
     self.assertEqual(2, c.user.id)
     self.assertRaises(exception.ConsumerExists, c.create)
예제 #12
0
def get_all_by_consumer_id(context, consumer_id):
    _create_incomplete_consumer(context, consumer_id)
    db_allocs = _get_allocations_by_consumer_uuid(context, consumer_id)

    if not db_allocs:
        return []

    # Build up the Consumer object (it's the same for all allocations
    # since we looked up by consumer ID)
    db_first = db_allocs[0]
    consumer = consumer_obj.Consumer(
        context,
        id=db_first['consumer_id'],
        uuid=db_first['consumer_uuid'],
        generation=db_first['consumer_generation'],
        project=project_obj.Project(
            context,
            id=db_first['project_id'],
            external_id=db_first['project_external_id']),
        user=user_obj.User(context,
                           id=db_first['user_id'],
                           external_id=db_first['user_external_id']))

    # Build up a list of Allocation objects, setting the Allocation object
    # fields to the same-named database record field we got from
    # _get_allocations_by_consumer_id().
    #
    # NOTE(jaypipes):  Unlike with get_all_by_resource_provider(), we do
    # NOT already have the ResourceProvider object so we construct a new
    # ResourceProvider object below by looking at the resource provider
    # fields returned by _get_allocations_by_consumer_id().
    alloc_list = [
        Allocation(id=rec['id'],
                   resource_provider=rp_obj.ResourceProvider(
                       context,
                       id=rec['resource_provider_id'],
                       uuid=rec['resource_provider_uuid'],
                       name=rec['resource_provider_name'],
                       generation=rec['resource_provider_generation']),
                   resource_class=rc_cache.RC_CACHE.string_from_id(
                       rec['resource_class_id']),
                   consumer=consumer,
                   used=rec['used'],
                   created_at=rec['created_at'],
                   updated_at=rec['updated_at']) for rec in db_allocs
    ]
    return alloc_list
예제 #13
0
파일: consumer.py 프로젝트: sapcc/placement
    def _from_db_object(ctx, target, source):
        target.id = source['id']
        target.uuid = source['uuid']
        target.generation = source['generation']
        target.created_at = source['created_at']
        target.updated_at = source['updated_at']

        target.project = project_obj.Project(
            ctx,
            id=source['project_id'],
            external_id=source['project_external_id'])
        target.user = user_obj.User(ctx,
                                    id=source['user_id'],
                                    external_id=source['user_external_id'])

        target._context = ctx
        return target
예제 #14
0
    def test_existing_project_no_existing_consumer_before_gen_success(self):
        """Check that if we find an existing project and user, that we use
        those found objects in creating the consumer. Do not require a consumer
        generation before the appropriate microversion.
        """
        proj = project_obj.Project(self.ctx, uuid=self.project_id)
        self.mock_project_get.return_value = proj
        user = user_obj.User(self.ctx, uuid=self.user_id)
        self.mock_user_get.return_value = user
        self.mock_consumer_get.side_effect = exception.NotFound

        consumer_gen = None  # should be ignored
        util.ensure_consumer(self.ctx, self.consumer_id, self.project_id,
                             self.user_id, consumer_gen, self.before_version)

        self.mock_project_create.assert_not_called()
        self.mock_user_create.assert_not_called()
        self.mock_consumer_create.assert_called_once()
예제 #15
0
    def test_existing_consumer_after_gen_fail(self):
        """Tests that we require a consumer_generation after the
        appropriate microversion and that when the consumer already exists,
        then we raise a 400 when there is a mismatch on the existing
        generation.
        """
        proj = project_obj.Project(self.ctx, uuid=self.project_id)
        self.mock_project_get.return_value = proj
        user = user_obj.User(self.ctx, uuid=self.user_id)
        self.mock_user_get.return_value = user
        consumer = consumer_obj.Consumer(self.ctx,
                                         project=proj,
                                         user=user,
                                         generation=42)
        self.mock_consumer_get.return_value = consumer

        consumer_gen = 2  # should NOT be ignored (and 2 is NOT expected)
        self.assertRaises(webob.exc.HTTPConflict, util.ensure_consumer,
                          self.ctx, self.consumer_id, self.project_id,
                          self.user_id, consumer_gen, self.after_version)
예제 #16
0
    def test_existing_consumer_after_gen_matches_supplied_gen(self):
        """Tests that we require a consumer_generation after the
        appropriate microversion and that when the consumer already exists,
        then we ensure a matching generation is supplied
        """
        proj = project_obj.Project(self.ctx, id=1, external_id=self.project_id)
        self.mock_project_get.return_value = proj
        user = user_obj.User(self.ctx, id=1, external_id=self.user_id)
        self.mock_user_get.return_value = user
        consumer = consumer_obj.Consumer(
            self.ctx, id=1, project=proj, user=user, generation=2)
        self.mock_consumer_get.return_value = consumer

        consumer_gen = 2  # should NOT be ignored (and 2 is expected)
        util.ensure_consumer(
            self.ctx, self.consumer_id, self.project_id, self.user_id,
            consumer_gen, self.after_version)

        self.mock_project_create.assert_not_called()
        self.mock_user_create.assert_not_called()
        self.mock_consumer_create.assert_not_called()
예제 #17
0
def get_all_by_resource_provider(context, rp):
    _create_incomplete_consumers_for_provider(context, rp.uuid)
    db_allocs = _get_allocations_by_provider_uuid(context, rp.uuid)
    # Build up a list of Allocation objects, setting the Allocation object
    # fields to the same-named database record field we got from
    # _get_allocations_by_provider_uuid(). We already have the
    # ResourceProvider object so we just pass that object to the Allocation
    # object constructor as-is
    objs = []
    for rec in db_allocs:
        consumer = consumer_obj.Consumer(
            context,
            uuid=rec["consumer_uuid"],
            generation=rec["consumer_generation"],
            project=project_obj.Project(context, uuid=rec["project_uuid"]),
            user=user_obj.User(context, uuid=rec["user_uuid"]))
        objs.append(
            Allocation(resource_provider=rp,
                       resource_class=rec["resource_class_name"],
                       consumer=consumer,
                       used=rec["used"],
                       created_at=rec["created_at"],
                       updated_at=rec["updated_at"]))
    return objs
예제 #18
0
파일: util.py 프로젝트: sapcc/placement
def ensure_consumer(ctx, consumer_uuid, project_id, user_id,
                    consumer_generation, want_version):
    """Ensures there are records in the consumers, projects and users table for
    the supplied external identifiers.

    Returns a tuple containing the populated Consumer object containing Project
    and User sub-objects and a boolean indicating whether a new Consumer object
    was created (as opposed to an existing consumer record retrieved)

    :note: If the supplied project or user external identifiers do not match an
           existing consumer's project and user identifiers, the existing
           consumer's project and user IDs are updated to reflect the supplied
           ones.

    :param ctx: The request context.
    :param consumer_uuid: The uuid of the consumer of the resources.
    :param project_id: The external ID of the project consuming the resources.
    :param user_id: The external ID of the user consuming the resources.
    :param consumer_generation: The generation provided by the user for this
        consumer.
    :param want_version: the microversion matcher.
    :raises webob.exc.HTTPConflict if consumer generation is required and there
            was a mismatch
    """
    created_new_consumer = False
    requires_consumer_generation = want_version.matches((1, 28))
    if project_id is None:
        project_id = ctx.config.placement.incomplete_consumer_project_id
        user_id = ctx.config.placement.incomplete_consumer_user_id
    try:
        proj = project_obj.Project.get_by_external_id(ctx, project_id)
    except exception.NotFound:
        # Auto-create the project if we found no record of it...
        try:
            proj = project_obj.Project(ctx, external_id=project_id)
            proj.create()
        except exception.ProjectExists:
            # No worries, another thread created this project already
            proj = project_obj.Project.get_by_external_id(ctx, project_id)
    try:
        user = user_obj.User.get_by_external_id(ctx, user_id)
    except exception.NotFound:
        # Auto-create the user if we found no record of it...
        try:
            user = user_obj.User(ctx, external_id=user_id)
            user.create()
        except exception.UserExists:
            # No worries, another thread created this user already
            user = user_obj.User.get_by_external_id(ctx, user_id)

    try:
        consumer = consumer_obj.Consumer.get_by_uuid(ctx, consumer_uuid)
        if requires_consumer_generation:
            if consumer.generation != consumer_generation:
                raise webob.exc.HTTPConflict(
                    'consumer generation conflict - '
                    'expected %(expected_gen)s but got %(got_gen)s' % {
                        'expected_gen': consumer.generation,
                        'got_gen': consumer_generation,
                    },
                    comment=errors.CONCURRENT_UPDATE)
        # NOTE(jaypipes): The user may have specified a different project and
        # user external ID than the one that we had for the consumer. If this
        # is the case, go ahead and modify the consumer record with the
        # newly-supplied project/user information, but do not bump the consumer
        # generation (since it will be bumped in the
        # AllocationList.replace_all() method).
        #
        # TODO(jaypipes): This means that there may be a partial update.
        # Imagine a scenario where a user calls POST /allocations, and the
        # payload references two consumers. The first consumer is a new
        # consumer and is auto-created. The second consumer is an existing
        # consumer, but contains a different project or user ID than the
        # existing consumer's record. If the eventual call to
        # AllocationList.replace_all() fails for whatever reason (say, a
        # resource provider generation conflict or out of resources failure),
        # we will end up deleting the auto-created consumer but we MAY not undo
        # the changes to the second consumer's project and user ID. I say MAY
        # and not WILL NOT because I'm not sure that the exception that gets
        # raised from AllocationList.replace_all() will cause the context
        # manager's transaction to rollback automatically. I believe that the
        # same transaction context is used for both util.ensure_consumer() and
        # AllocationList.replace_all() within the same HTTP request, but need
        # to test this to be 100% certain...
        if (project_id != consumer.project.external_id
                or user_id != consumer.user.external_id):
            LOG.debug(
                "Supplied project or user ID for consumer %s was "
                "different than existing record. Updating consumer "
                "record.", consumer_uuid)
            consumer.project = proj
            consumer.user = user
            consumer.update()
    except exception.NotFound:
        # If we are attempting to modify or create allocations after 1.26, we
        # need a consumer generation specified. The user must have specified
        # None for the consumer generation if we get here, since there was no
        # existing consumer with this UUID and therefore the user should be
        # indicating that they expect the consumer did not exist.
        if requires_consumer_generation:
            if consumer_generation is not None:
                raise webob.exc.HTTPConflict('consumer generation conflict - '
                                             'expected null but got %s' %
                                             consumer_generation,
                                             comment=errors.CONCURRENT_UPDATE)
        # No such consumer. This is common for new allocations. Create the
        # consumer record
        try:
            consumer = consumer_obj.Consumer(ctx,
                                             uuid=consumer_uuid,
                                             project=proj,
                                             user=user)
            consumer.create()
            created_new_consumer = True
        except exception.ConsumerExists:
            # No worries, another thread created this user already
            consumer = consumer_obj.Consumer.get_by_uuid(ctx, consumer_uuid)
    return consumer, created_new_consumer
예제 #19
0
def create_user_and_project(ctx, prefix='fake'):
    user = user_obj.User(ctx, external_id='%s-user' % prefix)
    user.create()
    proj = project_obj.Project(ctx, external_id='%s-project' % prefix)
    proj.create()
    return user, proj