Only send force parameter to live migration if supported
force isn't supported until microversion 2.30. Add a test for that microversion and only send it if the server supports it. Change-Id: Ic45e9cccac10d432162d27f9b42da4f4eb1ff167 Story: 2002752 Task: 22608
This commit is contained in:
parent
34ea72ce5b
commit
ed9cd86573
|
@ -1167,15 +1167,31 @@ class Proxy(proxy.Proxy):
|
|||
server = self._get_resource(_server.Server, server)
|
||||
server.migrate(self)
|
||||
|
||||
def live_migrate_server(self, server, host=None, force=False):
|
||||
"""Migrate a server from one host to target host
|
||||
def live_migrate_server(
|
||||
self, server, host=None, force=False, block_migration=None):
|
||||
"""Live migrate a server from one host to target host
|
||||
|
||||
:param server: Either the ID of a server or a
|
||||
:class:`~openstack.compute.v2.server.Server` instance.
|
||||
:param host: The host to which to migrate the server
|
||||
:param force: Force a live-migration by not verifying the provided
|
||||
destination host by the scheduler.
|
||||
:param server:
|
||||
Either the ID of a server or a
|
||||
:class:`~openstack.compute.v2.server.Server` instance.
|
||||
:param str host:
|
||||
The host to which to migrate the server. If the Nova service is
|
||||
too old, the host parameter implies force=True which causes the
|
||||
Nova scheduler to be bypassed. On such clouds, a ``ValueError``
|
||||
will be thrown if ``host`` is given without ``force``.
|
||||
:param bool force:
|
||||
Force a live-migration by not verifying the provided destination
|
||||
host by the scheduler. This is unsafe and not recommended.
|
||||
:param block_migration:
|
||||
Perform a block live migration to the destination host by the
|
||||
scheduler. Can be 'auto', True or False. Some clouds are too old
|
||||
to support 'auto', in which case a ValueError will be thrown. If
|
||||
omitted, the value will be 'auto' on clouds that support it, and
|
||||
False on clouds that do not.
|
||||
:returns: None
|
||||
"""
|
||||
server = self._get_resource(_server.Server, server)
|
||||
server.live_migrate(self, host, force)
|
||||
server.live_migrate(
|
||||
self, host,
|
||||
force=force,
|
||||
block_migration=block_migration)
|
||||
|
|
|
@ -171,7 +171,7 @@ class Server(resource.Resource, metadata.MetadataMixin):
|
|||
|
||||
return request
|
||||
|
||||
def _action(self, session, body):
|
||||
def _action(self, session, body, microversion=None):
|
||||
"""Preform server actions given the message body."""
|
||||
# NOTE: This is using Server.base_path instead of self.base_path
|
||||
# as both Server and ServerDetail instances can be acted on, but
|
||||
|
@ -179,7 +179,7 @@ class Server(resource.Resource, metadata.MetadataMixin):
|
|||
url = utils.urljoin(Server.base_path, self.id, 'action')
|
||||
headers = {'Accept': ''}
|
||||
return session.post(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=microversion)
|
||||
|
||||
def change_password(self, session, new_password):
|
||||
"""Change the administrator password to the given password."""
|
||||
|
@ -363,15 +363,80 @@ class Server(resource.Resource, metadata.MetadataMixin):
|
|||
resp = self._action(session, body)
|
||||
return resp.json()
|
||||
|
||||
def live_migrate(self, session, host, force):
|
||||
def live_migrate(self, session, host, force, block_migration):
|
||||
if utils.supports_microversion(session, '2.30'):
|
||||
return self._live_migrate_30(
|
||||
session, host,
|
||||
force=force,
|
||||
block_migration=block_migration)
|
||||
elif utils.supports_microversion(session, '2.25'):
|
||||
return self._live_migrate_25(
|
||||
session, host,
|
||||
force=force,
|
||||
block_migration=block_migration)
|
||||
else:
|
||||
return self._live_migrate(
|
||||
session, host,
|
||||
force=force,
|
||||
block_migration=block_migration)
|
||||
|
||||
def _live_migrate_30(self, session, host, force, block_migration):
|
||||
microversion = '2.30'
|
||||
body = {'host': None}
|
||||
if block_migration is None:
|
||||
block_migration = 'auto'
|
||||
body['block_migration'] = block_migration
|
||||
if host:
|
||||
body['host'] = host
|
||||
if force:
|
||||
body['force'] = force
|
||||
self._action(
|
||||
session, {'os-migrateLive': body}, microversion=microversion)
|
||||
|
||||
def _live_migrate_25(self, session, host, force, block_migration):
|
||||
microversion = '2.25'
|
||||
body = {'host': None}
|
||||
if block_migration is None:
|
||||
block_migration = 'auto'
|
||||
body['block_migration'] = block_migration
|
||||
if host:
|
||||
body['host'] = host
|
||||
if not force:
|
||||
raise ValueError(
|
||||
"Live migration on this cloud implies 'force'"
|
||||
" if the 'host' option has been given and it is not"
|
||||
" possible to disable. It is recommended to not use 'host'"
|
||||
" at all on this cloud as it is inherently unsafe, but if"
|
||||
" it is unavoidable, please supply 'force=True' so that it"
|
||||
" is clear you understand the risks.")
|
||||
self._action(
|
||||
session, {'os-migrateLive': body}, microversion=microversion)
|
||||
|
||||
def _live_migrate(self, session, host, force, block_migration):
|
||||
microversion = None
|
||||
# disk_over_commit is not exposed because post 2.25 it has been
|
||||
# removed and no SDK user is depending on it today.
|
||||
body = {
|
||||
"os-migrateLive": {
|
||||
"host": host,
|
||||
"block_migration": "auto",
|
||||
"force": force
|
||||
}
|
||||
'host': None,
|
||||
'disk_over_commit': False,
|
||||
}
|
||||
self._action(session, body)
|
||||
if block_migration == 'auto':
|
||||
raise ValueError(
|
||||
"Live migration on this cloud does not support 'auto' as"
|
||||
" a parameter to block_migration, but only True and False.")
|
||||
body['block_migration'] = block_migration or False
|
||||
if host:
|
||||
body['host'] = host
|
||||
if not force:
|
||||
raise ValueError(
|
||||
"Live migration on this cloud implies 'force'"
|
||||
" if the 'host' option has been given and it is not"
|
||||
" possible to disable. It is recommended to not use 'host'"
|
||||
" at all on this cloud as it is inherently unsafe, but if"
|
||||
" it is unavoidable, please supply 'force=True' so that it"
|
||||
" is clear you understand the risks.")
|
||||
self._action(
|
||||
session, {'os-migrateLive': body}, microversion=microversion)
|
||||
|
||||
|
||||
class ServerDetail(Server):
|
||||
|
|
|
@ -526,5 +526,6 @@ class TestComputeProxy(test_proxy_base.TestProxyBase):
|
|||
def test_live_migrate_server(self):
|
||||
self._verify('openstack.compute.v2.server.Server.live_migrate',
|
||||
self.proxy.live_migrate_server,
|
||||
method_args=["value", "host1", "force"],
|
||||
expected_args=["host1", "force"])
|
||||
method_args=["value", "host1", False],
|
||||
expected_args=["host1"],
|
||||
expected_kwargs={'force': False, 'block_migration': None})
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
# under the License.
|
||||
|
||||
import mock
|
||||
import six
|
||||
from openstack.tests.unit import base
|
||||
|
||||
from openstack.compute.v2 import server
|
||||
|
@ -193,7 +194,7 @@ class TestServer(base.TestCase):
|
|||
body = {"changePassword": {"adminPass": "a"}}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_reboot(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -204,7 +205,7 @@ class TestServer(base.TestCase):
|
|||
body = {"reboot": {"type": "HARD"}}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_force_delete(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -215,7 +216,7 @@ class TestServer(base.TestCase):
|
|||
body = {'forceDelete': None}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_rebuild(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -246,7 +247,7 @@ class TestServer(base.TestCase):
|
|||
}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_rebuild_minimal(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -270,7 +271,7 @@ class TestServer(base.TestCase):
|
|||
}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_resize(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -281,7 +282,7 @@ class TestServer(base.TestCase):
|
|||
body = {"resize": {"flavorRef": "2"}}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_confirm_resize(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -292,7 +293,7 @@ class TestServer(base.TestCase):
|
|||
body = {"confirmResize": None}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_revert_resize(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -303,7 +304,7 @@ class TestServer(base.TestCase):
|
|||
body = {"revertResize": None}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_create_image(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -316,7 +317,7 @@ class TestServer(base.TestCase):
|
|||
body = {"createImage": {'name': name, 'metadata': metadata}}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_create_image_minimal(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -328,7 +329,7 @@ class TestServer(base.TestCase):
|
|||
body = {"createImage": {'name': name}}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_add_security_group(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -339,7 +340,7 @@ class TestServer(base.TestCase):
|
|||
body = {"addSecurityGroup": {"name": "group"}}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_remove_security_group(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -350,7 +351,7 @@ class TestServer(base.TestCase):
|
|||
body = {"removeSecurityGroup": {"name": "group"}}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_reset_state(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -361,7 +362,7 @@ class TestServer(base.TestCase):
|
|||
body = {"os-resetState": {"state": 'active'}}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_add_fixed_ip(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -373,7 +374,7 @@ class TestServer(base.TestCase):
|
|||
body = {"addFixedIp": {"networkId": "NETWORK-ID"}}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_remove_fixed_ip(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -385,7 +386,7 @@ class TestServer(base.TestCase):
|
|||
body = {"removeFixedIp": {"address": "ADDRESS"}}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_add_floating_ip(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -397,7 +398,7 @@ class TestServer(base.TestCase):
|
|||
body = {"addFloatingIp": {"address": "FLOATING-IP"}}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_add_floating_ip_with_fixed_addr(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -410,7 +411,7 @@ class TestServer(base.TestCase):
|
|||
"fixed_address": "FIXED-ADDR"}}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_remove_floating_ip(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -422,7 +423,7 @@ class TestServer(base.TestCase):
|
|||
body = {"removeFloatingIp": {"address": "I-AM-FLOATING"}}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_backup(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -435,7 +436,7 @@ class TestServer(base.TestCase):
|
|||
"rotation": 1}}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_pause(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -447,7 +448,7 @@ class TestServer(base.TestCase):
|
|||
body = {"pause": None}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_unpause(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -459,7 +460,7 @@ class TestServer(base.TestCase):
|
|||
body = {"unpause": None}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_suspend(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -471,7 +472,7 @@ class TestServer(base.TestCase):
|
|||
body = {"suspend": None}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_resume(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -483,7 +484,7 @@ class TestServer(base.TestCase):
|
|||
body = {"resume": None}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_lock(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -495,7 +496,7 @@ class TestServer(base.TestCase):
|
|||
body = {"lock": None}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_unlock(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -507,7 +508,7 @@ class TestServer(base.TestCase):
|
|||
body = {"unlock": None}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_rescue(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -519,7 +520,7 @@ class TestServer(base.TestCase):
|
|||
body = {"rescue": {}}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_rescue_with_options(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -532,7 +533,7 @@ class TestServer(base.TestCase):
|
|||
'rescue_image_ref': 'IMG-ID'}}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_unrescue(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -544,7 +545,7 @@ class TestServer(base.TestCase):
|
|||
body = {"unrescue": None}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_evacuate(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -556,7 +557,7 @@ class TestServer(base.TestCase):
|
|||
body = {"evacuate": {}}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_evacuate_with_options(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -570,7 +571,7 @@ class TestServer(base.TestCase):
|
|||
'force': True}}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_start(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -582,7 +583,7 @@ class TestServer(base.TestCase):
|
|||
body = {"os-start": None}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_stop(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -594,7 +595,7 @@ class TestServer(base.TestCase):
|
|||
body = {"os-stop": None}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_shelve(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -606,7 +607,7 @@ class TestServer(base.TestCase):
|
|||
body = {"shelve": None}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_unshelve(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -618,7 +619,7 @@ class TestServer(base.TestCase):
|
|||
body = {"unshelve": None}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_migrate(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -631,7 +632,7 @@ class TestServer(base.TestCase):
|
|||
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_get_console_output(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
@ -643,7 +644,7 @@ class TestServer(base.TestCase):
|
|||
body = {'os-getConsoleOutput': {}}
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
res = sot.get_console_output(self.sess, length=1)
|
||||
|
||||
|
@ -653,23 +654,142 @@ class TestServer(base.TestCase):
|
|||
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_live_migrate(self):
|
||||
def test_live_migrate_no_force(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
||||
res = sot.live_migrate(self.sess, host='HOST2', force=False)
|
||||
class FakeEndpointData(object):
|
||||
min_microversion = None
|
||||
max_microversion = None
|
||||
self.sess.get_endpoint_data.return_value = FakeEndpointData()
|
||||
|
||||
ex = self.assertRaises(
|
||||
ValueError,
|
||||
sot.live_migrate,
|
||||
self.sess, host='HOST2', force=False, block_migration=False)
|
||||
self.assertIn(
|
||||
"Live migration on this cloud implies 'force'",
|
||||
six.text_type(ex))
|
||||
|
||||
def test_live_migrate_no_microversion_force_true(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
||||
class FakeEndpointData(object):
|
||||
min_microversion = None
|
||||
max_microversion = None
|
||||
self.sess.get_endpoint_data.return_value = FakeEndpointData()
|
||||
|
||||
res = sot.live_migrate(
|
||||
self.sess, host='HOST2', force=True, block_migration=False)
|
||||
|
||||
self.assertIsNone(res)
|
||||
url = 'servers/IDENTIFIER/action'
|
||||
body = {
|
||||
"os-migrateLive": {
|
||||
"host": 'HOST2',
|
||||
"block_migration": "auto",
|
||||
"force": False
|
||||
'os-migrateLive': {
|
||||
'host': 'HOST2',
|
||||
'disk_over_commit': False,
|
||||
'block_migration': False
|
||||
}
|
||||
}
|
||||
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers)
|
||||
url, json=body, headers=headers, microversion=None)
|
||||
|
||||
def test_live_migrate_25(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
||||
class FakeEndpointData(object):
|
||||
min_microversion = '2.1'
|
||||
max_microversion = '2.25'
|
||||
self.sess.get_endpoint_data.return_value = FakeEndpointData()
|
||||
|
||||
res = sot.live_migrate(
|
||||
self.sess, host='HOST2', force=True, block_migration=False)
|
||||
|
||||
self.assertIsNone(res)
|
||||
url = 'servers/IDENTIFIER/action'
|
||||
body = {
|
||||
"os-migrateLive": {
|
||||
'block_migration': False,
|
||||
'host': 'HOST2',
|
||||
}
|
||||
}
|
||||
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers, microversion='2.25')
|
||||
|
||||
def test_live_migrate_25_default_block(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
||||
class FakeEndpointData(object):
|
||||
min_microversion = '2.1'
|
||||
max_microversion = '2.25'
|
||||
self.sess.get_endpoint_data.return_value = FakeEndpointData()
|
||||
|
||||
res = sot.live_migrate(
|
||||
self.sess, host='HOST2', force=True, block_migration=None)
|
||||
|
||||
self.assertIsNone(res)
|
||||
url = 'servers/IDENTIFIER/action'
|
||||
body = {
|
||||
"os-migrateLive": {
|
||||
'block_migration': 'auto',
|
||||
'host': 'HOST2',
|
||||
}
|
||||
}
|
||||
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers, microversion='2.25')
|
||||
|
||||
def test_live_migrate_30(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
||||
class FakeEndpointData(object):
|
||||
min_microversion = '2.1'
|
||||
max_microversion = '2.30'
|
||||
self.sess.get_endpoint_data.return_value = FakeEndpointData()
|
||||
|
||||
res = sot.live_migrate(
|
||||
self.sess, host='HOST2', force=False, block_migration=False)
|
||||
|
||||
self.assertIsNone(res)
|
||||
url = 'servers/IDENTIFIER/action'
|
||||
body = {
|
||||
'os-migrateLive': {
|
||||
'block_migration': False,
|
||||
'host': 'HOST2'
|
||||
}
|
||||
}
|
||||
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers, microversion='2.30')
|
||||
|
||||
def test_live_migrate_30_force(self):
|
||||
sot = server.Server(**EXAMPLE)
|
||||
|
||||
class FakeEndpointData(object):
|
||||
min_microversion = '2.1'
|
||||
max_microversion = '2.30'
|
||||
self.sess.get_endpoint_data.return_value = FakeEndpointData()
|
||||
|
||||
res = sot.live_migrate(
|
||||
self.sess, host='HOST2', force=True, block_migration=None)
|
||||
|
||||
self.assertIsNone(res)
|
||||
url = 'servers/IDENTIFIER/action'
|
||||
body = {
|
||||
'os-migrateLive': {
|
||||
'block_migration': 'auto',
|
||||
'host': 'HOST2',
|
||||
'force': True,
|
||||
}
|
||||
}
|
||||
|
||||
headers = {'Accept': ''}
|
||||
self.sess.post.assert_called_with(
|
||||
url, json=body, headers=headers, microversion='2.30')
|
||||
|
|
|
@ -15,6 +15,7 @@ import string
|
|||
import time
|
||||
|
||||
import deprecation
|
||||
from keystoneauth1 import discover
|
||||
|
||||
from openstack import _log
|
||||
from openstack import exceptions
|
||||
|
@ -128,3 +129,28 @@ def get_string_format_keys(fmt_string, old_style=True):
|
|||
if t[1] is not None:
|
||||
keys.append(t[1])
|
||||
return keys
|
||||
|
||||
|
||||
def supports_microversion(adapter, microversion):
|
||||
"""Determine if the given adapter supports the given microversion.
|
||||
|
||||
Checks the min and max microversion asserted by the service and checks
|
||||
to make sure that ``min <= microversion <= max``.
|
||||
|
||||
:param adapter:
|
||||
:class:`~keystoneauth1.adapter.Adapter` instance.
|
||||
:param str microversion:
|
||||
String containing the desired microversion.
|
||||
:returns: True if the service supports the microversion.
|
||||
:rtype: bool
|
||||
"""
|
||||
|
||||
endpoint_data = adapter.get_endpoint_data()
|
||||
if (endpoint_data.min_microversion
|
||||
and endpoint_data.max_microversion
|
||||
and discover.version_between(
|
||||
endpoint_data.min_microversion,
|
||||
endpoint_data.max_microversion,
|
||||
microversion)):
|
||||
return True
|
||||
return False
|
||||
|
|
Loading…
Reference in New Issue