summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api-guide/source/port_with_resource_request.rst12
-rw-r--r--nova/api/openstack/compute/servers.py10
-rw-r--r--nova/compute/manager.py13
-rw-r--r--nova/tests/functional/integrated_helpers.py4
-rw-r--r--nova/tests/functional/test_servers.py160
-rw-r--r--nova/tests/unit/compute/test_compute_mgr.py10
-rw-r--r--releasenotes/notes/support-cold-migrating-neutron-ports-with-resource-request-6d23be654a253625.yaml4
7 files changed, 123 insertions, 90 deletions
diff --git a/api-guide/source/port_with_resource_request.rst b/api-guide/source/port_with_resource_request.rst
index 3ab019cea9..7fe2db81cd 100644
--- a/api-guide/source/port_with_resource_request.rst
+++ b/api-guide/source/port_with_resource_request.rst
@@ -25,7 +25,11 @@ version of nova:
shelve offload) servers with ports having resource request is not yet
supported.
-As of 20.0.0 (Train), nova supports cold migrating servers with neutron ports
-having resource requests if both the source and destination compute services
-are upgraded to 20.0.0 (Train) and the ``[upgrade_levels]/compute``
-configuration does not prevent the computes from using the latest RPC version.
+As of 20.0.0 (Train), nova supports cold migrating and resizing servers with
+neutron ports having resource requests if both the source and destination
+compute services are upgraded to 20.0.0 (Train) and the
+``[upgrade_levels]/compute`` configuration does not prevent the computes from
+using the latest RPC version.
+
+See :nova-doc:`the admin guide <admin/port_with_resource_request.html>` for
+administrative details.
diff --git a/nova/api/openstack/compute/servers.py b/nova/api/openstack/compute/servers.py
index e44e1c02a2..48b89e73df 100644
--- a/nova/api/openstack/compute/servers.py
+++ b/nova/api/openstack/compute/servers.py
@@ -940,18 +940,8 @@ class ServersController(wsgi.Controller):
target={'user_id': instance.user_id,
'project_id': instance.project_id})
- # We could potentially move this check to conductor and avoid the
- # extra API call to neutron when we support move operations with ports
- # having resource requests.
if common.instance_has_port_with_resource_request(
context, instance_id, self.network_api):
- if not common.supports_port_resource_request_during_move(req):
- msg = _("The resize action on a server with ports having "
- "resource requests, like a port with a QoS minimum "
- "bandwidth policy, is not supported with this "
- "microversion")
- raise exc.HTTPBadRequest(explanation=msg)
-
# TODO(gibi): Remove when nova only supports compute newer than
# Train
source_service = objects.Service.get_by_host_and_binary(
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 4f8930c5fa..6290cd6e0c 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -4284,7 +4284,8 @@ class ComputeManager(manager.Manager):
instance.save()
try:
- self._revert_allocation(context, instance, migration)
+ source_allocations = self._revert_allocation(
+ context, instance, migration)
except exception.AllocationMoveFailed:
LOG.error('Reverting allocation in placement for migration '
'%(migration_uuid)s failed. The instance '
@@ -4295,16 +4296,12 @@ class ComputeManager(manager.Manager):
raise
if request_spec:
- # TODO(gibi): the _revert_allocation() call above already
- # fetched the original allocation of the instance so we could
- # avoid this second call to placement
# NOTE(gibi): We need to re-calculate the resource provider -
# port mapping as we have to have the neutron ports allocate
# from the source compute after revert.
- allocs = self.reportclient.get_allocations_for_consumer(
- context, instance.uuid)
scheduler_utils.fill_provider_mapping_based_on_allocation(
- context, self.reportclient, request_spec, allocs)
+ context, self.reportclient, request_spec,
+ source_allocations)
provider_mappings = self._get_request_group_mapping(
request_spec)
else:
@@ -4391,7 +4388,7 @@ class ComputeManager(manager.Manager):
# TODO(cdent): Should we be doing anything with return values here?
self.reportclient.move_allocations(context, migration.uuid,
instance.uuid)
- return True
+ return orig_alloc
def _prep_resize(self, context, image, instance, instance_type,
filter_properties, node, migration, request_spec,
diff --git a/nova/tests/functional/integrated_helpers.py b/nova/tests/functional/integrated_helpers.py
index 5c8d657d6c..e00c3970e1 100644
--- a/nova/tests/functional/integrated_helpers.py
+++ b/nova/tests/functional/integrated_helpers.py
@@ -433,10 +433,10 @@ class ProviderUsageBaseTestCase(test.TestCase, InstanceHelperMixin):
placement = self.useFixture(func_fixtures.PlacementFixture())
self.placement_api = placement.api
- api_fixture = self.useFixture(nova_fixtures.OSAPIFixture(
+ self.api_fixture = self.useFixture(nova_fixtures.OSAPIFixture(
api_version='v2.1'))
- self.admin_api = api_fixture.admin_api
+ self.admin_api = self.api_fixture.admin_api
self.admin_api.microversion = self.microversion
self.api = self.admin_api
diff --git a/nova/tests/functional/test_servers.py b/nova/tests/functional/test_servers.py
index e70725ad89..756e21d200 100644
--- a/nova/tests/functional/test_servers.py
+++ b/nova/tests/functional/test_servers.py
@@ -5795,31 +5795,6 @@ class UnsupportedPortResourceRequestBasedSchedulingTest(
"until microversion 2.72.",
six.text_type(ex))
- def test_resize_server_with_port_resource_request_old_microversion(self):
- server = self._create_server(
- flavor=self.flavor,
- networks=[{'port': self.neutron.port_1['id']}])
- self._wait_for_state_change(self.admin_api, server, 'ACTIVE')
-
- # We need to simulate that the above server has a port that has
- # resource request; we cannot boot with such a port but legacy servers
- # can exist with such a port.
- self._add_resource_request_to_a_bound_port(self.neutron.port_1['id'])
-
- resize_req = {
- 'resize': {
- 'flavorRef': self.flavor['id']
- }
- }
- ex = self.assertRaises(
- client.OpenStackApiException,
- self.api.post_server_action, server['id'], resize_req)
-
- self.assertEqual(400, ex.response.status_code)
- self.assertIn(
- 'The resize action on a server with ports having resource '
- 'requests', six.text_type(ex))
-
def test_live_migrate_server_with_port_resource_request_old_microversion(
self):
server = self._create_server(
@@ -6348,9 +6323,22 @@ class ServerMoveWithPortResourceRequestTest(
self.compute2_service_id = self.admin_api.get_services(
host='host2', binary='nova-compute')[0]['id']
+ # create a bigger flavor to use in resize test
+ self.flavor_with_group_policy_bigger = self.admin_api.post_flavor(
+ {'flavor': {
+ 'ram': self.flavor_with_group_policy['ram'],
+ 'vcpus': self.flavor_with_group_policy['vcpus'],
+ 'name': self.flavor_with_group_policy['name'] + '+',
+ 'disk': self.flavor_with_group_policy['disk'] + 1,
+ }})
+ self.admin_api.post_extra_spec(
+ self.flavor_with_group_policy_bigger['id'],
+ {'extra_specs': {'group_policy': 'isolate'}})
+
def _check_allocation(
self, server, compute_rp_uuid, non_qos_port, qos_port,
- qos_sriov_port, migration_uuid=None, source_compute_rp_uuid=None):
+ qos_sriov_port, flavor, migration_uuid=None,
+ source_compute_rp_uuid=None, new_flavor=None):
updated_non_qos_port = self.neutron.show_port(
non_qos_port['id'])['port']
@@ -6361,13 +6349,18 @@ class ServerMoveWithPortResourceRequestTest(
allocations = self.placement_api.get(
'/allocations/%s' % server['id']).body['allocations']
+ # if there is new_flavor then we either have an in progress resize or
+ # a confirmed resize. In both cases the instance allocation should be
+ # according to the new_flavor
+ current_flavor = (new_flavor if new_flavor else flavor)
+
# We expect one set of allocations for the compute resources on the
# compute rp and two sets for the networking resources one on the ovs
# bridge rp due to the qos_port resource request and one one the
# sriov pf2 due to qos_sriov_port resource request
self.assertEqual(3, len(allocations))
self.assertComputeAllocationMatchesFlavor(
- allocations, compute_rp_uuid, self.flavor_with_group_policy)
+ allocations, compute_rp_uuid, current_flavor)
ovs_allocations = allocations[
self.ovs_bridge_rp_per_host[compute_rp_uuid]]['resources']
self.assertPortMatchesAllocation(qos_port, ovs_allocations)
@@ -6399,8 +6392,7 @@ class ServerMoveWithPortResourceRequestTest(
# the sriov pf2 due to qos_sriov_port resource request
self.assertEqual(3, len(migration_allocations))
self.assertComputeAllocationMatchesFlavor(
- migration_allocations, source_compute_rp_uuid,
- self.flavor_with_group_policy)
+ migration_allocations, source_compute_rp_uuid, flavor)
ovs_allocations = migration_allocations[
self.ovs_bridge_rp_per_host[
source_compute_rp_uuid]]['resources']
@@ -6445,7 +6437,7 @@ class ServerMoveWithPortResourceRequestTest(
# check that the server allocates from the current host properly
self._check_allocation(
server, self.compute1_rp_uuid, non_qos_normal_port,
- qos_normal_port, qos_sriov_port)
+ qos_normal_port, qos_sriov_port, self.flavor_with_group_policy)
orig_get_service = nova.objects.Service.get_by_host_and_binary
@@ -6471,7 +6463,7 @@ class ServerMoveWithPortResourceRequestTest(
# check that the server still allocates from the original host
self._check_allocation(
server, self.compute1_rp_uuid, non_qos_normal_port,
- qos_normal_port, qos_sriov_port)
+ qos_normal_port, qos_sriov_port, self.flavor_with_group_policy)
# but the migration allocation is gone
migration_uuid = self.get_migration_uuid_for_instance(server['id'])
@@ -6501,7 +6493,7 @@ class ServerMoveWithPortResourceRequestTest(
# check that the server allocates from the current host properly
self._check_allocation(
server, self.compute1_rp_uuid, non_qos_normal_port,
- qos_normal_port, qos_sriov_port)
+ qos_normal_port, qos_sriov_port, self.flavor_with_group_policy)
orig_get_service = nova.objects.Service.get_by_host_and_binary
@@ -6530,14 +6522,14 @@ class ServerMoveWithPortResourceRequestTest(
# check that server allocates from host3
self._check_allocation(
server, compute3_rp_uuid, non_qos_normal_port, qos_normal_port,
- qos_sriov_port, migration_uuid,
+ qos_sriov_port, self.flavor_with_group_policy, migration_uuid,
source_compute_rp_uuid=self.compute1_rp_uuid)
self._confirm_resize(server)
# check that allocation is still OK
self._check_allocation(
server, compute3_rp_uuid, non_qos_normal_port,
- qos_normal_port, qos_sriov_port)
+ qos_normal_port, qos_sriov_port, self.flavor_with_group_policy)
# but the migration allocation is gone
migration_allocations = self.placement_api.get(
'/allocations/%s' % migration_uuid).body['allocations']
@@ -6546,7 +6538,7 @@ class ServerMoveWithPortResourceRequestTest(
self._delete_server_and_check_allocations(
qos_normal_port, qos_sriov_port, server)
- def test_migrate_server_with_qos_ports(self):
+ def _test_resize_or_migrate_server_with_qos_ports(self, new_flavor=None):
non_qos_normal_port = self.neutron.port_1
qos_normal_port = self.neutron.port_with_resource_request
qos_sriov_port = self.neutron.port_with_sriov_resource_request
@@ -6557,9 +6549,14 @@ class ServerMoveWithPortResourceRequestTest(
# check that the server allocates from the current host properly
self._check_allocation(
server, self.compute1_rp_uuid, non_qos_normal_port,
- qos_normal_port, qos_sriov_port)
+ qos_normal_port, qos_sriov_port, self.flavor_with_group_policy)
+
+ if new_flavor:
+ self.api_fixture.api.post_server_action(
+ server['id'], {'resize': {"flavorRef": new_flavor['id']}})
+ else:
+ self.api.post_server_action(server['id'], {'migrate': None})
- self.api.post_server_action(server['id'], {'migrate': None})
self._wait_for_state_change(self.api, server, 'VERIFY_RESIZE')
migration_uuid = self.get_migration_uuid_for_instance(server['id'])
@@ -6567,15 +6564,17 @@ class ServerMoveWithPortResourceRequestTest(
# check that server allocates from the new host properly
self._check_allocation(
server, self.compute2_rp_uuid, non_qos_normal_port,
- qos_normal_port, qos_sriov_port, migration_uuid,
- source_compute_rp_uuid=self.compute1_rp_uuid)
+ qos_normal_port, qos_sriov_port, self.flavor_with_group_policy,
+ migration_uuid, source_compute_rp_uuid=self.compute1_rp_uuid,
+ new_flavor=new_flavor)
self._confirm_resize(server)
# check that allocation is still OK
self._check_allocation(
server, self.compute2_rp_uuid, non_qos_normal_port,
- qos_normal_port, qos_sriov_port)
+ qos_normal_port, qos_sriov_port, self.flavor_with_group_policy,
+ new_flavor=new_flavor)
migration_allocations = self.placement_api.get(
'/allocations/%s' % migration_uuid).body['allocations']
self.assertEqual({}, migration_allocations)
@@ -6583,7 +6582,14 @@ class ServerMoveWithPortResourceRequestTest(
self._delete_server_and_check_allocations(
qos_normal_port, qos_sriov_port, server)
- def test_migrate_revert_with_qos_port(self):
+ def test_migrate_server_with_qos_ports(self):
+ self._test_resize_or_migrate_server_with_qos_ports()
+
+ def test_resize_server_with_qos_ports(self):
+ self._test_resize_or_migrate_server_with_qos_ports(
+ new_flavor=self.flavor_with_group_policy_bigger)
+
+ def _test_resize_or_migrate_revert_with_qos_ports(self, new_flavor=None):
non_qos_port = self.neutron.port_1
qos_port = self.neutron.port_with_resource_request
qos_sriov_port = self.neutron.port_with_sriov_resource_request
@@ -6594,9 +6600,14 @@ class ServerMoveWithPortResourceRequestTest(
# check that the server allocates from the current host properly
self._check_allocation(
server, self.compute1_rp_uuid, non_qos_port, qos_port,
- qos_sriov_port)
+ qos_sriov_port, self.flavor_with_group_policy)
+
+ if new_flavor:
+ self.api_fixture.api.post_server_action(
+ server['id'], {'resize': {"flavorRef": new_flavor['id']}})
+ else:
+ self.api.post_server_action(server['id'], {'migrate': None})
- self.api.post_server_action(server['id'], {'migrate': None})
self._wait_for_state_change(self.api, server, 'VERIFY_RESIZE')
migration_uuid = self.get_migration_uuid_for_instance(server['id'])
@@ -6604,8 +6615,9 @@ class ServerMoveWithPortResourceRequestTest(
# check that server allocates from the new host properly
self._check_allocation(
server, self.compute2_rp_uuid, non_qos_port, qos_port,
- qos_sriov_port, migration_uuid,
- source_compute_rp_uuid=self.compute1_rp_uuid)
+ qos_sriov_port, self.flavor_with_group_policy, migration_uuid,
+ source_compute_rp_uuid=self.compute1_rp_uuid,
+ new_flavor=new_flavor)
self.api.post_server_action(server['id'], {'revertResize': None})
self._wait_for_state_change(self.api, server, 'ACTIVE')
@@ -6613,7 +6625,7 @@ class ServerMoveWithPortResourceRequestTest(
# check that allocation is moved back to the source host
self._check_allocation(
server, self.compute1_rp_uuid, non_qos_port, qos_port,
- qos_sriov_port)
+ qos_sriov_port, self.flavor_with_group_policy)
# check that the target host allocation is cleaned up.
self.assertRequestMatchesUsage(
@@ -6627,7 +6639,15 @@ class ServerMoveWithPortResourceRequestTest(
self._delete_server_and_check_allocations(
qos_port, qos_sriov_port, server)
- def test_migrate_server_with_qos_port_reschedule_success(self):
+ def test_migrate_revert_with_qos_ports(self):
+ self._test_resize_or_migrate_revert_with_qos_ports()
+
+ def test_resize_revert_with_qos_ports(self):
+ self._test_resize_or_migrate_revert_with_qos_ports(
+ new_flavor=self.flavor_with_group_policy_bigger)
+
+ def _test_resize_or_migrate_server_with_qos_port_reschedule_success(
+ self, new_flavor=None):
self._start_compute('host3')
compute3_rp_uuid = self._get_provider_uuid_by_host('host3')
self._create_networking_rp_tree('host3', compute3_rp_uuid)
@@ -6642,7 +6662,7 @@ class ServerMoveWithPortResourceRequestTest(
# check that the server allocates from the current host properly
self._check_allocation(
server, self.compute1_rp_uuid, non_qos_port, qos_port,
- qos_sriov_port)
+ qos_sriov_port, self.flavor_with_group_policy)
# Yes this isn't great in a functional test, but it's simple.
original_prep_resize = compute_manager.ComputeManager._prep_resize
@@ -6664,7 +6684,11 @@ class ServerMoveWithPortResourceRequestTest(
with mock.patch.object(
compute_manager.ComputeManager, '_prep_resize',
new=fake_prep_resize):
- self.api.post_server_action(server['id'], {'migrate': None})
+ if new_flavor:
+ self.api_fixture.api.post_server_action(
+ server['id'], {'resize': {"flavorRef": new_flavor['id']}})
+ else:
+ self.api.post_server_action(server['id'], {'migrate': None})
self._wait_for_state_change(self.api, server, 'VERIFY_RESIZE')
# ensure that resize is tried on two hosts, so we had a re-schedule
@@ -6676,13 +6700,16 @@ class ServerMoveWithPortResourceRequestTest(
# the migration holds the allocation on the source host
self._check_allocation(
server, compute3_rp_uuid, non_qos_port, qos_port, qos_sriov_port,
- migration_uuid, source_compute_rp_uuid=self.compute1_rp_uuid)
+ self.flavor_with_group_policy, migration_uuid,
+ source_compute_rp_uuid=self.compute1_rp_uuid,
+ new_flavor=new_flavor)
self._confirm_resize(server)
# check that allocation is still OK
self._check_allocation(
- server, compute3_rp_uuid, non_qos_port, qos_port, qos_sriov_port)
+ server, compute3_rp_uuid, non_qos_port, qos_port, qos_sriov_port,
+ self.flavor_with_group_policy, new_flavor=new_flavor)
migration_allocations = self.placement_api.get(
'/allocations/%s' % migration_uuid).body['allocations']
self.assertEqual({}, migration_allocations)
@@ -6690,7 +6717,15 @@ class ServerMoveWithPortResourceRequestTest(
self._delete_server_and_check_allocations(
qos_port, qos_sriov_port, server)
- def test_migrate_server_with_qos_port_reschedule_failure(self):
+ def test_migrate_server_with_qos_port_reschedule_success(self):
+ self._test_resize_or_migrate_server_with_qos_port_reschedule_success()
+
+ def test_resize_server_with_qos_port_reschedule_success(self):
+ self._test_resize_or_migrate_server_with_qos_port_reschedule_success(
+ new_flavor=self.flavor_with_group_policy_bigger)
+
+ def _test_resize_or_migrate_server_with_qos_port_reschedule_failure(
+ self, new_flavor=None):
non_qos_port = self.neutron.port_1
qos_port = self.neutron.port_with_resource_request
qos_sriov_port = self.neutron.port_with_sriov_resource_request
@@ -6701,7 +6736,7 @@ class ServerMoveWithPortResourceRequestTest(
# check that the server allocates from the current host properly
self._check_allocation(
server, self.compute1_rp_uuid, non_qos_port, qos_port,
- qos_sriov_port)
+ qos_sriov_port, self.flavor_with_group_policy)
# The patched compute manager on host2 will raise from _prep_resize.
# Then the migration is reschedule but there is no other host to
@@ -6710,7 +6745,11 @@ class ServerMoveWithPortResourceRequestTest(
compute_manager.ComputeManager, '_prep_resize',
side_effect=test.TestingException(
'Simulated prep_resize failure.')):
- self.api.post_server_action(server['id'], {'migrate': None})
+ if new_flavor:
+ self.api_fixture.api.post_server_action(
+ server['id'], {'resize': {"flavorRef": new_flavor['id']}})
+ else:
+ self.api.post_server_action(server['id'], {'migrate': None})
self._wait_for_server_parameter(
self.api, server,
{'OS-EXT-SRV-ATTR:host': 'host1',
@@ -6728,7 +6767,14 @@ class ServerMoveWithPortResourceRequestTest(
# and the instance allocates from the source host
self._check_allocation(
server, self.compute1_rp_uuid, non_qos_port, qos_port,
- qos_sriov_port)
+ qos_sriov_port, self.flavor_with_group_policy)
+
+ def test_migrate_server_with_qos_port_reschedule_failure(self):
+ self._test_resize_or_migrate_server_with_qos_port_reschedule_failure()
+
+ def test_resize_server_with_qos_port_reschedule_failure(self):
+ self._test_resize_or_migrate_server_with_qos_port_reschedule_failure(
+ new_flavor=self.flavor_with_group_policy_bigger)
def test_migrate_server_with_qos_port_pci_update_fail_not_reschedule(self):
self._start_compute('host3')
@@ -6745,7 +6791,7 @@ class ServerMoveWithPortResourceRequestTest(
# check that the server allocates from the current host properly
self._check_allocation(
server, self.compute1_rp_uuid, non_qos_port, qos_port,
- qos_sriov_port)
+ qos_sriov_port, self.flavor_with_group_policy)
# The patched compute manager on host2 will raise from
# _update_pci_request_spec_with_allocated_interface_name which will
@@ -6790,7 +6836,7 @@ class ServerMoveWithPortResourceRequestTest(
# and the instance allocates from the source host
self._check_allocation(
server, self.compute1_rp_uuid, non_qos_port, qos_port,
- qos_sriov_port)
+ qos_sriov_port, self.flavor_with_group_policy)
class PortResourceRequestReSchedulingTest(
diff --git a/nova/tests/unit/compute/test_compute_mgr.py b/nova/tests/unit/compute/test_compute_mgr.py
index 134f7eef4c..14f98194a2 100644
--- a/nova/tests/unit/compute/test_compute_mgr.py
+++ b/nova/tests/unit/compute/test_compute_mgr.py
@@ -7591,8 +7591,6 @@ class ComputeManagerMigrationTestCase(test.NoDBTestCase,
'_finish_revert_resize_network_migrate_finish')
@mock.patch('nova.scheduler.utils.'
'fill_provider_mapping_based_on_allocation')
- @mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
- 'get_allocations_for_consumer')
@mock.patch('nova.compute.manager.ComputeManager._revert_allocation')
@mock.patch.object(objects.Instance, 'save')
@mock.patch('nova.compute.manager.ComputeManager.'
@@ -7604,20 +7602,18 @@ class ComputeManagerMigrationTestCase(test.NoDBTestCase,
def test_finish_revert_resize_recalc_group_rp_mapping(
self, mock_get_bdms, mock_notify_action, mock_notify_usage,
mock_set_instance_info, mock_instance_save, mock_revert_allocation,
- mock_get_allocations, mock_fill_provider_mapping,
- mock_network_migrate_finish, mock_drop_migration_context):
+ mock_fill_provider_mapping, mock_network_migrate_finish,
+ mock_drop_migration_context):
mock_get_bdms.return_value = objects.BlockDeviceMappingList()
request_spec = objects.RequestSpec()
- mock_get_allocations.return_value = mock.sentinel.allocation
+ mock_revert_allocation.return_value = mock.sentinel.allocation
with mock.patch.object(
self.compute.network_api, 'get_instance_nw_info'):
self.compute.finish_revert_resize(
self.context, self.instance, self.migration, request_spec)
- mock_get_allocations.assert_called_once_with(
- self.context, self.instance.uuid)
mock_fill_provider_mapping.assert_called_once_with(
self.context, self.compute.reportclient, request_spec,
mock.sentinel.allocation)
diff --git a/releasenotes/notes/support-cold-migrating-neutron-ports-with-resource-request-6d23be654a253625.yaml b/releasenotes/notes/support-cold-migrating-neutron-ports-with-resource-request-6d23be654a253625.yaml
index 3f4f3fc92e..11c9c17700 100644
--- a/releasenotes/notes/support-cold-migrating-neutron-ports-with-resource-request-6d23be654a253625.yaml
+++ b/releasenotes/notes/support-cold-migrating-neutron-ports-with-resource-request-6d23be654a253625.yaml
@@ -1,8 +1,8 @@
---
features:
- |
- Cold migration is now supported for servers with neutron ports having
- resource requests. E.g. ports that have QoS minimum bandwidth rules
+ Cold migration and resize is now supported for servers with neutron ports
+ having resource requests. E.g. ports that have QoS minimum bandwidth rules
attached. Note that the migration is only supported if both the source and
the destination compute services are upgraded to Train and the
``[upgrade_levels]/compute`` configuration does not prevent the computes