Browse Source

Remove references to 'instance_type'

They haven't been instance types in a very long time. We're stuck with
that terminology in the database for now, but otherwise we can replace
references to 'instance_type' with 'flavor'.

While we're here, we also rename a single case of an 'i' variable to a
more informative 'idx'. 'i' is too short to be useful outside of a very
limited scope.

Change-Id: I81fec10535034f3a81d46713a6eda813f90561cf
Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
changes/46/778546/2
Stephen Finucane 7 months ago
parent
commit
1de6e960af
  1. 341
      nova/compute/api.py
  2. 50
      nova/tests/unit/compute/test_api.py
  3. 69
      nova/tests/unit/compute/test_compute.py
  4. 35
      nova/tests/unit/test_quota.py

341
nova/compute/api.py

@ -583,8 +583,9 @@ class API(base.Base):
# reason, we rely on the DB to cast True to a String.
return True if bool_val else ''
def _validate_flavor_image(self, context, image_id, image,
instance_type, root_bdm, validate_numa=True):
def _validate_flavor_image(
self, context, image_id, image, flavor, root_bdm, validate_numa=True,
):
"""Validate the flavor and image.
This is called from the API service to ensure that the flavor
@ -594,20 +595,20 @@ class API(base.Base):
:param context: A context.RequestContext
:param image_id: UUID of the image
:param image: a dict representation of the image including properties,
enforces the image status is active.
:param instance_type: Flavor object
enforces the image status is active.
:param flavor: Flavor object
:param root_bdm: BlockDeviceMapping for root disk. Will be None for
the resize case.
the resize case.
:param validate_numa: Flag to indicate whether or not to validate
the NUMA-related metadata.
:raises: Many different possible exceptions. See
api.openstack.compute.servers.INVALID_FLAVOR_IMAGE_EXCEPTIONS
for the full list.
the NUMA-related metadata.
:raises: Many different possible exceptions. See
api.openstack.compute.servers.INVALID_FLAVOR_IMAGE_EXCEPTIONS
for the full list.
"""
if image and image['status'] != 'active':
raise exception.ImageNotActive(image_id=image_id)
self._validate_flavor_image_nostatus(context, image, instance_type,
root_bdm, validate_numa)
self._validate_flavor_image_nostatus(
context, image, flavor, root_bdm, validate_numa)
@staticmethod
def _detect_nonbootable_image_from_properties(image_id, image):
@ -640,9 +641,10 @@ class API(base.Base):
reason=reason)
@staticmethod
def _validate_flavor_image_nostatus(context, image, instance_type,
root_bdm, validate_numa=True,
validate_pci=False):
def _validate_flavor_image_nostatus(
context, image, flavor, root_bdm, validate_numa=True,
validate_pci=False,
):
"""Validate the flavor and image.
This is called from the API service to ensure that the flavor
@ -651,7 +653,7 @@ class API(base.Base):
:param context: A context.RequestContext
:param image: a dict representation of the image including properties
:param instance_type: Flavor object
:param flavor: Flavor object
:param root_bdm: BlockDeviceMapping for root disk. Will be None for
the resize case.
:param validate_numa: Flag to indicate whether or not to validate
@ -672,7 +674,7 @@ class API(base.Base):
raise exception.InvalidImageConfigDrive(
config_drive=config_drive_option)
if instance_type['memory_mb'] < int(image.get('min_ram') or 0):
if flavor['memory_mb'] < int(image.get('min_ram') or 0):
raise exception.FlavorMemoryTooSmall()
# Image min_disk is in gb, size is in bytes. For sanity, have them both
@ -728,7 +730,7 @@ class API(base.Base):
# Target disk is a local disk whose size is taken from the flavor
else:
dest_size = instance_type['root_gb'] * units.Gi
dest_size = flavor['root_gb'] * units.Gi
# NOTE(johannes): root_gb is allowed to be 0 for legacy reasons
# since libvirt interpreted the value differently than other
@ -752,7 +754,7 @@ class API(base.Base):
raise exception.BootFromVolumeRequiredForZeroDiskFlavor()
API._validate_flavor_image_numa_pci(
image, instance_type, validate_numa=validate_numa,
image, flavor, validate_numa=validate_numa,
validate_pci=validate_pci)
# TODO(huaqiang): Remove in Wallaby when there is no nova-compute node
@ -778,9 +780,9 @@ class API(base.Base):
raise exception.MixedInstanceNotSupportByComputeService()
@staticmethod
def _validate_flavor_image_numa_pci(image, instance_type,
validate_numa=True,
validate_pci=False):
def _validate_flavor_image_numa_pci(
image, flavor, validate_numa=True, validate_pci=False,
):
"""Validate the flavor and image NUMA/PCI values.
This is called from the API service to ensure that the flavor
@ -788,7 +790,7 @@ class API(base.Base):
with each other.
:param image: a dict representation of the image including properties
:param instance_type: Flavor object
:param flavor: Flavor object
:param validate_numa: Flag to indicate whether or not to validate
the NUMA-related metadata.
:param validate_pci: Flag to indicate whether or not to validate
@ -799,10 +801,10 @@ class API(base.Base):
"""
image_meta = _get_image_meta_obj(image)
API._validate_flavor_image_mem_encryption(instance_type, image_meta)
API._validate_flavor_image_mem_encryption(flavor, image_meta)
# validate PMU extra spec and image metadata
flavor_pmu = instance_type.extra_specs.get('hw:pmu')
flavor_pmu = flavor.extra_specs.get('hw:pmu')
image_pmu = image_meta.properties.get('hw_pmu')
if (flavor_pmu is not None and image_pmu is not None and
image_pmu != strutils.bool_from_string(flavor_pmu)):
@ -810,29 +812,28 @@ class API(base.Base):
# Only validate values of flavor/image so the return results of
# following 'get' functions are not used.
hardware.get_number_of_serial_ports(instance_type, image_meta)
hardware.get_realtime_cpu_constraint(instance_type, image_meta)
hardware.get_cpu_topology_constraints(instance_type, image_meta)
hardware.get_number_of_serial_ports(flavor, image_meta)
hardware.get_realtime_cpu_constraint(flavor, image_meta)
hardware.get_cpu_topology_constraints(flavor, image_meta)
if validate_numa:
hardware.numa_get_constraints(instance_type, image_meta)
hardware.numa_get_constraints(flavor, image_meta)
if validate_pci:
pci_request.get_pci_requests_from_flavor(instance_type)
pci_request.get_pci_requests_from_flavor(flavor)
@staticmethod
def _validate_flavor_image_mem_encryption(instance_type, image):
def _validate_flavor_image_mem_encryption(flavor, image):
"""Validate that the flavor and image don't make contradictory
requests regarding memory encryption.
:param instance_type: Flavor object
:param flavor: Flavor object
:param image: an ImageMeta object
:raises: nova.exception.FlavorImageConflict
"""
# This library function will raise the exception for us if
# necessary; if not, we can ignore the result returned.
hardware.get_mem_encryption_constraint(instance_type, image)
hardware.get_mem_encryption_constraint(flavor, image)
def _get_image_defined_bdms(self, instance_type, image_meta,
root_device_name):
def _get_image_defined_bdms(self, flavor, image_meta, root_device_name):
image_properties = image_meta.get('properties', {})
# Get the block device mappings defined by the image.
@ -849,14 +850,13 @@ class API(base.Base):
image_defined_bdms))
if image_mapping:
image_mapping = self._prepare_image_mapping(instance_type,
image_mapping)
image_mapping = self._prepare_image_mapping(flavor, image_mapping)
image_defined_bdms = self._merge_bdms_lists(
image_mapping, image_defined_bdms)
return image_defined_bdms
def _get_flavor_defined_bdms(self, instance_type, block_device_mapping):
def _get_flavor_defined_bdms(self, flavor, block_device_mapping):
flavor_defined_bdms = []
have_ephemeral_bdms = any(filter(
@ -864,12 +864,12 @@ class API(base.Base):
have_swap_bdms = any(filter(
block_device.new_format_is_swap, block_device_mapping))
if instance_type.get('ephemeral_gb') and not have_ephemeral_bdms:
if flavor.get('ephemeral_gb') and not have_ephemeral_bdms:
flavor_defined_bdms.append(
block_device.create_blank_bdm(instance_type['ephemeral_gb']))
if instance_type.get('swap') and not have_swap_bdms:
block_device.create_blank_bdm(flavor['ephemeral_gb']))
if flavor.get('swap') and not have_swap_bdms:
flavor_defined_bdms.append(
block_device.create_blank_bdm(instance_type['swap'], 'swap'))
block_device.create_blank_bdm(flavor['swap'], 'swap'))
return flavor_defined_bdms
@ -887,9 +887,10 @@ class API(base.Base):
[bdm for bdm in overridable_mappings
if bdm['device_name'] not in device_names])
def _check_and_transform_bdm(self, context, base_options, instance_type,
image_meta, min_count, max_count,
block_device_mapping, legacy_bdm):
def _check_and_transform_bdm(
self, context, base_options, flavor, image_meta, min_count, max_count,
block_device_mapping, legacy_bdm,
):
# NOTE (ndipanov): Assume root dev name is 'vda' if not supplied.
# It's needed for legacy conversion to work.
root_device_name = (base_options.get('root_device_name') or 'vda')
@ -906,7 +907,7 @@ class API(base.Base):
raise exception.InvalidRequest(msg)
image_defined_bdms = self._get_image_defined_bdms(
instance_type, image_meta, root_device_name)
flavor, image_meta, root_device_name)
root_in_image_bdms = (
block_device.get_root_bdm(image_defined_bdms) is not None)
@ -942,7 +943,7 @@ class API(base.Base):
raise exception.InvalidRequest(msg)
block_device_mapping += self._get_flavor_defined_bdms(
instance_type, block_device_mapping)
flavor, block_device_mapping)
return block_device_obj.block_device_make_list_from_dicts(
context, block_device_mapping)
@ -954,33 +955,30 @@ class API(base.Base):
image = self.image_api.get(context, image_href)
return image['id'], image
def _checks_for_create_and_rebuild(self, context, image_id, image,
instance_type, metadata,
files_to_inject, root_bdm,
validate_numa=True):
def _checks_for_create_and_rebuild(
self, context, image_id, image, flavor, metadata, files_to_inject,
root_bdm, validate_numa=True,
):
self._check_metadata_properties_quota(context, metadata)
self._check_injected_file_quota(context, files_to_inject)
self._detect_nonbootable_image_from_properties(image_id, image)
self._validate_flavor_image(context, image_id, image,
instance_type, root_bdm,
flavor, root_bdm,
validate_numa=validate_numa)
def _validate_and_build_base_options(self, context, instance_type,
boot_meta, image_href, image_id,
kernel_id, ramdisk_id, display_name,
display_description, key_name,
key_data, security_groups,
availability_zone, user_data,
metadata, access_ip_v4, access_ip_v6,
requested_networks, config_drive,
auto_disk_config, reservation_id,
max_count,
supports_port_resource_request):
def _validate_and_build_base_options(
self, context, flavor, boot_meta, image_href, image_id, kernel_id,
ramdisk_id, display_name, display_description, key_name,
key_data, security_groups, availability_zone, user_data, metadata,
access_ip_v4, access_ip_v6, requested_networks, config_drive,
auto_disk_config, reservation_id, max_count,
supports_port_resource_request,
):
"""Verify all the input parameters regardless of the provisioning
strategy being performed.
"""
if instance_type['disabled']:
raise exception.FlavorNotFound(flavor_id=instance_type['id'])
if flavor['disabled']:
raise exception.FlavorNotFound(flavor_id=flavor['id'])
if user_data:
try:
@ -1017,13 +1015,12 @@ class API(base.Base):
boot_meta.get('properties', {})))
image_meta = _get_image_meta_obj(boot_meta)
numa_topology = hardware.numa_get_constraints(
instance_type, image_meta)
numa_topology = hardware.numa_get_constraints(flavor, image_meta)
system_metadata = {}
pci_numa_affinity_policy = hardware.get_pci_numa_policy_constraint(
instance_type, image_meta)
flavor, image_meta)
# PCI requests come from two sources: instance flavor and
# requested_networks. The first call in below returns an
@ -1032,7 +1029,7 @@ class API(base.Base):
# object for each SR-IOV port, and append it to the list in the
# InstancePCIRequests object
pci_request_info = pci_request.get_pci_requests_from_flavor(
instance_type, affinity_policy=pci_numa_affinity_policy)
flavor, affinity_policy=pci_numa_affinity_policy)
result = self.network_api.create_resource_requests(
context, requested_networks, pci_request_info,
affinity_policy=pci_numa_affinity_policy)
@ -1054,11 +1051,11 @@ class API(base.Base):
'config_drive': config_drive,
'user_id': context.user_id,
'project_id': context.project_id,
'instance_type_id': instance_type['id'],
'memory_mb': instance_type['memory_mb'],
'vcpus': instance_type['vcpus'],
'root_gb': instance_type['root_gb'],
'ephemeral_gb': instance_type['ephemeral_gb'],
'instance_type_id': flavor['id'],
'memory_mb': flavor['memory_mb'],
'vcpus': flavor['vcpus'],
'root_gb': flavor['root_gb'],
'ephemeral_gb': flavor['ephemeral_gb'],
'display_name': display_name,
'display_description': display_description,
'user_data': user_data,
@ -1240,13 +1237,15 @@ class API(base.Base):
'instance_az': instance_az, 'volume_az': volume_az}
raise exception.MismatchVolumeAZException(reason=msg)
def _provision_instances(self, context, instance_type, min_count,
max_count, base_options, boot_meta, security_groups,
block_device_mapping, shutdown_terminate,
instance_group, check_server_group_quota, filter_properties,
key_pair, tags, trusted_certs, supports_multiattach,
network_metadata=None, requested_host=None,
requested_hypervisor_hostname=None):
def _provision_instances(
self, context, flavor, min_count,
max_count, base_options, boot_meta, security_groups,
block_device_mapping, shutdown_terminate,
instance_group, check_server_group_quota, filter_properties,
key_pair, tags, trusted_certs, supports_multiattach,
network_metadata=None, requested_host=None,
requested_hypervisor_hostname=None,
):
# NOTE(boxiang): Check whether compute nodes exist by validating
# the host and/or the hypervisor_hostname. Pass the destination
# to the scheduler with host and/or hypervisor_hostname(node).
@ -1260,9 +1259,9 @@ class API(base.Base):
destination.node = requested_hypervisor_hostname
# Check quotas
num_instances = compute_utils.check_num_instances_quota(
context, instance_type, min_count, max_count)
context, flavor, min_count, max_count)
security_groups = security_group_api.populate_security_groups(
security_groups)
security_groups)
port_resource_requests = base_options.pop('port_resource_requests')
instances_to_build = []
# We could be iterating over several instances with several BDMs per
@ -1281,20 +1280,20 @@ class API(base.Base):
# base_options to match the volume zone.
base_options['availability_zone'] = volume_az
LOG.debug("Going to run %s instances...", num_instances)
extra_specs = instance_type.extra_specs
extra_specs = flavor.extra_specs
dp_name = extra_specs.get('accel:device_profile')
dp_request_groups = []
if dp_name:
dp_request_groups = cyborg.get_device_profile_request_groups(
context, dp_name)
try:
for i in range(num_instances):
for idx in range(num_instances):
# Create a uuid for the instance so we can store the
# RequestSpec before the instance is created.
instance_uuid = uuidutils.generate_uuid()
# Store the RequestSpec that will be used for scheduling.
req_spec = objects.RequestSpec.from_components(context,
instance_uuid, boot_meta, instance_type,
instance_uuid, boot_meta, flavor,
base_options['numa_topology'],
base_options['pci_requests'], filter_properties,
instance_group, base_options['availability_zone'],
@ -1337,13 +1336,13 @@ class API(base.Base):
context, trusted_certs)
self._populate_instance_for_create(
context, instance, boot_meta, i,
security_groups, instance_type,
context, instance, boot_meta, idx,
security_groups, flavor,
num_instances, shutdown_terminate)
block_device_mapping = (
self._bdm_validate_set_size_and_instance(context,
instance, instance_type, block_device_mapping,
instance, flavor, block_device_mapping,
image_cache, volumes, supports_multiattach))
instance_tags = self._transform_tags(tags, instance.uuid)
@ -1460,7 +1459,7 @@ class API(base.Base):
return objects.InstanceGroup.get_by_uuid(context, group_hint)
def _create_instance(self, context, instance_type,
def _create_instance(self, context, flavor,
image_href, kernel_id, ramdisk_id,
min_count, max_count,
display_name, display_description,
@ -1507,14 +1506,17 @@ class API(base.Base):
self._check_auto_disk_config(image=boot_meta,
auto_disk_config=auto_disk_config)
base_options, max_net_count, key_pair, security_groups, \
network_metadata = self._validate_and_build_base_options(
context, instance_type, boot_meta, image_href, image_id,
kernel_id, ramdisk_id, display_name, display_description,
key_name, key_data, security_groups, availability_zone,
user_data, metadata, access_ip_v4, access_ip_v6,
requested_networks, config_drive, auto_disk_config,
reservation_id, max_count, supports_port_resource_request)
(
base_options, max_net_count, key_pair, security_groups,
network_metadata,
) = self._validate_and_build_base_options(
context, flavor, boot_meta, image_href, image_id,
kernel_id, ramdisk_id, display_name, display_description,
key_name, key_data, security_groups, availability_zone,
user_data, metadata, access_ip_v4, access_ip_v6,
requested_networks, config_drive, auto_disk_config,
reservation_id, max_count, supports_port_resource_request,
)
# TODO(huaqiang): Remove in Wallaby
# check nova-compute nodes have been updated to Victoria to support the
@ -1535,7 +1537,7 @@ class API(base.Base):
max_count = max_net_count
block_device_mapping = self._check_and_transform_bdm(context,
base_options, instance_type, boot_meta, min_count, max_count,
base_options, flavor, boot_meta, min_count, max_count,
block_device_mapping, legacy_bdm)
# We can't do this check earlier because we need bdms from all sources
@ -1543,7 +1545,7 @@ class API(base.Base):
# Set validate_numa=False since numa validation is already done by
# _validate_and_build_base_options().
self._checks_for_create_and_rebuild(context, image_id, boot_meta,
instance_type, metadata, injected_files,
flavor, metadata, injected_files,
block_device_mapping.root_bdm(), validate_numa=False)
instance_group = self._get_requested_instance_group(context,
@ -1552,7 +1554,7 @@ class API(base.Base):
tags = self._create_tag_list_obj(context, tags)
instances_to_build = self._provision_instances(
context, instance_type, min_count, max_count, base_options,
context, flavor, min_count, max_count, base_options,
boot_meta, security_groups, block_device_mapping,
shutdown_terminate, instance_group, check_server_group_quota,
filter_properties, key_pair, tags, trusted_certs,
@ -1611,18 +1613,18 @@ class API(base.Base):
pass
@staticmethod
def _volume_size(instance_type, bdm):
def _volume_size(flavor, bdm):
size = bdm.get('volume_size')
# NOTE (ndipanov): inherit flavor size only for swap and ephemeral
if (size is None and bdm.get('source_type') == 'blank' and
bdm.get('destination_type') == 'local'):
if bdm.get('guest_format') == 'swap':
size = instance_type.get('swap', 0)
size = flavor.get('swap', 0)
else:
size = instance_type.get('ephemeral_gb', 0)
size = flavor.get('ephemeral_gb', 0)
return size
def _prepare_image_mapping(self, instance_type, mappings):
def _prepare_image_mapping(self, flavor, mappings):
"""Extract and format blank devices from image mappings."""
prepared_mappings = []
@ -1653,7 +1655,7 @@ class API(base.Base):
'boot_index': -1})
values['volume_size'] = self._volume_size(
instance_type, values)
flavor, values)
if values['volume_size'] == 0:
continue
@ -1662,7 +1664,7 @@ class API(base.Base):
return prepared_mappings
def _bdm_validate_set_size_and_instance(self, context, instance,
instance_type,
flavor,
block_device_mapping,
image_cache, volumes,
supports_multiattach=False):
@ -1673,7 +1675,7 @@ class API(base.Base):
:param context: nova auth RequestContext
:param instance: Instance object
:param instance_type: Flavor object - used for swap and ephemeral BDMs
:param flavor: Flavor object - used for swap and ephemeral BDMs
:param block_device_mapping: BlockDeviceMappingList object
:param image_cache: dict of image dicts keyed by id which is used as a
cache in case there are multiple BDMs in the same request using
@ -1685,11 +1687,11 @@ class API(base.Base):
LOG.debug("block_device_mapping %s", list(block_device_mapping),
instance_uuid=instance.uuid)
self._validate_bdm(
context, instance, instance_type, block_device_mapping,
context, instance, flavor, block_device_mapping,
image_cache, volumes, supports_multiattach)
instance_block_device_mapping = block_device_mapping.obj_clone()
for bdm in instance_block_device_mapping:
bdm.volume_size = self._volume_size(instance_type, bdm)
bdm.volume_size = self._volume_size(flavor, bdm)
bdm.instance_uuid = instance.uuid
return instance_block_device_mapping
@ -1713,14 +1715,15 @@ class API(base.Base):
raise exception.VolumeTypeNotFound(
id_or_name=volume_type_id_or_name)
def _validate_bdm(self, context, instance, instance_type,
block_device_mappings, image_cache, volumes,
supports_multiattach=False):
def _validate_bdm(
self, context, instance, flavor, block_device_mappings, image_cache,
volumes, supports_multiattach=False,
):
"""Validate requested block device mappings.
:param context: nova auth RequestContext
:param instance: Instance object
:param instance_type: Flavor object - used for swap and ephemeral BDMs
:param flavor: Flavor object - used for swap and ephemeral BDMs
:param block_device_mappings: BlockDeviceMappingList object
:param image_cache: dict of image dicts keyed by id which is used as a
cache in case there are multiple BDMs in the same request using
@ -1824,10 +1827,10 @@ class API(base.Base):
if disk_bus and disk_bus not in fields_obj.DiskBus.ALL:
raise exception.InvalidBDMDiskBus(disk_bus=disk_bus)
ephemeral_size = sum(bdm.volume_size or instance_type['ephemeral_gb']
ephemeral_size = sum(bdm.volume_size or flavor['ephemeral_gb']
for bdm in block_device_mappings
if block_device.new_format_is_ephemeral(bdm))
if ephemeral_size > instance_type['ephemeral_gb']:
if ephemeral_size > flavor['ephemeral_gb']:
raise exception.InvalidBDMEphemeralSize()
# There should be only one swap
@ -1838,7 +1841,7 @@ class API(base.Base):
if swap_list:
swap_size = swap_list[0].volume_size or 0
if swap_size > instance_type['swap']:
if swap_size > flavor['swap']:
raise exception.InvalidBDMSwapSize()
max_local = CONF.max_local_block_devices
@ -1881,9 +1884,10 @@ class API(base.Base):
instance.display_name = new_display_name
def _populate_instance_for_create(self, context, instance, image,
index, security_groups, instance_type,
num_instances, shutdown_terminate):
def _populate_instance_for_create(
self, context, instance, image, index, security_groups, flavor,
num_instances, shutdown_terminate,
):
"""Build the beginning of a new instance."""
instance.launch_index = index
@ -1893,7 +1897,7 @@ class API(base.Base):
info_cache.instance_uuid = instance.uuid
info_cache.network_info = network_model.NetworkInfo()
instance.info_cache = info_cache
instance.flavor = instance_type
instance.flavor = flavor
instance.old_flavor = None
instance.new_flavor = None
if CONF.ephemeral_storage_encryption.enabled:
@ -1918,7 +1922,7 @@ class API(base.Base):
instance.system_metadata = utils.instance_sys_meta(instance)
system_meta = utils.get_system_metadata_from_image(
image, instance_type)
image, flavor)
# In case we couldn't find any suitable base_image
system_meta.setdefault('image_base_image_ref', instance.image_ref)
@ -1965,8 +1969,7 @@ class API(base.Base):
tag.resource_id = resource_id
return instance_tags
def _check_multiple_instances_with_neutron_ports(self,
requested_networks):
def _check_multiple_instances_with_neutron_ports(self, requested_networks):
"""Check whether multiple instances are created from port id(s)."""
for requested_net in requested_networks:
if requested_net.port_id:
@ -1984,21 +1987,23 @@ class API(base.Base):
"is specified.")
raise exception.InvalidFixedIpAndMaxCountRequest(reason=msg)
def create(self, context, instance_type,
image_href, kernel_id=None, ramdisk_id=None,
min_count=None, max_count=None,
display_name=None, display_description=None,
key_name=None, key_data=None, security_groups=None,
availability_zone=None, forced_host=None, forced_node=None,
user_data=None, metadata=None, injected_files=None,
admin_password=None, block_device_mapping=None,
access_ip_v4=None, access_ip_v6=None, requested_networks=None,
config_drive=None, auto_disk_config=None, scheduler_hints=None,
legacy_bdm=True, shutdown_terminate=False,
check_server_group_quota=False, tags=None,
supports_multiattach=False, trusted_certs=None,
supports_port_resource_request=False,
requested_host=None, requested_hypervisor_hostname=None):
def create(
self, context, flavor,
image_href, kernel_id=None, ramdisk_id=None,
min_count=None, max_count=None,
display_name=None, display_description=None,
key_name=None, key_data=None, security_groups=None,
availability_zone=None, forced_host=None, forced_node=None,
user_data=None, metadata=None, injected_files=None,
admin_password=None, block_device_mapping=None,
access_ip_v4=None, access_ip_v6=None, requested_networks=None,
config_drive=None, auto_disk_config=None, scheduler_hints=None,
legacy_bdm=True, shutdown_terminate=False,
check_server_group_quota=False, tags=None,
supports_multiattach=False, trusted_certs=None,
supports_port_resource_request=False,
requested_host=None, requested_hypervisor_hostname=None,
):
"""Provision instances, sending instance information to the
scheduler. The scheduler will determine where the instance(s)
go and will handle creating the DB entries.
@ -2021,10 +2026,10 @@ class API(base.Base):
raise exception.InvalidRequest(msg)
filter_properties = scheduler_utils.build_filter_properties(
scheduler_hints, forced_host, forced_node, instance_type)
scheduler_hints, forced_host, forced_node, flavor)
return self._create_instance(
context, instance_type,
context, flavor,
image_href, kernel_id, ramdisk_id,
min_count, max_count,
display_name, display_description,
@ -3972,14 +3977,14 @@ class API(base.Base):
self._check_auto_disk_config(
instance, auto_disk_config=auto_disk_config)
current_instance_type = instance.get_flavor()
current_flavor = instance.get_flavor()
# NOTE(aarents): Ensure image_base_image_ref is present as it will be
# needed during finish_resize/cross_cell_resize. Instances upgraded
# from an older nova release may not have this property because of
# a rebuild bug Bug/1893618.
instance.system_metadata.update(
{'image_base_image_ref': instance.image_ref}
{'image_base_image_ref': instance.image_ref}
)
# If flavor_id is not provided, only migrate the instance.
@ -3987,52 +3992,51 @@ class API(base.Base):
if not flavor_id:
LOG.debug("flavor_id is None. Assuming migration.",
instance=instance)
new_instance_type = current_instance_type
new_flavor = current_flavor
else:
new_instance_type = flavors.get_flavor_by_flavor_id(
flavor_id, read_deleted="no")
new_flavor = flavors.get_flavor_by_flavor_id(
flavor_id, read_deleted="no")
# NOTE(wenping): We use this instead of the 'block_accelerator'
# decorator since the operation can differ depending on args,
# and for resize we have two flavors to worry about, we should
# reject resize with new flavor with accelerator.
if new_instance_type.extra_specs.get('accel:device_profile'):
if new_flavor.extra_specs.get('accel:device_profile'):
raise exception.ForbiddenWithAccelerators()
# Check to see if we're resizing to a zero-disk flavor which is
# only supported with volume-backed servers.
if (new_instance_type.get('root_gb') == 0 and
current_instance_type.get('root_gb') != 0):
if (new_flavor.get('root_gb') == 0 and
current_flavor.get('root_gb') != 0):
volume_backed = compute_utils.is_volume_backed_instance(
context, instance)
if not volume_backed:
reason = _('Resize to zero disk flavor is not allowed.')
raise exception.CannotResizeDisk(reason=reason)
current_instance_type_name = current_instance_type['name']
new_instance_type_name = new_instance_type['name']
LOG.debug("Old instance type %(current_instance_type_name)s, "
"new instance type %(new_instance_type_name)s",
{'current_instance_type_name': current_instance_type_name,
'new_instance_type_name': new_instance_type_name},
current_flavor_name = current_flavor['name']
new_flavor_name = new_flavor['name']
LOG.debug("Old instance type %(current_flavor_name)s, "
"new instance type %(new_flavor_name)s",
{'current_flavor_name': current_flavor_name,
'new_flavor_name': new_flavor_name},
instance=instance)
same_instance_type = (current_instance_type['id'] ==
new_instance_type['id'])
same_flavor = current_flavor['id'] == new_flavor['id']
# NOTE(sirp): We don't want to force a customer to change their flavor
# when Ops is migrating off of a failed host.
if not same_instance_type and new_instance_type.get('disabled'):
if not same_flavor and new_flavor.get('disabled'):
raise exception.FlavorNotFound(flavor_id=flavor_id)
if same_instance_type and flavor_id:
if same_flavor and flavor_id:
raise exception.CannotResizeToSameFlavor()
# ensure there is sufficient headroom for upsizes
if flavor_id:
self._check_quota_for_upsize(context, instance,
current_instance_type,
new_instance_type)
current_flavor,
new_flavor)
if not same_instance_type:
if not same_flavor:
image = utils.get_image_from_system_metadata(
instance.system_metadata)
# Figure out if the instance is volume-backed but only if we didn't
@ -4047,14 +4051,14 @@ class API(base.Base):
# resize case.
if volume_backed:
self._validate_flavor_image_numa_pci(
image, new_instance_type, validate_pci=True)
image, new_flavor, validate_pci=True)
else:
self._validate_flavor_image_nostatus(
context, image, new_instance_type, root_bdm=None,
context, image, new_flavor, root_bdm=None,
validate_pci=True)
filter_properties = {'ignore_hosts': []}
if not self._allow_resize_to_same_host(same_instance_type, instance):
if not self._allow_resize_to_same_host(same_flavor, instance):
filter_properties['ignore_hosts'].append(instance.host)
request_spec = objects.RequestSpec.get_by_instance_uuid(
@ -4062,9 +4066,9 @@ class API(base.Base):
request_spec.ignore_hosts = filter_properties['ignore_hosts']
# don't recalculate the NUMA topology unless the flavor has changed
if not same_instance_type:
if not same_flavor:
request_spec.numa_topology = hardware.numa_get_constraints(
new_instance_type, instance.image_meta)
new_flavor, instance.image_meta)
# TODO(huaqiang): Remove in Wallaby
# check nova-compute nodes have been updated to Victoria to resize
# instance to a new mixed instance from a dedicated or shared
@ -4107,9 +4111,10 @@ class API(base.Base):
# Asynchronously RPC cast to conductor so the response is not blocked
# during scheduling. If something fails the user can find out via
# instance actions.
self.compute_task_api.resize_instance(context, instance,
self.compute_task_api.resize_instance(
context, instance,
scheduler_hint=scheduler_hint,
flavor=new_instance_type,
flavor=new_flavor,
clean_shutdown=clean_shutdown,
request_spec=request_spec,
do_cast=True)

50
nova/tests/unit/compute/test_api.py

@ -215,7 +215,7 @@ class _ComputeAPIUnitTestMixIn(object):
get_image.return_value = (None, {})
check_requested_networks.return_value = 1
instance_type = self._create_flavor()
flavor = self._create_flavor()
port = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'
address = '10.0.0.1'
@ -226,7 +226,7 @@ class _ComputeAPIUnitTestMixIn(object):
with mock.patch.object(self.compute_api.network_api,
'create_resource_requests',
return_value=(None, [])):
self.compute_api.create(self.context, instance_type, 'image_id',
self.compute_api.create(self.context, flavor, 'image_id',
requested_networks=requested_networks,
max_count=None)
@ -239,7 +239,7 @@ class _ComputeAPIUnitTestMixIn(object):
mock_limit_check, mock_count):
image_href = "image_href"
image_id = 0
instance_type = self._create_flavor()
flavor = self._create_flavor()
quotas = {'instances': 1, 'cores': 1, 'ram': 1}
quota_exception = exception.OverQuota(quotas=quotas,
@ -259,7 +259,7 @@ class _ComputeAPIUnitTestMixIn(object):
return_value=(image_id, {})) as mock_get_image:
for min_count, message in [(20, '20-40'), (40, '40')]:
try:
self.compute_api.create(self.context, instance_type,
self.compute_api.create(self.context, flavor,
"image_href", min_count=min_count,
max_count=40)
except exception.TooManyInstances as e:
@ -277,7 +277,7 @@ class _ComputeAPIUnitTestMixIn(object):
# creating a volume-backed instance
self.assertRaises(exception.CertificateValidationFailed,
self.compute_api.create, self.context,
instance_type=self._create_flavor(), image_href=None,
flavor=self._create_flavor(), image_href=None,
trusted_certs=['test-cert-1', 'test-cert-2'])
@mock.patch('nova.objects.Quotas.limit_check')
@ -290,7 +290,7 @@ class _ComputeAPIUnitTestMixIn(object):
# creating a volume-backed instance
self.assertRaises(exception.CertificateValidationFailed,
self.compute_api.create, self.context,
instance_type=self._create_flavor(),
flavor=self._create_flavor(),
image_href=None)
def _test_create_max_net_count(self, max_net_count, min_count, max_count):
@ -4628,7 +4628,7 @@ class _ComputeAPIUnitTestMixIn(object):
side_effect=exception.CinderConnectionFailed(reason='error'))
def test_validate_bdm_with_cinder_down(self, mock_get_snapshot):
instance = self._create_instance_obj()
instance_type = self._create_flavor()
flavor = self._create_flavor()
bdms = [objects.BlockDeviceMapping(
**fake_block_device.FakeDbBlockDeviceDict(
{
@ -4643,7 +4643,7 @@ class _ComputeAPIUnitTestMixIn(object):
self.assertRaises(exception.CinderConnectionFailed,
self.compute_api._validate_bdm,
self.context,
instance, instance_type, bdms, image_cache, volumes)
instance, flavor, bdms, image_cache, volumes)
@mock.patch.object(cinder.API, 'attachment_create',
side_effect=exception.InvalidInput(reason='error'))
@ -4653,7 +4653,7 @@ class _ComputeAPIUnitTestMixIn(object):
# 'available' results in _validate_bdm re-raising InvalidVolume.
instance = self._create_instance_obj()
del instance.id
instance_type = self._create_flavor()
flavor = self._create_flavor()
volume_id = 'e856840e-9f5b-4894-8bde-58c6e29ac1e8'
volume_info = {'status': 'error',
'attach_status': 'detached',
@ -4671,7 +4671,7 @@ class _ComputeAPIUnitTestMixIn(object):
self.assertRaises(exception.InvalidVolume,
self.compute_api._validate_bdm,
self.context,
instance, instance_type, bdms, {},
instance, flavor, bdms, {},
{volume_id: volume_info})
mock_attach_create.assert_called_once_with(
@ -4694,7 +4694,7 @@ class _ComputeAPIUnitTestMixIn(object):
"""Test _check_requested_volume_type method is used.
"""
instance = self._create_instance_obj()
instance_type = self._create_flavor()
flavor = self._create_flavor()
volume_type = 'fake_lvm_1'
volume_types = [{'id': 'fake_volume_type_id_1', 'name': 'fake_lvm_1'},
@ -4733,7 +4733,7 @@ class _ComputeAPIUnitTestMixIn(object):
image_cache = volumes = {}
self.compute_api._validate_bdm(self.context, instance,
instance_type, bdms, image_cache,
flavor, bdms, image_cache,
volumes)
get_all_vol_types.assert_called_once_with(self.context)
@ -4951,7 +4951,7 @@ class _ComputeAPIUnitTestMixIn(object):
@mock.patch('nova.objects.Instance')
@mock.patch('nova.objects.InstanceMapping.create')
def _test_provision_instances_with_accels(self,
instance_type, dp_request_groups, prev_request_groups,
flavor, dp_request_groups, prev_request_groups,
mock_im, mock_instance, mock_br, mock_rs, mock_get_dp):
@mock.patch.object(self.compute_api, '_get_volumes_for_bdms')
@ -4968,7 +4968,7 @@ class _ComputeAPIUnitTestMixIn(object):
def do_test(mock_bdm_v, mock_sg, mock_cniq, mock_get_vols):
mock_cniq.return_value = 1
self.compute_api._provision_instances(self.context,
instance_type,
flavor,
1, 1, mock.MagicMock(),
{}, None,
None, None, None, {}, None,
@ -4988,7 +4988,7 @@ class _ComputeAPIUnitTestMixIn(object):
# should be obtained, and added to reqspec's requested_resources.
dp_name = 'mydp'
extra_specs = {'extra_specs': {'accel:device_profile': dp_name}}
instance_type = self._create_flavor(**extra_specs)
flavor = self._create_flavor(**extra_specs)
prev_groups = [objects.RequestGroup(requester_id='prev0'),
objects.RequestGroup(requester_id='prev1')]
@ -4996,7 +4996,7 @@ class _ComputeAPIUnitTestMixIn(object):
objects.RequestGroup(requester_id='deviceprofile3')]
mock_get_dp, fake_rs = self._test_provision_instances_with_accels(
instance_type, dp_groups, prev_groups)
flavor, dp_groups, prev_groups)
mock_get_dp.assert_called_once_with(self.context, dp_name)
self.assertEqual(prev_groups + dp_groups, fake_rs.requested_resources)
@ -5004,11 +5004,11 @@ class _ComputeAPIUnitTestMixIn(object):
# If extra specs has no accel spec, no attempt should be made to
# get device profile's request_groups, and reqspec.requested_resources
# should be left unchanged.
instance_type = self._create_flavor()
flavor = self._create_flavor()
prev_groups = [objects.RequestGroup(requester_id='prev0'),
objects.RequestGroup(requester_id='prev1')]
mock_get_dp, fake_rs = self._test_provision_instances_with_accels(
instance_type, [], prev_groups)
flavor, [], prev_groups)
mock_get_dp.assert_not_called()
self.assertEqual(prev_groups, fake_rs.requested_resources)
@ -5654,7 +5654,7 @@ class _ComputeAPIUnitTestMixIn(object):
self._test_detach_interface_invalid_state(state)
def _test_check_and_transform_bdm(self, block_device_mapping):
instance_type = self._create_flavor()
flavor = self._create_flavor()
base_options = {'uuid': uuids.bdm_instance,
'image_ref': 'fake_image_ref',
'metadata': {}}
@ -5667,7 +5667,7 @@ class _ComputeAPIUnitTestMixIn(object):
block_device_mapping = block_device_mapping
self.assertRaises(exception.InvalidRequest,
self.compute_api._check_and_transform_bdm,
self.context, base_options, instance_type,
self.context, base_options, flavor,
image_meta, 1, 1, block_device_mapping, legacy_bdm)
def test_check_and_transform_bdm_source_volume(self):
@ -5698,8 +5698,8 @@ class _ComputeAPIUnitTestMixIn(object):
swap_size = 42
ephemeral_size = 24
instance = self._create_instance_obj()
instance_type = self._create_flavor(swap=swap_size,
ephemeral_gb=ephemeral_size)
flavor = self._create_flavor(
swap=swap_size, ephemeral_gb=ephemeral_size)
block_device_mapping = [
{'device_name': '/dev/sda1',
'source_type': 'snapshot', 'destination_type': 'volume',
@ -5722,7 +5722,7 @@ class _ComputeAPIUnitTestMixIn(object):
with mock.patch.object(self.compute_api, '_validate_bdm'):
image_cache = volumes = {}
bdms = self.compute_api._bdm_validate_set_size_and_instance(
self.context, instance, instance_type, block_device_mapping,
self.context, instance, flavor, block_device_mapping,
image_cache, volumes)
expected = [{'device_name': '/dev/sda1',
@ -7083,7 +7083,7 @@ class ComputeAPIUnitTestCase(_ComputeAPIUnitTestMixIn, test.NoDBTestCase):
requested Neutron security group and that will be returned from
_validate_and_build_base_options
"""
instance_type = objects.Flavor(**test_flavor.fake_flavor)
flavor = objects.Flavor(**test_flavor.fake_flavor)
boot_meta = metadata = {}
kernel_id = ramdisk_id = key_name = key_data = user_data = \
access_ip_v4 = access_ip_v6 = config_drive = \
@ -7102,7 +7102,7 @@ class ComputeAPIUnitTestCase(_ComputeAPIUnitTestMixIn, test.NoDBTestCase):
base_options, max_network_count, key_pair, security_groups, \
network_metadata = (
self.compute_api._validate_and_build_base_options(
self.context, instance_type, boot_meta, uuids.image_href,
self.context, flavor, boot_meta, uuids.image_href,
mock.sentinel.image_id, kernel_id, ramdisk_id,
'fake-display-name', 'fake-description', key_name,
key_data, requested_secgroups, 'fake-az', user_data,

69
nova/tests/unit/compute/test_compute.py

@ -1621,7 +1621,7 @@ class ComputeTestCase(BaseTestCase,
self.assertRaises(exception.MultiplePortsNotApplicable,
self.compute_api.create,
self.context,
instance_type=self.default_flavor,
flavor=self.default_flavor,
image_href=None,
max_count=2,
requested_networks=requested_networks)
@ -8612,11 +8612,12 @@ class ComputeAPITestCase(BaseTestCase):
def test_create_instance_sets_system_metadata(self):
# Make sure image properties are copied into system metadata.
with mock.patch.object(self.compute_api.compute_task_api,
'schedule_and_build_instances') as mock_sbi:
(ref, resv_id) = self.compute_api.create(
with mock.patch.object(
self.compute_api.compute_task_api, 'schedule_and_build_instances',
) as mock_sbi:
ref, resv_id = self.compute_api.create(
self.context,
instance_type=self.default_flavor,
flavor=self.default_flavor,
image_href='f5000000-0000-0000-0000-000000000000')
build_call = mock_sbi.call_args_list[0]
@ -8630,11 +8631,12 @@ class ComputeAPITestCase(BaseTestCase):
self.assertEqual(value, instance.system_metadata[key])
def test_create_saves_flavor(self):
with mock.patch.object(self.compute_api.compute_task_api,
'schedule_and_build_instances') as mock_sbi:
(ref, resv_id) = self.compute_api.create(
with mock.patch.object(
self.compute_api.compute_task_api, 'schedule_and_build_instances',
) as mock_sbi:
ref, resv_id = self.compute_api.create(
self.context,
instance_type=self.default_flavor,
flavor=self.default_flavor,
image_href=uuids.image_href_id)
build_call = mock_sbi.call_args_list[0]
@ -8654,7 +8656,7 @@ class ComputeAPITestCase(BaseTestCase):
) as (mock_sbi, mock_secgroups):
self.compute_api.create(
self.context,
instance_type=self.default_flavor,
flavor=self.default_flavor,
image_href=uuids.image_href_id,
security_groups=['testgroup'])
@ -8671,12 +8673,13 @@ class ComputeAPITestCase(BaseTestCase):
'nova.network.security_group_api.validate_name',
side_effect=exception.SecurityGroupNotFound('foo'),
) as mock_secgroups:
self.assertRaises(exception.SecurityGroupNotFound,
self.compute_api.create,
self.context,
instance_type=self.default_flavor,
image_href=None,
security_groups=['invalid_sec_group'])
self.assertRaises(
exception.SecurityGroupNotFound,
self.compute_api.create,
self.context,
flavor=self.default_flavor,
image_href=None,
security_groups=['invalid_sec_group'])
self.assertEqual(pre_build_len,
len(db.instance_get_all(self.context)))
@ -8697,7 +8700,7 @@ class ComputeAPITestCase(BaseTestCase):
) as (mock_sbi, _mock_create_resreqs):
self.compute_api.create(
self.context,
instance_type=self.default_flavor,
flavor=self.default_flavor,
image_href=uuids.image_href_id,
requested_networks=requested_networks)
@ -8737,14 +8740,14 @@ class ComputeAPITestCase(BaseTestCase):
instance = objects.Instance()
instance.update(base_options)
instance = self.compute_api._populate_instance_for_create(
self.context,
instance,
self.fake_image,
1,
security_groups=objects.SecurityGroupList(),
instance_type=self.tiny_flavor,
num_instances=num_instances,
shutdown_terminate=False)
self.context,
instance,
self.fake_image,
1,
security_groups=objects.SecurityGroupList(),
flavor=self.tiny_flavor,
num_instances=num_instances,
shutdown_terminate=False)
self.assertEqual(str(base_options['image_ref']),
instance['system_metadata']['image_base_image_ref'])
self.assertEqual(vm_states.BUILDING, instance['vm_state'])
@ -8772,14 +8775,14 @@ class ComputeAPITestCase(BaseTestCase):
self.compute_api.key_manager = key_manager.API()
index = 1
instance = self.compute_api._populate_instance_for_create(
self.context,
instance,
self.fake_image,
index,
security_groups=objects.SecurityGroupList(),
instance_type=self.tiny_flavor,
num_instances=num_instances,
shutdown_terminate=False)
self.context,
instance,
self.fake_image,
index,
security_groups=objects.SecurityGroupList(),
flavor=self.tiny_flavor,
num_instances=num_instances,
shutdown_terminate=False)
self.assertIsNotNone(instance.ephemeral_key_uuid)
def test_default_hostname_generator(self):

35
nova/tests/unit/test_quota.py

@ -64,7 +64,7 @@ class QuotaIntegrationTestCase(test.TestCase):
self.context = context.RequestContext(self.user_id,
self.project_id,
is_admin=True)
self.inst_type = objects.Flavor.get_by_name(self.context, 'm1.small')
self.flavor = objects.Flavor.get_by_name(self.context, 'm1.small')
self.useFixture(nova_fixtures.GlanceFixture(self))
@ -106,9 +106,9 @@ class QuotaIntegrationTestCase(test.TestCase):
self._create_instance()
image_uuid = 'cedef40a-ed67-4d10-800e-17455edce175'
try:
self.compute_api.create(self.context, min_count=1, max_count=1,
instance_type=self.inst_type,
image_href=image_uuid)
self.compute_api.create(
self.context, min_count=1, max_count=1,
flavor=self.flavor, image_href=image_uuid)
except exception.QuotaError as e:
expected_kwargs = {'code': 413,
'req': '1, 1',
@ -123,9 +123,9 @@ class QuotaIntegrationTestCase(test.TestCase):
self._create_instance()
image_uuid = 'cedef40a-ed67-4d10-800e-17455edce175'
try:
self.compute_api.create(self.context, min_count=1, max_count=1,
instance_type=self.inst_type,
image_href=image_uuid)
self.compute_api.create(
self.context, min_count=1, max_count=1, flavor=self.flavor,
image_href=image_uuid)
except exception.QuotaError as e:
expected_kwargs = {'code': 413,
'req': '1',
@ -149,27 +149,22 @@ class QuotaIntegrationTestCase(test.TestCase):
for i in range(CONF.quota.metadata_items + 1):
metadata['key%s' % i] = 'value%s' % i
image_uuid = 'cedef40a-ed67-4d10-800e-17455edce175'
self.assertRaises(exception.QuotaError, self.compute_api.create,
self.context,
min_count=1,
max_count=1,
instance_type=self.inst_type,
image_href=image_uuid,
metadata=metadata)
self.assertRaises(
exception.QuotaError, self.compute_api.create,
self.context, min_count=1, max_count=1, flavor=self.flavor,
image_href=image_uuid, metadata=metadata)
def _create_with_injected_files(self, files):
api = self.compute_api
image_uuid = 'cedef40a-ed67-4d10-800e-17455edce175'
api.create(self.context, min_count=1, max_count=1,
instance_type=self.inst_type, image_href=image_uuid,
injected_files=files)
api.create(
self.context, min_count=1, max_count=1, flavor=self.flavor,
image_href=image_uuid, injected_files=files)
def test_no_injected_files(self):
api = self.compute_api
image_uuid = 'cedef40a-ed67-4d10-800e-17455edce175'
api.create(self.context,
instance_type=self.inst_type,
image_href=image_uuid)
api.create(self.context, flavor=self.flavor, image_href=image_uuid)
def test_max_injected_files(self):
files = []

Loading…
Cancel
Save