nova/nova/tests/functional/regressions/test_bug_1718455.py

134 lines
5.8 KiB
Python

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import time
from nova import test
from nova.tests import fixtures as nova_fixtures
from nova.tests.functional import integrated_helpers
from nova.tests.unit import fake_network
import nova.tests.unit.image.fake
from nova.tests.unit import policy_fixture
class TestLiveMigrateOneOfConcurrentlyCreatedInstances(
test.TestCase, integrated_helpers.InstanceHelperMixin):
"""Regression tests for bug #1718455
When creating multiple instances at the same time, the RequestSpec record
is persisting the number of concurrent instances.
When moving one of those instances, the scheduler should not include
num_instances > 1 in the request spec.
It was partially fixed by bug #1708961 but we forgot to amend
some place in the scheduler so that the right number of hosts was returned
to the scheduler method calling both the Placement API and filters/weighers
but we were verifying that returned size of hosts against a wrong number,
which is the number of instances created concurrently.
That test will create 2 concurrent instances and verify that when
live-migrating one of them, we end up with a correct move operation.
"""
microversion = 'latest'
def setUp(self):
super(TestLiveMigrateOneOfConcurrentlyCreatedInstances, self).setUp()
self.useFixture(policy_fixture.RealPolicyFixture())
self.useFixture(nova_fixtures.NeutronFixture(self))
self.useFixture(nova_fixtures.PlacementFixture())
api_fixture = self.useFixture(nova_fixtures.OSAPIFixture(
api_version='v2.1'))
self.api = api_fixture.admin_api
self.api.microversion = self.microversion
nova.tests.unit.image.fake.stub_out_image_service(self)
self.addCleanup(nova.tests.unit.image.fake.FakeImageService_reset)
self.start_service('conductor')
self.start_service('scheduler')
self.start_service('compute', host='host1')
self.start_service('compute', host='host2')
fake_network.set_stub_network_methods(self)
flavors = self.api.get_flavors()
self.flavor1 = flavors[0]
def _boot_servers(self, num_servers=1):
server_req = self._build_minimal_create_server_request(
self.api, 'some-server', flavor_id=self.flavor1['id'],
image_uuid='155d900f-4e14-4e4c-a73d-069cbf4541e6',
networks='none')
server_req.update({'min_count': str(num_servers),
'return_reservation_id': 'True'})
response = self.api.post_server({'server': server_req})
reservation_id = response['reservation_id']
# lookup servers created by the multi-create request.
servers = self.api.get_servers(detail=True,
search_opts={'reservation_id': reservation_id})
for idx, server in enumerate(servers):
servers[idx] = self._wait_for_state_change(self.api, server,
'ACTIVE')
return servers
def _wait_for_migration_status(self, server, expected_status):
"""Waits for a migration record with the given status to be found
for the given server, else the test fails. The migration record, if
found, is returned.
"""
for attempt in range(10):
migrations = self.api.get_migrations()
for migration in migrations:
if (migration['instance_uuid'] == server['id'] and
migration['status'].lower() ==
expected_status.lower()):
return migration
time.sleep(0.5)
self.fail('Timed out waiting for migration with status "%s" for '
'instance: %s. Current instance migrations: %s' %
(expected_status, server['id'], migrations))
def test_live_migrate_one_multi_created_instance(self):
# Boot two servers in a multi-create request
servers = self._boot_servers(num_servers=2)
# Take the first instance and verify which host the instance is there
server = servers[0]
original_host = server['OS-EXT-SRV-ATTR:host']
target_host = 'host1' if original_host == 'host2' else 'host2'
# Initiate live migration for that instance by targeting the other host
post = {'os-migrateLive': {'block_migration': 'auto',
'host': target_host}}
# NOTE(sbauza): Since API version 2.34, live-migration pre-checks are
# now done asynchronously so even if we hit a NoValidHost exception by
# the conductor, the API call will always succeed with a HTTP202
# response code. In order to verify whether the migration succeeded,
# we need to lookup the migrations API.
self.api.post_server_action(server['id'], post)
# Poll the migration until it is done.
migration = self._wait_for_migration_status(server, 'completed')
self.assertEqual('live-migration', migration['migration_type'])
self.assertEqual(original_host, migration['source_compute'])
# Verify that the migration succeeded as the instance is now on the
# destination node.
server = self.api.get_server(server['id'])
self.assertEqual(target_host, server['OS-EXT-SRV-ATTR:host'])