Skip to content

Commit b41c0fd

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "Test aborting queued live migration" into stable/xena
2 parents ad7447d + 19c4f8e commit b41c0fd

File tree

1 file changed

+117
-0
lines changed

1 file changed

+117
-0
lines changed
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# Copyright 2021 Red Hat, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
4+
# not use this file except in compliance with the License. You may obtain
5+
# a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12+
# License for the specific language governing permissions and limitations
13+
# under the License.
14+
15+
import threading
16+
17+
from lxml import etree
18+
from nova.tests.functional import integrated_helpers
19+
from nova.tests.functional.libvirt import base as libvirt_base
20+
21+
22+
class LiveMigrationQueuedAbortTest(
23+
libvirt_base.LibvirtMigrationMixin,
24+
libvirt_base.ServersTestBase,
25+
integrated_helpers.InstanceHelperMixin
26+
):
27+
"""Functional test for bug 1949808.
28+
29+
This test is used to confirm that VM's state is reverted properly
30+
when queued Live migration is aborted.
31+
"""
32+
33+
api_major_version = 'v2.1'
34+
microversion = '2.74'
35+
ADMIN_API = True
36+
37+
def setUp(self):
38+
super().setUp()
39+
40+
# We will allow only one live migration to be processed at any
41+
# given period of time
42+
self.flags(max_concurrent_live_migrations='1')
43+
self.src_hostname = self.start_compute(hostname='src')
44+
self.dest_hostname = self.start_compute(hostname='dest')
45+
46+
self.src = self.computes[self.src_hostname]
47+
self.dest = self.computes[self.dest_hostname]
48+
49+
# Live migration's execution could be locked if needed
50+
self.lock_live_migration = threading.Lock()
51+
52+
def _migrate_stub(self, domain, destination, params, flags):
53+
# Execute only if live migration is not locked
54+
with self.lock_live_migration:
55+
self.dest.driver._host.get_connection().createXML(
56+
params['destination_xml'],
57+
'fake-createXML-doesnt-care-about-flags')
58+
conn = self.src.driver._host.get_connection()
59+
60+
# Because migrateToURI3 is spawned in a background thread,
61+
# this method does not block the upper nova layers. Because
62+
# we don't want nova to think the live migration has
63+
# finished until this method is done, the last thing we do
64+
# is make fakelibvirt's Domain.jobStats() return
65+
# VIR_DOMAIN_JOB_COMPLETED.
66+
server = etree.fromstring(
67+
params['destination_xml']
68+
).find('./uuid').text
69+
dom = conn.lookupByUUIDString(server)
70+
dom.complete_job()
71+
72+
def test_queued_live_migration_abort(self):
73+
# Lock live migrations
74+
self.lock_live_migration.acquire()
75+
76+
# Start instances: first one would be used to occupy
77+
# executor's live migration queue, second one would be used
78+
# to actually confirm that queued live migrations are
79+
# aborted properly.
80+
self.server_a = self._create_server(
81+
host=self.src_hostname, networks='none')
82+
self.server_b = self._create_server(
83+
host=self.src_hostname, networks='none')
84+
# Issue live migration requests for both servers. We expect that
85+
# server_a live migration would be running, but locked by
86+
# self.lock_live_migration and server_b live migration would be
87+
# queued.
88+
self._live_migrate(
89+
self.server_a,
90+
migration_expected_state='running',
91+
server_expected_state='MIGRATING'
92+
)
93+
self._live_migrate(
94+
self.server_b,
95+
migration_expected_state='queued',
96+
server_expected_state='MIGRATING'
97+
)
98+
99+
# Abort live migration for server_b
100+
serverb_migration = self.api.api_get(
101+
'/os-migrations?instance_uuid=%s' % self.server_b['id']
102+
).body['migrations'].pop()
103+
104+
self.api.api_delete(
105+
'/servers/%s/migrations/%s' % (self.server_b['id'],
106+
serverb_migration['id']))
107+
self._wait_for_migration_status(self.server_b, ['cancelled'])
108+
# Unlock live migrations and confirm that server_a becomes
109+
# active again after successful live migration
110+
self.lock_live_migration.release()
111+
self._wait_for_state_change(self.server_a, 'ACTIVE')
112+
113+
# FIXME(artom) Assert the server_b never comes out of 'MIGRATING'
114+
self.assertRaises(
115+
AssertionError,
116+
self._wait_for_state_change, self.server_b, 'ACTIVE')
117+
self._wait_for_state_change(self.server_b, 'MIGRATING')

0 commit comments

Comments
 (0)