object-ify flavors api and compute/api side of RPC

This change converts flavors to use objects instead of direct database
access. The rpcapi primitivizes objects before they go over the wire.

The flavors.add_flavor_access() and flavors.remove_flavor_access()
functions were also removed as flavor object add_access() and
remove_access() should be used instead.

Related to blueprint kilo-objects

Change-Id: I86432720b600e479d8d8b7f7531a2c85ab364319
This commit is contained in:
melanie witt 2014-08-28 17:39:10 +00:00
parent 4c45902548
commit cb338cb769
12 changed files with 156 additions and 201 deletions

View File

@ -150,6 +150,10 @@ class CellsAPI(object):
build_inst_kwargs['instances'] = instances_p
build_inst_kwargs['image'] = jsonutils.to_primitive(
build_inst_kwargs['image'])
if 'filter_properties' in build_inst_kwargs:
flavor = build_inst_kwargs['filter_properties']['instance_type']
flavor_p = objects_base.obj_to_primitive(flavor)
build_inst_kwargs['filter_properties']['instance_type'] = flavor_p
cctxt = self.client.prepare(version='1.8')
cctxt.cast(ctxt, 'build_instances',
build_inst_kwargs=build_inst_kwargs)

View File

@ -22,7 +22,6 @@ import re
import uuid
from oslo.config import cfg
from oslo.db import exception as db_exc
from oslo.utils import strutils
import six
@ -31,6 +30,7 @@ from nova import db
from nova import exception
from nova.i18n import _
from nova.i18n import _LE
from nova import objects
from nova.openstack.common import log as logging
from nova import utils
@ -170,11 +170,9 @@ def create(name, memory, vcpus, root_gb, ephemeral_gb=0, flavorid=None,
except ValueError:
raise exception.InvalidInput(reason=_("is_public must be a boolean"))
try:
return db.flavor_create(context.get_admin_context(), kwargs)
except db_exc.DBError as e:
LOG.exception(_LE('DB error: %s'), e)
raise exception.FlavorCreateFailed()
flavor = objects.Flavor(context=context.get_admin_context(), **kwargs)
flavor.create()
return flavor
def destroy(name):
@ -182,7 +180,9 @@ def destroy(name):
try:
if not name:
raise ValueError()
db.flavor_destroy(context.get_admin_context(), name)
flavor = objects.Flavor(name=name)
ctxt = context.get_admin_context()
flavor.destroy(ctxt)
except (ValueError, exception.NotFound):
LOG.exception(_LE('Instance type %s not found for deletion'), name)
raise exception.FlavorNotFoundByName(flavor_name=name)
@ -191,32 +191,30 @@ def destroy(name):
def get_all_flavors(ctxt=None, inactive=False, filters=None):
"""Get all non-deleted flavors as a dict.
Pass true as argument if you want deleted flavors returned also.
Pass inactive=True if you want deleted flavors returned also.
"""
if ctxt is None:
ctxt = context.get_admin_context()
inst_types = db.flavor_get_all(
ctxt, inactive=inactive, filters=filters)
inst_types = objects.FlavorList.get_all(ctxt, inactive=inactive,
filters=filters)
inst_type_dict = {}
for inst_type in inst_types:
inst_type_dict[inst_type['id']] = inst_type
inst_type_dict[inst_type.id] = inst_type
return inst_type_dict
def get_all_flavors_sorted_list(ctxt=None, inactive=False, filters=None,
sort_key='flavorid', sort_dir='asc',
limit=None, marker=None):
def get_all_flavors_sorted_list(ctxt=None, filters=None, sort_key='flavorid',
sort_dir='asc', limit=None, marker=None):
"""Get all non-deleted flavors as a sorted list.
Pass true as argument if you want deleted flavors returned also.
"""
if ctxt is None:
ctxt = context.get_admin_context()
return db.flavor_get_all(ctxt, filters=filters, sort_key=sort_key,
sort_dir=sort_dir, limit=limit, marker=marker)
return objects.FlavorList.get_all(ctxt, filters=filters, sort_key=sort_key,
sort_dir=sort_dir, limit=limit,
marker=marker)
def get_default_flavor():
@ -236,7 +234,7 @@ def get_flavor(instance_type_id, ctxt=None, inactive=False):
if inactive:
ctxt = ctxt.elevated(read_deleted="yes")
return db.flavor_get(ctxt, instance_type_id)
return objects.Flavor.get_by_id(ctxt, instance_type_id)
def get_flavor_by_name(name, ctxt=None):
@ -247,7 +245,7 @@ def get_flavor_by_name(name, ctxt=None):
if ctxt is None:
ctxt = context.get_admin_context()
return db.flavor_get_by_name(ctxt, name)
return objects.Flavor.get_by_name(ctxt, name)
# TODO(termie): flavor-specific code should probably be in the API that uses
@ -260,8 +258,7 @@ def get_flavor_by_flavor_id(flavorid, ctxt=None, read_deleted="yes"):
if ctxt is None:
ctxt = context.get_admin_context(read_deleted=read_deleted)
# NOTE(melwitt): return a copy temporarily until conversion to object
return dict(db.flavor_get_by_flavor_id(ctxt, flavorid, read_deleted))
return objects.Flavor.get_by_flavor_id(ctxt, flavorid, read_deleted)
def get_flavor_access_by_flavor_id(flavorid, ctxt=None):
@ -269,35 +266,20 @@ def get_flavor_access_by_flavor_id(flavorid, ctxt=None):
if ctxt is None:
ctxt = context.get_admin_context()
return db.flavor_access_get_by_flavor_id(ctxt, flavorid)
def add_flavor_access(flavorid, projectid, ctxt=None):
"""Add flavor access for project."""
if ctxt is None:
ctxt = context.get_admin_context()
return db.flavor_access_add(ctxt, flavorid, projectid)
def remove_flavor_access(flavorid, projectid, ctxt=None):
"""Remove flavor access for project."""
if ctxt is None:
ctxt = context.get_admin_context()
return db.flavor_access_remove(ctxt, flavorid, projectid)
flavor = objects.Flavor.get_by_flavor_id(ctxt, flavorid)
return flavor.projects
def extract_flavor(instance, prefix=''):
"""Create an InstanceType-like object from instance's system_metadata
"""Create a Flavor object from instance's system_metadata
information.
"""
instance_type = {}
flavor = objects.Flavor()
sys_meta = utils.instance_sys_meta(instance)
for key, type_fn in system_metadata_flavor_props.items():
for key in system_metadata_flavor_props.keys():
type_key = '%sinstance_type_%s' % (prefix, key)
instance_type[key] = type_fn(sys_meta[type_key])
setattr(flavor, key, sys_meta[type_key])
# NOTE(danms): We do NOT save all of extra_specs, but only the
# NUMA-related ones that we need to avoid an uglier alternative. This
@ -306,12 +288,12 @@ def extract_flavor(instance, prefix=''):
extra_specs = [(k, v) for k, v in sys_meta.items()
if k.startswith('%sinstance_type_extra_' % prefix)]
if extra_specs:
instance_type['extra_specs'] = {}
flavor.extra_specs = {}
for key, value in extra_specs:
extra_key = key[len('%sinstance_type_extra_' % prefix):]
instance_type['extra_specs'][extra_key] = value
flavor.extra_specs[extra_key] = value
return instance_type
return flavor
def save_flavor_info(metadata, instance_type, prefix=''):

View File

@ -782,10 +782,7 @@ class ResourceTracker(object):
if not instance_type_id:
instance_type_id = instance['instance_type_id']
return objects.Flavor.get_by_id(context, instance_type_id)
# NOTE (ndipanov): Make sure we don't try to lazy-load extra_specs
# from the object, if there were none stashed in system_metadata
extracted_flavor.setdefault('extra_specs', {})
return objects.Flavor(context, **extracted_flavor)
return extracted_flavor
def _get_usage_dict(self, object_or_dict, **updates):
"""Make a usage dict _update methods expect.

View File

@ -887,6 +887,10 @@ class ComputeAPI(object):
requested_networks = [(network_id, address, port_id)
for (network_id, address, port_id, _) in
requested_networks.as_tuples()]
if 'instance_type' in filter_properties:
flavor = filter_properties['instance_type']
flavor_p = objects_base.obj_to_primitive(flavor)
filter_properties = dict(filter_properties, instance_type=flavor_p)
cctxt = self.client.prepare(server=host, version=version)
cctxt.cast(ctxt, 'build_and_run_instance', instance=instance,

View File

@ -417,6 +417,10 @@ class ComputeTaskAPI(object):
admin_password, injected_files, requested_networks,
security_groups, block_device_mapping, legacy_bdm=True):
image_p = jsonutils.to_primitive(image)
if 'instance_type' in filter_properties:
flavor = filter_properties['instance_type']
flavor_p = objects_base.obj_to_primitive(flavor)
filter_properties = dict(filter_properties, instance_type=flavor_p)
kw = {'instances': instances, 'image': image_p,
'filter_properties': filter_properties,
'admin_password': admin_password,

View File

@ -103,6 +103,10 @@ class SchedulerAPI(object):
serializer=serializer)
def select_destinations(self, ctxt, request_spec, filter_properties):
if 'instance_type' in filter_properties:
flavor = filter_properties['instance_type']
flavor_p = objects_base.obj_to_primitive(flavor)
filter_properties = dict(filter_properties, instance_type=flavor_p)
cctxt = self.client.prepare()
return cctxt.call(ctxt, 'select_destinations',
request_spec=request_spec, filter_properties=filter_properties)

View File

@ -21,7 +21,6 @@ from oslo.serialization import jsonutils
from nova.compute import flavors
from nova.compute import utils as compute_utils
from nova import db
from nova import exception
from nova.i18n import _, _LE, _LW
from nova import notifications
@ -57,10 +56,10 @@ def build_request_spec(ctxt, image, instances, instance_type=None):
if instance_type is None:
instance_type = flavors.extract_flavor(instance)
# NOTE(comstud): This is a bit ugly, but will get cleaned up when
# we're passing an InstanceType internal object.
extra_specs = db.flavor_extra_specs_get(ctxt, instance_type['flavorid'])
instance_type['extra_specs'] = extra_specs
if isinstance(instance_type, objects.Flavor):
instance_type = obj_base.obj_to_primitive(instance_type)
request_spec = {
'image': image or {},
'instance_properties': instance,

View File

@ -425,8 +425,6 @@ class PrivateFlavorManageTestV21(test.TestCase):
def test_create_public_flavor_should_not_create_flavor_access(self):
self.expected["flavor"]["os-flavor-access:is_public"] = True
self.mox.StubOutWithMock(flavors, "add_flavor_access")
self.mox.ReplayAll()
body = self._get_response()
for key in self.expected["flavor"]:
self.assertEqual(body["flavor"][key], self.expected["flavor"][key])

View File

@ -77,7 +77,7 @@ class _ComputeAPIUnitTestMixIn(object):
exclude_states = set()
return vm_state - exclude_states
def _create_flavor(self, params=None):
def _create_flavor(self, **updates):
flavor = {'id': 1,
'flavorid': 1,
'name': 'm1.tiny',
@ -91,10 +91,15 @@ class _ComputeAPIUnitTestMixIn(object):
'deleted': 0,
'disabled': False,
'is_public': True,
'deleted_at': None,
'created_at': datetime.datetime(2012, 1, 19, 18,
49, 30, 877329),
'updated_at': None,
}
if params:
flavor.update(params)
return flavor
if updates:
flavor.update(updates)
return objects.Flavor._from_db_object(self.context, objects.Flavor(),
flavor)
def _create_instance_obj(self, params=None, flavor=None):
"""Create a test instance."""
@ -129,7 +134,7 @@ class _ComputeAPIUnitTestMixIn(object):
instance.project_id = self.project_id
instance.host = 'fake_host'
instance.node = NODENAME
instance.instance_type_id = flavor['id']
instance.instance_type_id = flavor.id
instance.ami_launch_index = 0
instance.memory_mb = 0
instance.vcpus = 0
@ -516,10 +521,9 @@ class _ComputeAPIUnitTestMixIn(object):
self.context, objects.Migration(),
fake_db_migration)
inst.instance_type_id = migration.new_instance_type_id
old_flavor = {'vcpus': 1,
'memory_mb': 512}
deltas['cores'] = -old_flavor['vcpus']
deltas['ram'] = -old_flavor['memory_mb']
old_flavor = self._create_flavor(vcpus=1, memory_mb=512)
deltas['cores'] = -old_flavor.vcpus
deltas['ram'] = -old_flavor.memory_mb
self.mox.StubOutWithMock(objects.Migration,
'get_by_instance_and_status')
@ -1220,11 +1224,11 @@ class _ComputeAPIUnitTestMixIn(object):
current_flavor = flavors.extract_flavor(fake_inst)
if flavor_id_passed:
new_flavor = dict(id=200, flavorid='new-flavor-id',
name='new_flavor', disabled=False)
new_flavor = self._create_flavor(id=200, flavorid='new-flavor-id',
name='new_flavor', disabled=False)
if same_flavor:
cur_flavor = flavors.extract_flavor(fake_inst)
new_flavor['id'] = cur_flavor['id']
new_flavor.id = cur_flavor.id
flavors.get_flavor_by_flavor_id(
'new-flavor-id',
read_deleted='no').AndReturn(new_flavor)
@ -1240,8 +1244,8 @@ class _ComputeAPIUnitTestMixIn(object):
resvs)
self.compute_api._upsize_quota_delta(
self.context, new_flavor,
current_flavor).AndReturn('deltas')
self.context, mox.IsA(objects.Flavor),
mox.IsA(objects.Flavor)).AndReturn('deltas')
self.compute_api._reserve_quota_delta(self.context, 'deltas',
fake_inst).AndReturn(fake_quotas)
@ -1274,9 +1278,9 @@ class _ComputeAPIUnitTestMixIn(object):
def _check_mig(ctxt):
self.assertEqual(fake_inst.uuid, mig.instance_uuid)
self.assertEqual(current_flavor['id'],
self.assertEqual(current_flavor.id,
mig.old_instance_type_id)
self.assertEqual(new_flavor['id'],
self.assertEqual(new_flavor.id,
mig.new_instance_type_id)
self.assertEqual('finished', mig.status)
@ -1299,7 +1303,8 @@ class _ComputeAPIUnitTestMixIn(object):
self.compute_api.compute_task_api.resize_instance(
self.context, fake_inst, extra_kwargs,
scheduler_hint=scheduler_hint,
flavor=new_flavor, reservations=expected_reservations)
flavor=mox.IsA(objects.Flavor),
reservations=expected_reservations)
self.mox.ReplayAll()
@ -1376,8 +1381,8 @@ class _ComputeAPIUnitTestMixIn(object):
'resize_instance')
fake_inst = obj_base.obj_to_primitive(self._create_instance_obj())
fake_flavor = dict(id=200, flavorid='flavor-id', name='foo',
disabled=True)
fake_flavor = self._create_flavor(id=200, flavorid='flavor-id',
name='foo', disabled=True)
flavors.get_flavor_by_flavor_id(
'flavor-id', read_deleted='no').AndReturn(fake_flavor)
@ -1391,8 +1396,8 @@ class _ComputeAPIUnitTestMixIn(object):
@mock.patch.object(flavors, 'get_flavor_by_flavor_id')
def test_resize_to_zero_disk_flavor_fails(self, get_flavor_by_flavor_id):
fake_inst = self._create_instance_obj()
fake_flavor = dict(id=200, flavorid='flavor-id', name='foo',
root_gb=0)
fake_flavor = self._create_flavor(id=200, flavorid='flavor-id',
name='foo', root_gb=0)
get_flavor_by_flavor_id.return_value = fake_flavor
@ -1412,15 +1417,14 @@ class _ComputeAPIUnitTestMixIn(object):
'resize_instance')
fake_inst = obj_base.obj_to_primitive(self._create_instance_obj())
current_flavor = flavors.extract_flavor(fake_inst)
fake_flavor = dict(id=200, flavorid='flavor-id', name='foo',
disabled=False)
fake_flavor = self._create_flavor(id=200, flavorid='flavor-id',
name='foo', disabled=False)
flavors.get_flavor_by_flavor_id(
'flavor-id', read_deleted='no').AndReturn(fake_flavor)
deltas = dict(resource=0)
self.compute_api._upsize_quota_delta(
self.context, fake_flavor,
current_flavor).AndReturn(deltas)
self.context, mox.IsA(objects.Flavor),
mox.IsA(objects.Flavor)).AndReturn(deltas)
usage = dict(in_use=0, reserved=0)
quotas = {'resource': 0}
usages = {'resource': usage}

View File

@ -1192,7 +1192,7 @@ class _BaseTaskTestCase(object):
inst = fake_instance.fake_db_instance(image_ref='image_ref')
inst_obj = objects.Instance._from_db_object(
self.context, objects.Instance(), inst, [])
flavor = flavors.get_default_flavor()
flavor = obj_base.obj_to_primitive(flavors.get_default_flavor())
flavor['extra_specs'] = 'extra_specs'
request_spec = {'instance_type': flavor,
'instance_properties': {}}
@ -1242,10 +1242,9 @@ class _BaseTaskTestCase(object):
system_metadata=system_metadata,
expected_attrs=['system_metadata']) for i in xrange(2)]
instance_type = flavors.extract_flavor(instances[0])
instance_type['extra_specs'] = 'fake-specs'
instance_type_p = jsonutils.to_primitive(instance_type)
instance_properties = jsonutils.to_primitive(instances[0])
self.mox.StubOutWithMock(db, 'flavor_extra_specs_get')
self.mox.StubOutWithMock(scheduler_utils, 'setup_instance_group')
self.mox.StubOutWithMock(self.conductor_manager.scheduler_client,
'select_destinations')
@ -1255,15 +1254,12 @@ class _BaseTaskTestCase(object):
self.mox.StubOutWithMock(self.conductor_manager.compute_rpcapi,
'build_and_run_instance')
db.flavor_extra_specs_get(
self.context,
instance_type['flavorid']).AndReturn('fake-specs')
scheduler_utils.setup_instance_group(self.context, None, None)
self.conductor_manager.scheduler_client.select_destinations(
self.context, {'image': {'fake_data': 'should_pass_silently'},
'instance_properties': jsonutils.to_primitive(
instances[0]),
'instance_type': instance_type,
'instance_type': instance_type_p,
'instance_uuids': [inst.uuid for inst in instances],
'num_instances': 2},
{'retry': {'num_attempts': 1, 'hosts': []}}).AndReturn(
@ -1283,7 +1279,7 @@ class _BaseTaskTestCase(object):
request_spec={
'image': {'fake_data': 'should_pass_silently'},
'instance_properties': instance_properties,
'instance_type': instance_type,
'instance_type': instance_type_p,
'instance_uuids': [inst.uuid for inst in instances],
'num_instances': 2},
filter_properties={'retry': {'num_attempts': 1,
@ -1309,7 +1305,7 @@ class _BaseTaskTestCase(object):
request_spec={
'image': {'fake_data': 'should_pass_silently'},
'instance_properties': instance_properties,
'instance_type': instance_type,
'instance_type': instance_type_p,
'instance_uuids': [inst.uuid for inst in instances],
'num_instances': 2},
filter_properties={'limits': [],

View File

@ -48,9 +48,7 @@ class SchedulerUtilsTestCase(test.NoDBTestCase):
instance_type = {'flavorid': 'fake-id'}
self.mox.StubOutWithMock(flavors, 'extract_flavor')
self.mox.StubOutWithMock(db, 'flavor_extra_specs_get')
flavors.extract_flavor(mox.IgnoreArg()).AndReturn(instance_type)
db.flavor_extra_specs_get(self.context, mox.IgnoreArg()).AndReturn([])
self.mox.ReplayAll()
request_spec = scheduler_utils.build_request_spec(self.context, image,
@ -58,14 +56,11 @@ class SchedulerUtilsTestCase(test.NoDBTestCase):
self.assertEqual({}, request_spec['image'])
@mock.patch.object(flavors, 'extract_flavor')
@mock.patch.object(db, 'flavor_extra_specs_get')
def test_build_request_spec_with_object(self, flavor_extra_specs_get,
extract_flavor):
def test_build_request_spec_with_object(self, extract_flavor):
instance_type = {'flavorid': 'fake-id'}
instance = fake_instance.fake_instance_obj(self.context)
extract_flavor.return_value = instance_type
flavor_extra_specs_get.return_value = []
request_spec = scheduler_utils.build_request_spec(self.context, None,
[instance])

View File

@ -21,6 +21,8 @@ from nova import db
from nova.db.sqlalchemy import api as sql_session
from nova.db.sqlalchemy import models
from nova import exception
from nova import objects
from nova.objects import base as obj_base
from nova import test
@ -67,7 +69,7 @@ class InstanceTypeTestCase(test.TestCase):
def _generate_flavorid(self):
"""return a flavorid not in the DB."""
nonexistent_flavor = 2700
flavor_ids = [value["id"] for key, value in
flavor_ids = [value.id for key, value in
flavors.get_all_flavors().iteritems()]
while nonexistent_flavor in flavor_ids:
nonexistent_flavor += 1
@ -78,62 +80,6 @@ class InstanceTypeTestCase(test.TestCase):
"""return first flavor name."""
return flavors.get_all_flavors().keys()[0]
def test_add_instance_type_access(self):
user_id = 'fake'
project_id = 'fake'
ctxt = context.RequestContext(user_id, project_id, is_admin=True)
flavor_id = 'flavor1'
type_ref = flavors.create('some flavor', 256, 1, 120, 100,
flavorid=flavor_id)
access_ref = flavors.add_flavor_access(flavor_id,
project_id,
ctxt=ctxt)
self.assertEqual(access_ref["project_id"], project_id)
self.assertEqual(access_ref["instance_type_id"], type_ref["id"])
def test_add_flavor_access_already_exists(self):
user_id = 'fake'
project_id = 'fake'
ctxt = context.RequestContext(user_id, project_id, is_admin=True)
flavor_id = 'flavor1'
flavors.create('some flavor', 256, 1, 120, 100, flavorid=flavor_id)
flavors.add_flavor_access(flavor_id, project_id, ctxt=ctxt)
self.assertRaises(exception.FlavorAccessExists,
flavors.add_flavor_access,
flavor_id, project_id, ctxt)
def test_add_flavor_access_invalid_flavor(self):
user_id = 'fake'
project_id = 'fake'
ctxt = context.RequestContext(user_id, project_id, is_admin=True)
flavor_id = 'no_such_flavor'
self.assertRaises(exception.FlavorNotFound,
flavors.add_flavor_access,
flavor_id, project_id, ctxt)
def test_remove_flavor_access(self):
user_id = 'fake'
project_id = 'fake'
ctxt = context.RequestContext(user_id, project_id, is_admin=True)
flavor_id = 'flavor1'
flavors.create('some flavor', 256, 1, 120, 100, flavorid=flavor_id)
flavors.add_flavor_access(flavor_id, project_id, ctxt)
flavors.remove_flavor_access(flavor_id, project_id, ctxt)
projects = flavors.get_flavor_access_by_flavor_id(flavor_id,
ctxt)
self.assertEqual([], projects)
def test_remove_flavor_access_does_not_exist(self):
user_id = 'fake'
project_id = 'fake'
ctxt = context.RequestContext(user_id, project_id, is_admin=True)
flavor_id = 'flavor1'
flavors.create('some flavor', 256, 1, 120, 100, flavorid=flavor_id)
self.assertRaises(exception.FlavorAccessNotFound,
flavors.remove_flavor_access,
flavor_id, project_id, ctxt=ctxt)
def test_get_all_instance_types(self):
# Ensures that all flavors can be retrieved.
session = sql_session.get_session()
@ -160,9 +106,10 @@ class InstanceTypeTestCase(test.TestCase):
def test_will_get_flavor_by_id(self):
default_instance_type = flavors.get_default_flavor()
instance_type_id = default_instance_type['id']
instance_type_id = default_instance_type.id
fetched = flavors.get_flavor(instance_type_id)
self.assertEqual(default_instance_type, fetched)
self.assertIsInstance(fetched, objects.Flavor)
self.assertEqual(default_instance_type.flavorid, fetched.flavorid)
def test_will_not_get_flavor_by_unknown_id(self):
# Ensure get by name returns default flavor with no name.
@ -178,7 +125,9 @@ class InstanceTypeTestCase(test.TestCase):
# Ensure get by name returns default flavor with no name.
default = flavors.get_default_flavor()
actual = flavors.get_flavor_by_name(None)
self.assertEqual(default, actual)
self.assertIsInstance(default, objects.Flavor)
self.assertIsInstance(actual, objects.Flavor)
self.assertEqual(default.flavorid, actual.flavorid)
def test_will_not_get_flavor_with_bad_name(self):
# Ensure get by name returns default flavor with bad name.
@ -193,9 +142,10 @@ class InstanceTypeTestCase(test.TestCase):
def test_will_get_instance_by_flavor_id(self):
default_instance_type = flavors.get_default_flavor()
flavorid = default_instance_type['flavorid']
flavorid = default_instance_type.flavorid
fetched = flavors.get_flavor_by_flavor_id(flavorid)
self.assertEqual(default_instance_type, fetched)
self.assertIsInstance(fetched, objects.Flavor)
self.assertEqual(default_instance_type.flavorid, fetched.flavorid)
def test_can_read_deleted_types_using_flavor_id(self):
# Ensure deleted flavors can be read when querying flavor_id.
@ -204,15 +154,15 @@ class InstanceTypeTestCase(test.TestCase):
inst_type = flavors.create(inst_type_name, 256, 1, 120, 100,
inst_type_flavor_id)
self.assertEqual(inst_type_name, inst_type["name"])
self.assertEqual(inst_type_name, inst_type.name)
# NOTE(jk0): The deleted flavor will show up here because the context
# in get_flavor_by_flavor_id() is set to use read_deleted by
# default.
flavors.destroy(inst_type["name"])
flavors.destroy(inst_type.name)
deleted_inst_type = flavors.get_flavor_by_flavor_id(
inst_type_flavor_id)
self.assertEqual(inst_type_name, deleted_inst_type["name"])
self.assertEqual(inst_type_name, deleted_inst_type.name)
def test_read_deleted_false_converting_flavorid(self):
"""Ensure deleted flavors are not returned when not needed (for
@ -225,17 +175,25 @@ class InstanceTypeTestCase(test.TestCase):
instance_type = flavors.get_flavor_by_flavor_id(
"test1", read_deleted="no")
self.assertEqual("instance_type1_redo", instance_type["name"])
self.assertEqual("instance_type1_redo", instance_type.name)
def test_get_all_flavors_sorted_list_sort(self):
# Test default sort
all_flavors = flavors.get_all_flavors_sorted_list()
self.assertEqual(DEFAULT_FLAVORS, all_flavors)
self.assertEqual(len(DEFAULT_FLAVORS), len(all_flavors))
for i in range(len(all_flavors)):
f = all_flavors[i]
self.assertIsInstance(f, objects.Flavor)
self.assertEqual(DEFAULT_FLAVORS[i]['flavorid'], f.flavorid)
# Test sorted by name
all_flavors = flavors.get_all_flavors_sorted_list(sort_key='name')
expected = sorted(DEFAULT_FLAVORS, key=lambda item: item['name'])
self.assertEqual(expected, all_flavors)
self.assertEqual(len(expected), len(all_flavors))
for i in range(len(all_flavors)):
f = all_flavors[i]
self.assertIsInstance(f, objects.Flavor)
self.assertEqual(expected[i]['flavorid'], f.flavorid)
def test_get_all_flavors_sorted_list_limit(self):
limited_flavors = flavors.get_all_flavors_sorted_list(limit=2)
@ -245,12 +203,17 @@ class InstanceTypeTestCase(test.TestCase):
all_flavors = flavors.get_all_flavors_sorted_list()
# Set the 3rd result as the marker
marker_flavorid = all_flavors[2]['flavorid']
marker_flavorid = all_flavors[2].flavorid
marked_flavors = flavors.get_all_flavors_sorted_list(
marker=marker_flavorid)
# We expect everything /after/ the 3rd result
expected_results = all_flavors[3:]
self.assertEqual(expected_results, marked_flavors)
self.assertEqual(len(expected_results), len(marked_flavors))
for i in range(len(marked_flavors)):
f = marked_flavors[i]
self.assertIsInstance(f, objects.Flavor)
self.assertEqual(expected_results[i].flavorid,
f.flavorid)
def test_get_inactive_flavors(self):
flav1 = flavors.create('flavor1', 256, 1, 120)
@ -258,12 +221,12 @@ class InstanceTypeTestCase(test.TestCase):
flavors.destroy('flavor1')
returned_flavors_ids = flavors.get_all_flavors().keys()
self.assertNotIn(flav1['id'], returned_flavors_ids)
self.assertIn(flav2['id'], returned_flavors_ids)
self.assertNotIn(flav1.id, returned_flavors_ids)
self.assertIn(flav2.id, returned_flavors_ids)
returned_flavors_ids = flavors.get_all_flavors(inactive=True).keys()
self.assertIn(flav1['id'], returned_flavors_ids)
self.assertIn(flav2['id'], returned_flavors_ids)
self.assertIn(flav1.id, returned_flavors_ids)
self.assertIn(flav2.id, returned_flavors_ids)
def test_get_inactive_flavors_with_same_name(self):
flav1 = flavors.create('flavor', 256, 1, 120)
@ -271,12 +234,12 @@ class InstanceTypeTestCase(test.TestCase):
flav2 = flavors.create('flavor', 512, 4, 250)
returned_flavors_ids = flavors.get_all_flavors().keys()
self.assertNotIn(flav1['id'], returned_flavors_ids)
self.assertIn(flav2['id'], returned_flavors_ids)
self.assertNotIn(flav1.id, returned_flavors_ids)
self.assertIn(flav2.id, returned_flavors_ids)
returned_flavors_ids = flavors.get_all_flavors(inactive=True).keys()
self.assertIn(flav1['id'], returned_flavors_ids)
self.assertIn(flav2['id'], returned_flavors_ids)
self.assertIn(flav1.id, returned_flavors_ids)
self.assertIn(flav2.id, returned_flavors_ids)
def test_get_inactive_flavors_with_same_flavorid(self):
flav1 = flavors.create('flavor', 256, 1, 120, 100, "flavid")
@ -284,12 +247,12 @@ class InstanceTypeTestCase(test.TestCase):
flav2 = flavors.create('flavor', 512, 4, 250, 100, "flavid")
returned_flavors_ids = flavors.get_all_flavors().keys()
self.assertNotIn(flav1['id'], returned_flavors_ids)
self.assertIn(flav2['id'], returned_flavors_ids)
self.assertNotIn(flav1.id, returned_flavors_ids)
self.assertIn(flav2.id, returned_flavors_ids)
returned_flavors_ids = flavors.get_all_flavors(inactive=True).keys()
self.assertIn(flav1['id'], returned_flavors_ids)
self.assertIn(flav2['id'], returned_flavors_ids)
self.assertIn(flav1.id, returned_flavors_ids)
self.assertIn(flav2.id, returned_flavors_ids)
class InstanceTypeToolsTest(test.TestCase):
@ -298,19 +261,20 @@ class InstanceTypeToolsTest(test.TestCase):
def _test_extract_flavor(self, prefix):
instance_type = flavors.get_default_flavor()
instance_type_p = obj_base.obj_to_primitive(instance_type)
metadata = {}
flavors.save_flavor_info(metadata, instance_type,
prefix)
flavors.save_flavor_info(metadata, instance_type, prefix)
instance = {'system_metadata': self._dict_to_metadata(metadata)}
_instance_type = flavors.extract_flavor(instance, prefix)
_instance_type_p = obj_base.obj_to_primitive(_instance_type)
props = flavors.system_metadata_flavor_props.keys()
for key in instance_type.keys():
for key in instance_type_p.keys():
if key not in props:
del instance_type[key]
del instance_type_p[key]
self.assertEqual(instance_type, _instance_type)
self.assertEqual(instance_type_p, _instance_type_p)
def test_extract_flavor(self):
self._test_extract_flavor('')
@ -494,10 +458,10 @@ class CreateInstanceTypeTest(test.TestCase):
self.assertInvalidInput('flavor1', 64, 1, 120, rxtx_factor=0.0)
flavor = flavors.create('flavor1', 64, 1, 120, rxtx_factor=1.0)
self.assertEqual(1.0, flavor['rxtx_factor'])
self.assertEqual(1.0, flavor.rxtx_factor)
flavor = flavors.create('flavor2', 64, 1, 120, rxtx_factor=1.1)
self.assertEqual(1.1, flavor['rxtx_factor'])
self.assertEqual(1.1, flavor.rxtx_factor)
def test_rxtx_factor_must_be_within_sql_float_range(self):
_context = context.get_admin_context()
@ -511,7 +475,7 @@ class CreateInstanceTypeTest(test.TestCase):
flavor = flavors.create('flavor2', 64, 1, 120,
rxtx_factor=flavors.SQL_SP_FLOAT_MAX)
self.assertEqual(flavors.SQL_SP_FLOAT_MAX, flavor['rxtx_factor'])
self.assertEqual(flavors.SQL_SP_FLOAT_MAX, flavor.rxtx_factor)
def test_is_public_must_be_valid_bool_string(self):
self.assertInvalidInput('flavor1', 64, 1, 120, is_public='foo')
@ -528,21 +492,21 @@ class CreateInstanceTypeTest(test.TestCase):
def test_flavorid_populated(self):
flavor1 = flavors.create('flavor1', 64, 1, 120)
self.assertIsNot(None, flavor1['flavorid'])
self.assertIsNot(None, flavor1.flavorid)
flavor2 = flavors.create('flavor2', 64, 1, 120, flavorid='')
self.assertIsNot(None, flavor2['flavorid'])
self.assertIsNot(None, flavor2.flavorid)
flavor3 = flavors.create('flavor3', 64, 1, 120, flavorid='foo')
self.assertEqual('foo', flavor3['flavorid'])
self.assertEqual('foo', flavor3.flavorid)
def test_default_values(self):
flavor1 = flavors.create('flavor1', 64, 1, 120)
self.assertIsNot(None, flavor1['flavorid'])
self.assertEqual(flavor1['ephemeral_gb'], 0)
self.assertEqual(flavor1['swap'], 0)
self.assertEqual(flavor1['rxtx_factor'], 1.0)
self.assertIsNot(None, flavor1.flavorid)
self.assertEqual(flavor1.ephemeral_gb, 0)
self.assertEqual(flavor1.swap, 0)
self.assertEqual(flavor1.rxtx_factor, 1.0)
def test_basic_create(self):
# Ensure instance types can be created.
@ -550,10 +514,10 @@ class CreateInstanceTypeTest(test.TestCase):
# Create new type and make sure values stick
flavor = flavors.create('flavor', 64, 1, 120)
self.assertEqual(flavor['name'], 'flavor')
self.assertEqual(flavor['memory_mb'], 64)
self.assertEqual(flavor['vcpus'], 1)
self.assertEqual(flavor['root_gb'], 120)
self.assertEqual(flavor.name, 'flavor')
self.assertEqual(flavor.memory_mb, 64)
self.assertEqual(flavor.vcpus, 1)
self.assertEqual(flavor.root_gb, 120)
# Ensure new type shows up in list
new_list = flavors.get_all_flavors()
@ -572,11 +536,15 @@ class CreateInstanceTypeTest(test.TestCase):
flavors.destroy('flavor')
self.assertRaises(exception.FlavorNotFound,
flavors.get_flavor, flavor['id'])
flavors.get_flavor, flavor.id)
# Deleted instance should not be in list anymore
new_list = flavors.get_all_flavors()
self.assertEqual(original_list, new_list)
self.assertEqual(len(original_list), len(new_list))
for k in original_list.keys():
f = original_list[k]
self.assertIsInstance(f, objects.Flavor)
self.assertEqual(f.flavorid, new_list[k].flavorid)
def test_duplicate_names_fail(self):
# Ensures that name duplicates raise FlavorCreateFailed.