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
This commit is contained in:
parent
eaee84097a
commit
6a00d30e96
cinderclient
releasenotes/notes
@ -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
|
||||
#
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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.
|
Loading…
x
Reference in New Issue
Block a user