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}
|
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
|
# resource filters
|
||||||
#
|
#
|
||||||
|
@ -41,3 +41,45 @@ class ServicesTest(utils.TestCase):
|
|||||||
client = fakes.FakeClient(version_header='3.0')
|
client = fakes.FakeClient(version_header='3.0')
|
||||||
svs = client.services.server_api_version()
|
svs = client.services.server_api_version()
|
||||||
[self.assertIsInstance(s, services.Service) for s in svs]
|
[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 fixtures
|
||||||
import mock
|
import mock
|
||||||
from requests_mock.contrib import fixture as requests_mock_fixture
|
from requests_mock.contrib import fixture as requests_mock_fixture
|
||||||
|
import six
|
||||||
|
|
||||||
from cinderclient import client
|
from cinderclient import client
|
||||||
from cinderclient import exceptions
|
from cinderclient import exceptions
|
||||||
@ -788,3 +789,78 @@ class ShellTest(utils.TestCase):
|
|||||||
self.run_command(cmd)
|
self.run_command(cmd)
|
||||||
expected = {'list_replication_targets': {}}
|
expected = {'list_replication_targets': {}}
|
||||||
self.assert_called('POST', '/groups/1234/action', body=expected)
|
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 api_versions
|
||||||
|
from cinderclient import base
|
||||||
from cinderclient.v2 import services
|
from cinderclient.v2 import services
|
||||||
|
|
||||||
Service = services.Service
|
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):
|
class ServiceManager(services.ServiceManager):
|
||||||
@api_versions.wraps("3.0")
|
@api_versions.wraps("3.0")
|
||||||
def server_api_version(self):
|
def server_api_version(self):
|
||||||
@ -36,3 +43,25 @@ class ServiceManager(services.ServiceManager):
|
|||||||
return self._get_with_base_url("", response_key='versions')
|
return self._get_with_base_url("", response_key='versions')
|
||||||
except LookupError:
|
except LookupError:
|
||||||
return []
|
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:")
|
print("\nServer supported API versions:")
|
||||||
utils.print_list(result, columns)
|
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