282 lines
12 KiB
Python
282 lines
12 KiB
Python
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
"""Tests for manipulating allocations via the DB API"""
|
|
|
|
from oslo_utils import uuidutils
|
|
|
|
from ironic.common import exception
|
|
from ironic.db import api as db_api
|
|
from ironic.tests.unit.db import base
|
|
from ironic.tests.unit.db import utils as db_utils
|
|
|
|
|
|
class AllocationsTestCase(base.DbTestCase):
|
|
|
|
def setUp(self):
|
|
super(AllocationsTestCase, self).setUp()
|
|
self.node = db_utils.create_test_node()
|
|
self.allocation = db_utils.create_test_allocation(name='host1')
|
|
|
|
def test_create(self):
|
|
dbapi = db_api.get_instance()
|
|
allocation = dbapi.create_allocation({'resource_class': 'bm'})
|
|
self.assertIsNotNone(allocation.uuid)
|
|
self.assertEqual('allocating', allocation.state)
|
|
|
|
def _create_test_allocation_range(self, count, start_idx=0, **kw):
|
|
"""Create the specified number of test allocation entries in DB
|
|
|
|
It uses create_test_allocation method. And returns List of Allocation
|
|
DB objects.
|
|
|
|
:param count: Specifies the number of allocations to be created
|
|
:returns: List of Allocation DB objects
|
|
|
|
"""
|
|
return [db_utils.create_test_allocation(uuid=uuidutils.generate_uuid(),
|
|
name='allocation' + str(i),
|
|
**kw).uuid
|
|
for i in range(start_idx, count + start_idx)]
|
|
|
|
def test_get_allocation_by_id(self):
|
|
res = self.dbapi.get_allocation_by_id(self.allocation.id)
|
|
self.assertEqual(self.allocation.uuid, res.uuid)
|
|
|
|
def test_get_allocation_by_id_that_does_not_exist(self):
|
|
self.assertRaises(exception.AllocationNotFound,
|
|
self.dbapi.get_allocation_by_id, 99)
|
|
|
|
def test_get_allocation_by_uuid(self):
|
|
res = self.dbapi.get_allocation_by_uuid(self.allocation.uuid)
|
|
self.assertEqual(self.allocation.id, res.id)
|
|
|
|
def test_get_allocation_by_uuid_that_does_not_exist(self):
|
|
self.assertRaises(exception.AllocationNotFound,
|
|
self.dbapi.get_allocation_by_uuid,
|
|
'EEEEEEEE-EEEE-EEEE-EEEE-EEEEEEEEEEEE')
|
|
|
|
def test_get_allocation_by_name(self):
|
|
res = self.dbapi.get_allocation_by_name(self.allocation.name)
|
|
self.assertEqual(self.allocation.id, res.id)
|
|
|
|
def test_get_allocation_by_name_that_does_not_exist(self):
|
|
self.assertRaises(exception.AllocationNotFound,
|
|
self.dbapi.get_allocation_by_name, 'testfail')
|
|
|
|
def test_get_allocation_list(self):
|
|
uuids = self._create_test_allocation_range(6)
|
|
# Also add the uuid for the allocation created in setUp()
|
|
uuids.append(self.allocation.uuid)
|
|
|
|
res = self.dbapi.get_allocation_list()
|
|
self.assertEqual(set(uuids), {r.uuid for r in res})
|
|
|
|
def test_get_allocation_list_sorted(self):
|
|
uuids = self._create_test_allocation_range(6)
|
|
# Also add the uuid for the allocation created in setUp()
|
|
uuids.append(self.allocation.uuid)
|
|
|
|
res = self.dbapi.get_allocation_list(sort_key='uuid')
|
|
res_uuids = [r.uuid for r in res]
|
|
self.assertEqual(sorted(uuids), res_uuids)
|
|
|
|
def test_get_allocation_list_filter_by_state(self):
|
|
self._create_test_allocation_range(6, state='error')
|
|
|
|
res = self.dbapi.get_allocation_list(filters={'state': 'allocating'})
|
|
self.assertEqual([self.allocation.uuid], [r.uuid for r in res])
|
|
|
|
res = self.dbapi.get_allocation_list(filters={'state': 'error'})
|
|
self.assertEqual(6, len(res))
|
|
|
|
def test_get_allocation_list_filter_by_node(self):
|
|
self._create_test_allocation_range(6)
|
|
self.dbapi.update_allocation(self.allocation.id,
|
|
{'node_id': self.node.id})
|
|
|
|
res = self.dbapi.get_allocation_list(
|
|
filters={'node_uuid': self.node.uuid})
|
|
self.assertEqual([self.allocation.uuid], [r.uuid for r in res])
|
|
|
|
def test_get_allocation_list_filter_by_rsc(self):
|
|
self._create_test_allocation_range(6)
|
|
self.dbapi.update_allocation(self.allocation.id,
|
|
{'resource_class': 'very-large'})
|
|
|
|
res = self.dbapi.get_allocation_list(
|
|
filters={'resource_class': 'very-large'})
|
|
self.assertEqual([self.allocation.uuid], [r.uuid for r in res])
|
|
|
|
def test_get_allocation_list_filter_by_conductor_affinity(self):
|
|
db_utils.create_test_conductor(id=1, hostname='host1')
|
|
db_utils.create_test_conductor(id=2, hostname='host2')
|
|
in_host1 = self._create_test_allocation_range(2, conductor_affinity=1)
|
|
in_host2 = self._create_test_allocation_range(2, conductor_affinity=2,
|
|
start_idx=2)
|
|
|
|
res = self.dbapi.get_allocation_list(
|
|
filters={'conductor_affinity': 1})
|
|
self.assertEqual(set(in_host1), {r.uuid for r in res})
|
|
|
|
res = self.dbapi.get_allocation_list(
|
|
filters={'conductor_affinity': 'host2'})
|
|
self.assertEqual(set(in_host2), {r.uuid for r in res})
|
|
|
|
def test_get_allocation_list_invalid_fields(self):
|
|
self.assertRaises(exception.InvalidParameterValue,
|
|
self.dbapi.get_allocation_list, sort_key='foo')
|
|
self.assertRaises(ValueError,
|
|
self.dbapi.get_allocation_list,
|
|
filters={'foo': 42})
|
|
|
|
def test_destroy_allocation(self):
|
|
self.dbapi.destroy_allocation(self.allocation.id)
|
|
self.assertRaises(exception.AllocationNotFound,
|
|
self.dbapi.get_allocation_by_id, self.allocation.id)
|
|
|
|
def test_destroy_allocation_with_node(self):
|
|
self.dbapi.update_node(self.node.id,
|
|
{'allocation_id': self.allocation.id,
|
|
'instance_uuid': uuidutils.generate_uuid(),
|
|
'instance_info': {'traits': ['foo']}})
|
|
self.dbapi.destroy_allocation(self.allocation.id)
|
|
self.assertRaises(exception.AllocationNotFound,
|
|
self.dbapi.get_allocation_by_id, self.allocation.id)
|
|
node = self.dbapi.get_node_by_id(self.node.id)
|
|
self.assertIsNone(node.allocation_id)
|
|
self.assertIsNone(node.instance_uuid)
|
|
# NOTE(dtantsur): currently we do not clean up instance_info contents
|
|
# on deallocation. It may be changed in the future.
|
|
self.assertEqual(node.instance_info, {'traits': ['foo']})
|
|
|
|
def test_destroy_allocation_that_does_not_exist(self):
|
|
self.assertRaises(exception.AllocationNotFound,
|
|
self.dbapi.destroy_allocation, 99)
|
|
|
|
def test_destroy_allocation_uuid(self):
|
|
self.dbapi.destroy_allocation(self.allocation.uuid)
|
|
|
|
def test_update_allocation(self):
|
|
old_name = self.allocation.name
|
|
new_name = 'newname'
|
|
self.assertNotEqual(old_name, new_name)
|
|
res = self.dbapi.update_allocation(self.allocation.id,
|
|
{'name': new_name})
|
|
self.assertEqual(new_name, res.name)
|
|
|
|
def test_update_allocation_uuid(self):
|
|
self.assertRaises(exception.InvalidParameterValue,
|
|
self.dbapi.update_allocation, self.allocation.id,
|
|
{'uuid': ''})
|
|
|
|
def test_update_allocation_not_found(self):
|
|
id_2 = 99
|
|
self.assertNotEqual(self.allocation.id, id_2)
|
|
self.assertRaises(exception.AllocationNotFound,
|
|
self.dbapi.update_allocation, id_2,
|
|
{'name': 'newname'})
|
|
|
|
def test_update_allocation_duplicated_name(self):
|
|
name1 = self.allocation.name
|
|
allocation2 = db_utils.create_test_allocation(
|
|
uuid=uuidutils.generate_uuid(), name='name2')
|
|
self.assertRaises(exception.AllocationDuplicateName,
|
|
self.dbapi.update_allocation, allocation2.id,
|
|
{'name': name1})
|
|
|
|
def test_update_allocation_with_node_id(self):
|
|
res = self.dbapi.update_allocation(self.allocation.id,
|
|
{'name': 'newname',
|
|
'traits': ['foo'],
|
|
'node_id': self.node.id})
|
|
self.assertEqual('newname', res.name)
|
|
self.assertEqual(['foo'], res.traits)
|
|
self.assertEqual(self.node.id, res.node_id)
|
|
|
|
node = self.dbapi.get_node_by_id(self.node.id)
|
|
self.assertEqual(res.id, node.allocation_id)
|
|
self.assertEqual(res.uuid, node.instance_uuid)
|
|
self.assertEqual(['foo'], node.instance_info['traits'])
|
|
|
|
def test_update_allocation_node_already_associated(self):
|
|
existing_uuid = uuidutils.generate_uuid()
|
|
self.dbapi.update_node(self.node.id, {'instance_uuid': existing_uuid})
|
|
self.assertRaises(exception.NodeAssociated,
|
|
self.dbapi.update_allocation, self.allocation.id,
|
|
{'node_id': self.node.id, 'traits': ['foo']})
|
|
|
|
# Make sure we do not see partial updates
|
|
allocation = self.dbapi.get_allocation_by_id(self.allocation.id)
|
|
self.assertEqual([], allocation.traits)
|
|
self.assertIsNone(allocation.node_id)
|
|
|
|
node = self.dbapi.get_node_by_id(self.node.id)
|
|
self.assertIsNone(node.allocation_id)
|
|
self.assertEqual(existing_uuid, node.instance_uuid)
|
|
self.assertNotIn('traits', node.instance_info)
|
|
|
|
def test_update_allocation_associated_with_another_node(self):
|
|
db_utils.create_test_node(uuid=uuidutils.generate_uuid(),
|
|
allocation_id=self.allocation.id,
|
|
instance_uuid=self.allocation.uuid)
|
|
|
|
self.assertRaises(exception.InstanceAssociated,
|
|
self.dbapi.update_allocation, self.allocation.id,
|
|
{'node_id': self.node.id, 'traits': ['foo']})
|
|
|
|
# Make sure we do not see partial updates
|
|
allocation = self.dbapi.get_allocation_by_id(self.allocation.id)
|
|
self.assertEqual([], allocation.traits)
|
|
self.assertIsNone(allocation.node_id)
|
|
|
|
node = self.dbapi.get_node_by_id(self.node.id)
|
|
self.assertIsNone(node.allocation_id)
|
|
self.assertIsNone(node.instance_uuid)
|
|
self.assertNotIn('traits', node.instance_info)
|
|
|
|
def test_take_over_success(self):
|
|
for i in range(2):
|
|
db_utils.create_test_conductor(id=i, hostname='host-%d' % i)
|
|
allocation = db_utils.create_test_allocation(conductor_affinity=0)
|
|
|
|
self.assertTrue(self.dbapi.take_over_allocation(
|
|
allocation.id, old_conductor_id=0, new_conductor_id=1))
|
|
allocation = self.dbapi.get_allocation_by_id(allocation.id)
|
|
self.assertEqual(1, allocation.conductor_affinity)
|
|
|
|
def test_take_over_conflict(self):
|
|
for i in range(3):
|
|
db_utils.create_test_conductor(id=i, hostname='host-%d' % i)
|
|
allocation = db_utils.create_test_allocation(conductor_affinity=2)
|
|
|
|
self.assertFalse(self.dbapi.take_over_allocation(
|
|
allocation.id, old_conductor_id=0, new_conductor_id=1))
|
|
allocation = self.dbapi.get_allocation_by_id(allocation.id)
|
|
# The affinity was not changed
|
|
self.assertEqual(2, allocation.conductor_affinity)
|
|
|
|
def test_take_over_allocation_not_found(self):
|
|
self.assertRaises(exception.AllocationNotFound,
|
|
self.dbapi.take_over_allocation, 999, 0, 1)
|
|
|
|
def test_create_allocation_duplicated_name(self):
|
|
self.assertRaises(exception.AllocationDuplicateName,
|
|
db_utils.create_test_allocation,
|
|
uuid=uuidutils.generate_uuid(),
|
|
name=self.allocation.name)
|
|
|
|
def test_create_allocation_duplicated_uuid(self):
|
|
self.assertRaises(exception.AllocationAlreadyExists,
|
|
db_utils.create_test_allocation,
|
|
uuid=self.allocation.uuid)
|