summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGorka Eguileor <geguileo@redhat.com>2017-03-14 13:52:14 +0100
committerGorka Eguileor <geguileo@redhat.com>2017-07-10 15:11:55 +0200
commit6a00d30e966d5fbd24cc8817afae32d9969adfb5 (patch)
treee90684f06b24a10c1301cb0030b49adf2ee16d17
parenteaee84097ab15338e8655b8bd1590a25993c09d5 (diff)
downloadpython-cinderclient-6a00d30e966d5fbd24cc8817afae32d9969adfb5.tar.gz
Dynamic log level support
This patch adds support for microversion 3.32 allowing setting and querying Cinder services' log levels. Two new commands are available: cinder service-get-log [--binary {,*,cinder-api,cinder-volume,cinder-scheduler, cinder-backup}] [--server SERVER] [--prefix PREFIX] cinder service-set-log [--binary {,*,cinder-api,cinder-volume,cinder-scheduler, cinder-backup}] [--server SERVER] [--prefix PREFIX] <log-level> Implements: blueprint dynamic-log-levels Depends-On: Ia5ef81135044733f1dd3970a116f97457b0371de Change-Id: I50b5ea93464b15751e45afa0a05475651eeb53a8
-rw-r--r--cinderclient/tests/unit/v3/fakes.py10
-rw-r--r--cinderclient/tests/unit/v3/test_services.py42
-rw-r--r--cinderclient/tests/unit/v3/test_shell.py76
-rw-r--r--cinderclient/v3/services.py29
-rw-r--r--cinderclient/v3/shell.py41
-rw-r--r--releasenotes/notes/service_dynamic_log-bd81d93c73fc1570.yaml6
6 files changed, 204 insertions, 0 deletions
diff --git a/cinderclient/tests/unit/v3/fakes.py b/cinderclient/tests/unit/v3/fakes.py
index 7b6ea71..c06ca3e 100644
--- a/cinderclient/tests/unit/v3/fakes.py
+++ b/cinderclient/tests/unit/v3/fakes.py
@@ -547,6 +547,16 @@ class FakeHTTPClient(fake_v2.FakeHTTPClient):
}
return 200, {}, {'message': message}
+ def put_os_services_set_log(self, body):
+ return (202, {}, {})
+
+ def put_os_services_get_log(self, body):
+ levels = [{'binary': 'cinder-api', 'host': 'host1',
+ 'levels': {'prefix1': 'DEBUG', 'prefix2': 'INFO'}},
+ {'binary': 'cinder-volume', 'host': 'host@backend#pool',
+ 'levels': {'prefix3': 'WARNING', 'prefix4': 'ERROR'}}]
+ return (200, {}, {'log_levels': levels})
+
#
# resource filters
#
diff --git a/cinderclient/tests/unit/v3/test_services.py b/cinderclient/tests/unit/v3/test_services.py
index ac45298..92f7903 100644
--- a/cinderclient/tests/unit/v3/test_services.py
+++ b/cinderclient/tests/unit/v3/test_services.py
@@ -41,3 +41,45 @@ class ServicesTest(utils.TestCase):
client = fakes.FakeClient(version_header='3.0')
svs = client.services.server_api_version()
[self.assertIsInstance(s, services.Service) for s in svs]
+
+ def test_set_log_levels(self):
+ expected = {'level': 'debug', 'binary': 'cinder-api',
+ 'server': 'host1', 'prefix': 'sqlalchemy.'}
+
+ cs = fakes.FakeClient(version_header='3.32')
+ cs.services.set_log_levels(expected['level'], expected['binary'],
+ expected['server'], expected['prefix'])
+
+ cs.assert_called('PUT', '/os-services/set-log', body=expected)
+
+ def test_get_log_levels(self):
+ expected = {'binary': 'cinder-api', 'server': 'host1',
+ 'prefix': 'sqlalchemy.'}
+
+ cs = fakes.FakeClient(version_header='3.32')
+ result = cs.services.get_log_levels(expected['binary'],
+ expected['server'],
+ expected['prefix'])
+
+ cs.assert_called('PUT', '/os-services/get-log', body=expected)
+ expected = [services.LogLevel(cs.services,
+ {'binary': 'cinder-api', 'host': 'host1',
+ 'prefix': 'prefix1', 'level': 'DEBUG'},
+ loaded=True),
+ services.LogLevel(cs.services,
+ {'binary': 'cinder-api', 'host': 'host1',
+ 'prefix': 'prefix2', 'level': 'INFO'},
+ loaded=True),
+ services.LogLevel(cs.services,
+ {'binary': 'cinder-volume',
+ 'host': 'host@backend#pool',
+ 'prefix': 'prefix3',
+ 'level': 'WARNING'},
+ loaded=True),
+ services.LogLevel(cs.services,
+ {'binary': 'cinder-volume',
+ 'host': 'host@backend#pool',
+ 'prefix': 'prefix4', 'level': 'ERROR'},
+ loaded=True)]
+ # Since it will be sorted by the prefix we can compare them directly
+ self.assertListEqual(expected, result)
diff --git a/cinderclient/tests/unit/v3/test_shell.py b/cinderclient/tests/unit/v3/test_shell.py
index bfd2d93..96dd7cf 100644
--- a/cinderclient/tests/unit/v3/test_shell.py
+++ b/cinderclient/tests/unit/v3/test_shell.py
@@ -18,6 +18,7 @@ import ddt
import fixtures
import mock
from requests_mock.contrib import fixture as requests_mock_fixture
+import six
from cinderclient import client
from cinderclient import exceptions
@@ -788,3 +789,78 @@ class ShellTest(utils.TestCase):
self.run_command(cmd)
expected = {'list_replication_targets': {}}
self.assert_called('POST', '/groups/1234/action', body=expected)
+
+ @mock.patch('cinderclient.v3.services.ServiceManager.get_log_levels')
+ def test_service_get_log_before_3_32(self, get_levels_mock):
+ self.assertRaises(SystemExit,
+ self.run_command, '--os-volume-api-version 3.28 '
+ 'service-get-log')
+ get_levels_mock.assert_not_called()
+
+ @mock.patch('cinderclient.v3.services.ServiceManager.get_log_levels')
+ @mock.patch('cinderclient.utils.print_list')
+ def test_service_get_log_no_params(self, print_mock, get_levels_mock):
+ self.run_command('--os-volume-api-version 3.32 service-get-log')
+ get_levels_mock.assert_called_once_with('', '', '')
+ print_mock.assert_called_once_with(get_levels_mock.return_value,
+ ('Binary', 'Host', 'Prefix',
+ 'Level'))
+
+ @ddt.data('*', 'cinder-api', 'cinder-volume', 'cinder-scheduler',
+ 'cinder-backup')
+ @mock.patch('cinderclient.v3.services.ServiceManager.get_log_levels')
+ @mock.patch('cinderclient.utils.print_list')
+ def test_service_get_log(self, binary, print_mock, get_levels_mock):
+ server = 'host1'
+ prefix = 'sqlalchemy'
+
+ self.run_command('--os-volume-api-version 3.32 service-get-log '
+ '--binary %s --server %s --prefix %s' % (
+ binary, server, prefix))
+ get_levels_mock.assert_called_once_with(binary, server, prefix)
+ print_mock.assert_called_once_with(get_levels_mock.return_value,
+ ('Binary', 'Host', 'Prefix',
+ 'Level'))
+
+ @mock.patch('cinderclient.v3.services.ServiceManager.set_log_levels')
+ def test_service_set_log_before_3_32(self, set_levels_mock):
+ self.assertRaises(SystemExit,
+ self.run_command, '--os-volume-api-version 3.28 '
+ 'service-set-log debug')
+ set_levels_mock.assert_not_called()
+
+ @mock.patch('cinderclient.v3.services.ServiceManager.set_log_levels')
+ @mock.patch('cinderclient.shell.CinderClientArgumentParser.error')
+ def test_service_set_log_missing_required(self, error_mock,
+ set_levels_mock):
+ error_mock.side_effect = SystemExit
+ self.assertRaises(SystemExit,
+ self.run_command, '--os-volume-api-version 3.32 '
+ 'service-set-log')
+ set_levels_mock.assert_not_called()
+ # Different error message from argparse library in Python 2 and 3
+ if six.PY3:
+ msg = 'the following arguments are required: <log-level>'
+ else:
+ msg = 'too few arguments'
+ error_mock.assert_called_once_with(msg)
+
+ @ddt.data('debug', 'DEBUG', 'info', 'INFO', 'warning', 'WARNING', 'error',
+ 'ERROR')
+ @mock.patch('cinderclient.v3.services.ServiceManager.set_log_levels')
+ def test_service_set_log_min_params(self, level, set_levels_mock):
+ self.run_command('--os-volume-api-version 3.32 '
+ 'service-set-log %s' % level)
+ set_levels_mock.assert_called_once_with(level, '', '', '')
+
+ @ddt.data('*', 'cinder-api', 'cinder-volume', 'cinder-scheduler',
+ 'cinder-backup')
+ @mock.patch('cinderclient.v3.services.ServiceManager.set_log_levels')
+ def test_service_set_log_levels(self, binary, set_levels_mock):
+ level = 'debug'
+ server = 'host1'
+ prefix = 'sqlalchemy.'
+ self.run_command('--os-volume-api-version 3.32 '
+ 'service-set-log %s --binary %s --server %s '
+ '--prefix %s' % (level, binary, server, prefix))
+ set_levels_mock.assert_called_once_with(level, binary, server, prefix)
diff --git a/cinderclient/v3/services.py b/cinderclient/v3/services.py
index bd8a6c4..55d3ee4 100644
--- a/cinderclient/v3/services.py
+++ b/cinderclient/v3/services.py
@@ -18,11 +18,18 @@ service interface
"""
from cinderclient import api_versions
+from cinderclient import base
from cinderclient.v2 import services
Service = services.Service
+class LogLevel(base.Resource):
+ def __repr__(self):
+ return '<LogLevel: binary=%s host=%s prefix=%s level=%s>' % (
+ self.binary, self.host, self.prefix, self.level)
+
+
class ServiceManager(services.ServiceManager):
@api_versions.wraps("3.0")
def server_api_version(self):
@@ -36,3 +43,25 @@ class ServiceManager(services.ServiceManager):
return self._get_with_base_url("", response_key='versions')
except LookupError:
return []
+
+ @api_versions.wraps("3.32")
+ def set_log_levels(self, level, binary, server, prefix):
+ """Set log level for services."""
+ body = {'level': level, 'binary': binary, 'server': server,
+ 'prefix': prefix}
+ return self._update("/os-services/set-log", body)
+
+ @api_versions.wraps("3.32")
+ def get_log_levels(self, binary, server, prefix):
+ """Get log levels for services."""
+ body = {'binary': binary, 'server': server, 'prefix': prefix}
+ response = self._update("/os-services/get-log", body)
+
+ log_levels = []
+ for entry in response['log_levels']:
+ entry_levels = sorted(entry['levels'].items(), key=lambda x: x[0])
+ for prefix, level in entry_levels:
+ log_dict = {'binary': entry['binary'], 'host': entry['host'],
+ 'prefix': prefix, 'level': level}
+ log_levels.append(LogLevel(self, log_dict, loaded=True))
+ return log_levels
diff --git a/cinderclient/v3/shell.py b/cinderclient/v3/shell.py
index 3b73b15..a389f09 100644
--- a/cinderclient/v3/shell.py
+++ b/cinderclient/v3/shell.py
@@ -1922,3 +1922,44 @@ def do_version_list(cs, args):
print("\nServer supported API versions:")
utils.print_list(result, columns)
+
+
+@api_versions.wraps('3.32')
+@utils.arg('level',
+ metavar='<log-level>',
+ choices=('INFO', 'WARNING', 'ERROR', 'DEBUG',
+ 'info', 'warning', 'error', 'debug'),
+ help='Desired log level.')
+@utils.arg('--binary',
+ choices=('', '*', 'cinder-api', 'cinder-volume', 'cinder-scheduler',
+ 'cinder-backup'),
+ default='',
+ help='Binary to change.')
+@utils.arg('--server',
+ default='',
+ help='Host or cluster value for service.')
+@utils.arg('--prefix',
+ default='',
+ help='Prefix for the log. ie: "cinder.volume.drivers.".')
+def do_service_set_log(cs, args):
+ cs.services.set_log_levels(args.level, args.binary, args.server,
+ args.prefix)
+
+
+@api_versions.wraps('3.32')
+@utils.arg('--binary',
+ choices=('', '*', 'cinder-api', 'cinder-volume', 'cinder-scheduler',
+ 'cinder-backup'),
+ default='',
+ help='Binary to query.')
+@utils.arg('--server',
+ default='',
+ help='Host or cluster value for service.')
+@utils.arg('--prefix',
+ default='',
+ help='Prefix for the log. ie: "sqlalchemy.".')
+def do_service_get_log(cs, args):
+ log_levels = cs.services.get_log_levels(args.binary, args.server,
+ args.prefix)
+ columns = ('Binary', 'Host', 'Prefix', 'Level')
+ utils.print_list(log_levels, columns)
diff --git a/releasenotes/notes/service_dynamic_log-bd81d93c73fc1570.yaml b/releasenotes/notes/service_dynamic_log-bd81d93c73fc1570.yaml
new file mode 100644
index 0000000..e71c7db
--- /dev/null
+++ b/releasenotes/notes/service_dynamic_log-bd81d93c73fc1570.yaml
@@ -0,0 +1,6 @@
+---
+features:
+ - |
+ Support microversion 3.32 that allows dynamically changing and querying
+ Cinder services' log levels with ``service-set-log`` and
+ ``service-get-log`` commands.