Add support for fetching console logs from servers

Added get_server_console method to fetch the console
log from a Server. On clouds that do not expose this
feature, a debug line will be logged and an empty
string will be returned.

Change-Id: Ifb973c7d382118d3a8b6bf406cb7ed463b057180
This commit is contained in:
Monty Taylor 2016-08-20 09:38:03 -05:00
parent c40cc19381
commit 7b3b959882
No known key found for this signature in database
GPG Key ID: 7BAE94BC7141A594
6 changed files with 144 additions and 1 deletions

View File

@ -0,0 +1,6 @@
---
features:
- Added get_server_console method to fetch the console
log from a Server. On clouds that do not expose this
feature, a debug line will be logged and an empty
string will be returned.

View File

@ -152,6 +152,11 @@ class ServerListSecurityGroups(task_manager.Task):
return client.nova_client.servers.list_security_group(**self.args)
class ServerConsoleGet(task_manager.Task):
def main(self, client):
return client.nova_client.servers.get_console_output(**self.args)
class ServerGet(task_manager.Task):
def main(self, client):
return client.nova_client.servers.get(**self.args)

View File

@ -1969,6 +1969,40 @@ class OpenStackCloud(object):
return _utils._get_entity(
self.search_security_groups, name_or_id, filters)
def get_server_console(self, server, length=None):
"""Get the console log for a server.
:param server: The server to fetch the console log for. Can be either
a server dict or the Name or ID of the server.
:param int length: The number of lines you would like to retrieve from
the end of the log. (optional, defaults to all)
:returns: A string containing the text of the console log or an
empty string if the cloud does not support console logs.
:raises: OpenStackCloudException if an invalid server argument is given
or if something else unforseen happens
"""
if not isinstance(server, dict):
server = self.get_server(server)
if not server:
raise OpenStackCloudException(
"Console log requested for invalid server")
try:
return self.manager.submitTask(
_tasks.ServerConsoleGet(server=server['id'], length=length),
raw=True)
except nova_exceptions.BadRequest:
return ""
except OpenStackCloudException:
raise
except Exception as e:
raise OpenStackCloudException(
"Unable to get console log for {server}: {exception}".format(
server=server['id'], exception=str(e)))
def get_server(self, name_or_id=None, filters=None, detailed=False):
"""Get a server by name or ID.

View File

@ -92,7 +92,7 @@ class Task(object):
elif (not isinstance(self._result, bool) and
not isinstance(self._result, int) and
not isinstance(self._result, float) and
not isinstance(self._result, str) and
not isinstance(self._result, six.string_types) and
not isinstance(self._result, set) and
not isinstance(self._result, tuple) and
not isinstance(self._result, types.GeneratorType)):

View File

@ -19,9 +19,12 @@ test_compute
Functional tests for `shade` compute methods.
"""
import six
from shade import exc
from shade.tests.functional import base
from shade.tests.functional.util import pick_flavor, pick_image
from shade import _utils
class TestCompute(base.BaseFunctionalTestCase):
@ -67,6 +70,40 @@ class TestCompute(base.BaseFunctionalTestCase):
self.demo_cloud.delete_server(self.server_name, wait=True))
self.assertIsNone(self.demo_cloud.get_server(self.server_name))
def test_get_server_console(self):
self.addCleanup(self._cleanup_servers_and_volumes, self.server_name)
server = self.demo_cloud.create_server(
name=self.server_name,
image=self.image,
flavor=self.flavor,
wait=True)
for _ in _utils._iterate_timeout(
5, "Did not get more than 0 lines in the console log"):
log = self.demo_cloud.get_server_console(server=server)
self.assertTrue(isinstance(log, six.string_types))
if len(log) > 0:
break
def test_get_server_console_name_or_id(self):
self.addCleanup(self._cleanup_servers_and_volumes, self.server_name)
self.demo_cloud.create_server(
name=self.server_name,
image=self.image,
flavor=self.flavor,
wait=True)
for _ in _utils._iterate_timeout(
5, "Did not get more than 0 lines in the console log"):
log = self.demo_cloud.get_server_console(server=self.server_name)
self.assertTrue(isinstance(log, six.string_types))
if len(log) > 0:
break
def test_get_server_console_bad_server(self):
self.assertRaises(
exc.OpenStackCloudException,
self.demo_cloud.get_server_console,
server=self.server_name)
def test_create_and_delete_server_with_admin_pass(self):
self.addCleanup(self._cleanup_servers_and_volumes, self.server_name)
server = self.demo_cloud.create_server(

View File

@ -0,0 +1,61 @@
# -*- coding: utf-8 -*-
# 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 mock
import novaclient.exceptions as nova_exceptions
import shade
from shade.tests.unit import base
from shade.tests import fakes
class TestServerConsole(base.TestCase):
@mock.patch.object(shade.OpenStackCloud, 'nova_client')
def test_get_server_console_dict(self, mock_nova):
server = dict(id='12345')
self.cloud.get_server_console(server)
mock_nova.servers.list.assert_not_called()
mock_nova.servers.get_console_output.assert_called_once_with(
server='12345', length=None)
@mock.patch.object(shade.OpenStackCloud, 'has_service')
@mock.patch.object(shade.OpenStackCloud, 'nova_client')
def test_get_server_console_name_or_id(self, mock_nova, mock_has_service):
server = '12345'
fake_server = fakes.FakeServer(server, '', 'ACTIVE')
mock_nova.servers.get.return_value = fake_server
mock_nova.servers.list.return_value = [fake_server]
mock_has_service.return_value = False
self.cloud.get_server_console(server)
mock_nova.servers.get_console_output.assert_called_once_with(
server='12345', length=None)
@mock.patch.object(shade.OpenStackCloud, 'nova_client')
def test_get_server_console_no_console(self, mock_nova):
server = dict(id='12345')
exc = nova_exceptions.BadRequest(
'There is no such action: os-getConsoleOutput')
mock_nova.servers.get_console_output.side_effect = exc
log = self.cloud.get_server_console(server)
self.assertEqual('', log)
mock_nova.servers.list.assert_not_called()
mock_nova.servers.get_console_output.assert_called_once_with(
server='12345', length=None)