diff --git a/doc/source/users/proxies/compute.rst b/doc/source/users/proxies/compute.rst index 9fb50d01..3d3b3cb1 100644 --- a/doc/source/users/proxies/compute.rst +++ b/doc/source/users/proxies/compute.rst @@ -64,6 +64,7 @@ Starting, Stopping, etc. .. automethod:: openstack.compute.v2._proxy.Proxy.evacuate_server .. automethod:: openstack.compute.v2._proxy.Proxy.migrate_server .. automethod:: openstack.compute.v2._proxy.Proxy.get_server_console_output + .. automethod:: openstack.compute.v2._proxy.Proxy.live_migrate_server Modifying a Server ****************** diff --git a/openstack/compute/v2/_proxy.py b/openstack/compute/v2/_proxy.py index 62622298..9ee9899b 100644 --- a/openstack/compute/v2/_proxy.py +++ b/openstack/compute/v2/_proxy.py @@ -1267,6 +1267,18 @@ class Proxy(proxy2.BaseProxy): :class:`~openstack.compute.v2.server.Server` instance. :returns: None """ - server = self._get_resource(_server.Server, server) server.migrate(self._session) + + def live_migrate_server(self, server, host=None, force=False): + """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. + :returns: None + """ + server = self._get_resource(_server.Server, server) + server.live_migrate(self._session, host, force) diff --git a/openstack/compute/v2/server.py b/openstack/compute/v2/server.py index 440cdc62..574b7202 100644 --- a/openstack/compute/v2/server.py +++ b/openstack/compute/v2/server.py @@ -357,6 +357,16 @@ class Server(resource2.Resource, metadata.MetadataMixin): resp = self._action(session, body) return resp.json() + def live_migrate(self, session, host, force): + body = { + "os-migrateLive": { + "host": host, + "block_migration": "auto", + "force": force + } + } + self._action(session, body) + class ServerDetail(Server): base_path = '/servers/detail' diff --git a/openstack/tests/unit/compute/v2/test_proxy.py b/openstack/tests/unit/compute/v2/test_proxy.py index 9468a0f5..a608a261 100644 --- a/openstack/tests/unit/compute/v2/test_proxy.py +++ b/openstack/tests/unit/compute/v2/test_proxy.py @@ -510,3 +510,9 @@ class TestComputeProxy(test_proxy_base2.TestProxyBase): self.proxy.force_service_down, method_args=["value", "host1", "nova-compute"], expected_args=["host1", "nova-compute"]) + + 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"]) diff --git a/openstack/tests/unit/compute/v2/test_server.py b/openstack/tests/unit/compute/v2/test_server.py index 3485eb8a..80f5fa93 100644 --- a/openstack/tests/unit/compute/v2/test_server.py +++ b/openstack/tests/unit/compute/v2/test_server.py @@ -654,3 +654,22 @@ class TestServer(testtools.TestCase): headers = {'Accept': ''} self.sess.post.assert_called_with( url, endpoint_filter=sot.service, json=body, headers=headers) + + def test_live_migrate(self): + sot = server.Server(**EXAMPLE) + + res = sot.live_migrate(self.sess, host='HOST2', force=False) + + self.assertIsNone(res) + url = 'servers/IDENTIFIER/action' + body = { + "os-migrateLive": { + "host": 'HOST2', + "block_migration": "auto", + "force": False + } + } + + headers = {'Accept': ''} + self.sess.post.assert_called_with( + url, endpoint_filter=sot.service, json=body, headers=headers)