diff --git a/doc/source/users/proxies/compute.rst b/doc/source/users/proxies/compute.rst index 7c657381..63dc2b4e 100644 --- a/doc/source/users/proxies/compute.rst +++ b/doc/source/users/proxies/compute.rst @@ -62,6 +62,7 @@ Starting, Stopping, etc. .. automethod:: openstack.compute.v2._proxy.Proxy.unrescue_server .. 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 Modifying a Server ****************** diff --git a/openstack/compute/v2/_proxy.py b/openstack/compute/v2/_proxy.py index dbdfa682..5a094078 100644 --- a/openstack/compute/v2/_proxy.py +++ b/openstack/compute/v2/_proxy.py @@ -775,6 +775,19 @@ class Proxy(proxy2.BaseProxy): server = self._get_resource(_server.Server, server) server.unshelve(self._session) + def get_server_console_output(self, server, length=None): + """Return the console output for a server. + + :param server: Either the ID of a server or a + :class:`~openstack.compute.v2.server.Server` instance. + :param length: Optional number of line to fetch from the end of console + log. All lines will be returned if this is not specified. + :returns: The console output as a dict. Control characters will be + escaped to create a valid JSON string. + """ + server = self._get_resource(_server.Server, server) + return server.get_console_output(self._session, length=length) + def wait_for_server(self, server, status='ACTIVE', failures=['ERROR'], interval=2, wait=120): return resource2.wait_for_status(self._session, server, status, diff --git a/openstack/compute/v2/server.py b/openstack/compute/v2/server.py index 6618a093..8955a5c3 100644 --- a/openstack/compute/v2/server.py +++ b/openstack/compute/v2/server.py @@ -340,6 +340,13 @@ class Server(resource2.Resource, metadata.MetadataMixin): body = {"migrate": None} self._action(session, body) + def get_console_output(self, session, length=None): + body = {"os-getConsoleOutput": {}} + if length is not None: + body["os-getConsoleOutput"]["length"] = length + resp = self._action(session, body) + return resp.json() + 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 f50112fc..206b412d 100644 --- a/openstack/tests/unit/compute/v2/test_proxy.py +++ b/openstack/tests/unit/compute/v2/test_proxy.py @@ -401,6 +401,17 @@ class TestComputeProxy(test_proxy_base2.TestProxyBase): self.proxy.unshelve_server, method_args=["value"]) + def test_get_server_output(self): + self._verify("openstack.compute.v2.server.Server.get_console_output", + self.proxy.get_server_console_output, + method_args=["value"], + expected_kwargs={"length": None}) + + self._verify("openstack.compute.v2.server.Server.get_console_output", + self.proxy.get_server_console_output, + method_args=["value", 1], + expected_kwargs={"length": 1}) + def test_availability_zones(self): self.verify_list_no_kwargs(self.proxy.availability_zones, az.AvailabilityZone, diff --git a/openstack/tests/unit/compute/v2/test_server.py b/openstack/tests/unit/compute/v2/test_server.py index 0e60d050..44da49be 100644 --- a/openstack/tests/unit/compute/v2/test_server.py +++ b/openstack/tests/unit/compute/v2/test_server.py @@ -615,6 +615,29 @@ class TestServer(testtools.TestCase): self.assertIsNone(res) url = 'servers/IDENTIFIER/action' body = {"migrate": None} + + headers = {'Accept': ''} + self.sess.post.assert_called_with( + url, endpoint_filter=sot.service, json=body, headers=headers) + + def test_get_console_output(self): + sot = server.Server(**EXAMPLE) + + res = sot.get_console_output(self.sess) + + self.assertIsNone(res) + url = 'servers/IDENTIFIER/action' + body = {'os-getConsoleOutput': {}} + headers = {'Accept': ''} + self.sess.post.assert_called_with( + url, endpoint_filter=sot.service, json=body, headers=headers) + + res = sot.get_console_output(self.sess, length=1) + + self.assertIsNone(res) + url = 'servers/IDENTIFIER/action' + body = {'os-getConsoleOutput': {'length': 1}} + headers = {'Accept': ''} self.sess.post.assert_called_with( url, endpoint_filter=sot.service, json=body, headers=headers)