summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLingxian Kong <anlin.kong@gmail.com>2019-12-16 14:31:13 +1300
committerLingxian Kong <anlin.kong@gmail.com>2019-12-16 15:21:25 +1300
commitadde0d0bedb5783be2c03bd9412d70684bff0612 (patch)
tree73ccbe4f16a10f2a529bbe1305db2692f03469b0
parentf5a57732a95e130689f6c5a16794e42266b206b0 (diff)
downloadpython-troveclient-adde0d0bedb5783be2c03bd9412d70684bff0612.tar.gz
Support log tail/save for instance
Support to show log content and save instance log files: openstack database log tail [--lines LINES] <instance> <log_name> openstack database log save [--file FILE] <instance> <log_name> Change-Id: I2a4eecca663f9126f770fae4c4be28b3667f91c4
-rw-r--r--releasenotes/notes/ussuri-02-instance-log-tail-save-0b267a761faa11ea.yaml9
-rw-r--r--setup.cfg2
-rw-r--r--troveclient/osc/v1/database_logs.py97
-rw-r--r--troveclient/v1/instances.py30
-rw-r--r--troveclient/v1/shell.py8
5 files changed, 125 insertions, 21 deletions
diff --git a/releasenotes/notes/ussuri-02-instance-log-tail-save-0b267a761faa11ea.yaml b/releasenotes/notes/ussuri-02-instance-log-tail-save-0b267a761faa11ea.yaml
new file mode 100644
index 0000000..5516d14
--- /dev/null
+++ b/releasenotes/notes/ussuri-02-instance-log-tail-save-0b267a761faa11ea.yaml
@@ -0,0 +1,9 @@
+---
+features:
+ - |
+ Support to show log content and save instance log files:
+
+ .. code-block:: console
+
+ openstack database log tail [--lines LINES] <instance> <log_name>
+ openstack database log save [--file FILE] <instance> <log_name>
diff --git a/setup.cfg b/setup.cfg
index 57c55bc..a6a35a8 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -81,6 +81,8 @@ openstack.database.v1 =
database_log_list = troveclient.osc.v1.database_logs:ListDatabaseLogs
database_log_set = troveclient.osc.v1.database_logs:SetDatabaseInstanceLog
database_log_show = troveclient.osc.v1.database_logs:ShowDatabaseInstanceLog
+ database_log_tail = troveclient.osc.v1.database_logs:ShowDatabaseInstanceLogContents
+ database_log_save = troveclient.osc.v1.database_logs:SaveDatabaseInstanceLog
database_quota_show = troveclient.osc.v1.database_quota:ShowDatabaseQuota
database_quota_update = troveclient.osc.v1.database_quota:UpdateDatabaseQuota
database_root_disable = troveclient.osc.v1.database_root:DisableDatabaseRoot
diff --git a/troveclient/osc/v1/database_logs.py b/troveclient/osc/v1/database_logs.py
index eb342c3..d43d331 100644
--- a/troveclient/osc/v1/database_logs.py
+++ b/troveclient/osc/v1/database_logs.py
@@ -10,12 +10,13 @@
# License for the specific language governing permissions and limitations
# under the License.
-"""Database v1 Logs action implementations"""
+from __future__ import print_function
from osc_lib.command import command
from osc_lib import utils as osc_utils
import six
+from troveclient import exceptions
from troveclient.i18n import _
@@ -134,3 +135,97 @@ class ShowDatabaseInstanceLog(command.ShowOne):
result = log_info._info
return zip(*sorted(six.iteritems(result)))
+
+
+class ShowDatabaseInstanceLogContents(command.Command):
+ _description = _("Show the content of log file.")
+
+ def get_parser(self, prog_name):
+ parser = super(ShowDatabaseInstanceLogContents, self).get_parser(
+ prog_name)
+ parser.add_argument(
+ 'instance',
+ metavar='<instance>',
+ type=str,
+ help=_('Id or Name of the instance.')
+ )
+ parser.add_argument(
+ 'log_name',
+ metavar='<log_name>',
+ type=str,
+ help=_('Name of log to operate.')
+ )
+ parser.add_argument(
+ '--lines', default=50, type=int,
+ help="The number of log lines can be shown in batch.",
+ )
+
+ return parser
+
+ def take_action(self, parsed_args):
+ db_instances = self.app.client_manager.database.instances
+ instance = osc_utils.find_resource(db_instances,
+ parsed_args.instance)
+
+ try:
+ log_gen = db_instances.log_generator(instance,
+ parsed_args.log_name,
+ lines=parsed_args.lines)
+ for log_part in log_gen():
+ print(log_part, end="")
+ except exceptions.GuestLogNotFoundError:
+ print(
+ "ERROR: No published '%(log_name)s' log was found for "
+ "%(instance)s" % {'log_name': parsed_args.log_name,
+ 'instance': instance}
+ )
+ except Exception as ex:
+ error_msg = ex.message.split('\n')
+ print(error_msg[0])
+
+
+class SaveDatabaseInstanceLog(command.Command):
+ _description = _("Save the log file.")
+
+ def get_parser(self, prog_name):
+ parser = super(SaveDatabaseInstanceLog, self).get_parser(prog_name)
+ parser.add_argument(
+ 'instance',
+ metavar='<instance>',
+ type=str,
+ help=_('Id or Name of the instance.')
+ )
+ parser.add_argument(
+ 'log_name',
+ metavar='<log_name>',
+ type=str,
+ help=_('Name of log to operate.')
+ )
+ parser.add_argument(
+ '--file',
+ help="Path of file to save log to for instance.",
+ )
+
+ return parser
+
+ def take_action(self, parsed_args):
+ db_instances = self.app.client_manager.database.instances
+ instance = osc_utils.find_resource(db_instances,
+ parsed_args.instance)
+
+ try:
+ filepath = db_instances.log_save(instance,
+ parsed_args.log_name,
+ filename=parsed_args.file)
+ print(_('Log "%(log_name)s" written to %(file_name)s')
+ % {'log_name': parsed_args.log_name,
+ 'file_name': filepath})
+ except exceptions.GuestLogNotFoundError:
+ print(
+ "ERROR: No published '%(log_name)s' log was found for "
+ "%(instance)s" % {'log_name': parsed_args.log_name,
+ 'instance': instance}
+ )
+ except Exception as ex:
+ error_msg = ex.message.split('\n')
+ print(error_msg[0])
diff --git a/troveclient/v1/instances.py b/troveclient/v1/instances.py
index a122bc3..15725a3 100644
--- a/troveclient/v1/instances.py
+++ b/troveclient/v1/instances.py
@@ -412,9 +412,9 @@ class Instances(base.ManagerWithFind):
common.check_for_exceptions(resp, body, url)
return DatastoreLog(self, body['log'], loaded=True)
- def _get_container_info(self, instance, log_name, publish):
+ def _get_container_info(self, instance, log_name):
try:
- log_info = self.log_action(instance, log_name, publish=publish)
+ log_info = self.log_show(instance, log_name)
container = log_info.container
prefix = log_info.prefix
metadata_file = log_info.metafile
@@ -424,33 +424,33 @@ class Instances(base.ManagerWithFind):
raise exceptions.GuestLogNotFoundError()
raise
- def log_generator(self, instance, log_name, publish=None, lines=50,
- swift=None):
+ def log_generator(self, instance, log_name, lines=50, swift=None):
"""Return generator to yield the last <lines> lines of guest log.
:param instance: The :class:`Instance` (or its ID) of the database
instance to get the log for.
:param log_name: The name of <log> to publish
- :param publish: Publish updates before displaying log
:param lines: Display last <lines> lines of log (0 for all lines)
:param swift: Connection to swift
:rtype: generator function to yield log as chunks.
"""
-
if not swift:
swift = self._get_swift_client()
- def _log_generator(instance, log_name, publish, lines, swift):
+ def _log_generator(instance, log_name, lines, swift):
try:
container, prefix, metadata_file = self._get_container_info(
- instance, log_name, publish)
+ instance, log_name)
+
head, body = swift.get_container(container, prefix=prefix)
log_obj_to_display = []
+
if lines:
total_lines = lines
partial_results = False
parts = sorted(body, key=lambda obj: obj['last_modified'],
reverse=True)
+
for part in parts:
obj_hdrs = swift.head_object(container, part['name'])
obj_lines = int(obj_hdrs['x-object-meta-lines'])
@@ -461,13 +461,16 @@ class Instances(base.ManagerWithFind):
lines -= obj_lines
if not partial_results:
lines = total_lines
+
part = log_obj_to_display.pop(0)
hdrs, log_obj = swift.get_object(container, part['name'])
log_by_lines = log_obj.decode().splitlines()
yield "\n".join(log_by_lines[-1 * lines:]) + "\n"
else:
+ # Show all the logs
log_obj_to_display = sorted(
body, key=lambda obj: obj['last_modified'])
+
for log_part in log_obj_to_display:
headers, log_obj = swift.get_object(container,
log_part['name'])
@@ -477,20 +480,19 @@ class Instances(base.ManagerWithFind):
raise exceptions.GuestLogNotFoundError()
raise
- return lambda: _log_generator(instance, log_name, publish,
- lines, swift)
+ return lambda: _log_generator(instance, log_name, lines, swift)
- def log_save(self, instance, log_name, publish=None, filename=None):
+ def log_save(self, instance, log_name, filename=None):
"""Saves a guest log to a file.
:param instance: The :class:`Instance` (or its ID) of the database
instance to get the log for.
:param log_name: The name of <log> to publish
- :param publish: Publish updates before displaying log
:rtype: Filename to which log was saved
"""
- written_file = filename or (instance.name + '-' + log_name + ".log")
- log_gen = self.log_generator(instance, log_name, publish, 0)
+ written_file = filename or (
+ 'trove-' + instance.id + '-' + log_name + ".log")
+ log_gen = self.log_generator(instance, log_name, lines=0)
with open(written_file, 'w') as f:
for log_obj in log_gen():
f.write(log_obj)
diff --git a/troveclient/v1/shell.py b/troveclient/v1/shell.py
index bb6f2f6..1b72d31 100644
--- a/troveclient/v1/shell.py
+++ b/troveclient/v1/shell.py
@@ -2292,8 +2292,6 @@ def do_log_discard(cs, args):
@utils.arg('instance', metavar='<instance>',
help=_('Id or Name of the instance.'))
@utils.arg('log_name', metavar='<log_name>', help=_('Name of log to publish.'))
-@utils.arg('--publish', action='store_true', default=False,
- help=_('Publish latest entries from guest before display.'))
@utils.arg('--lines', metavar='<lines>', default=50, type=int,
help=_('Publish latest entries from guest before display.'))
@utils.service_type('database')
@@ -2302,7 +2300,7 @@ def do_log_tail(cs, args):
try:
instance = _find_instance(cs, args.instance)
log_gen = cs.instances.log_generator(instance, args.log_name,
- args.publish, args.lines)
+ args.lines)
for log_part in log_gen():
print(log_part, end="")
except exceptions.GuestLogNotFoundError:
@@ -2316,8 +2314,6 @@ def do_log_tail(cs, args):
@utils.arg('instance', metavar='<instance>',
help=_('Id or Name of the instance.'))
@utils.arg('log_name', metavar='<log_name>', help=_('Name of log to publish.'))
-@utils.arg('--publish', action='store_true', default=False,
- help=_('Publish latest entries from guest before display.'))
@utils.arg('--file', metavar='<file>', default=None,
help=_('Path of file to save log to for instance.'))
@utils.service_type('database')
@@ -2326,7 +2322,7 @@ def do_log_save(cs, args):
try:
instance = _find_instance(cs, args.instance)
filename = cs.instances.log_save(instance, args.log_name,
- args.publish, args.file)
+ filename=args.file)
print(_('Log "%(log_name)s" written to %(file_name)s')
% {'log_name': args.log_name,
'file_name': filename})