Add node log functions to API and CLI
This commit is contained in:
@ -19,6 +19,8 @@
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
import time
|
||||
|
||||
import pvc.cli_lib.ansiprint as ansiprint
|
||||
from pvc.cli_lib.common import call_api
|
||||
|
||||
@ -69,6 +71,91 @@ def node_domain_state(config, node, action, wait):
|
||||
return retstatus, response.json().get('message', '')
|
||||
|
||||
|
||||
def view_node_log(config, node, lines=100):
|
||||
"""
|
||||
Return node log lines from the API (and display them in a pager in the main CLI)
|
||||
|
||||
API endpoint: GET /node/{node}/log
|
||||
API arguments: lines={lines}
|
||||
API schema: {"name":"{node}","data":"{node_log}"}
|
||||
"""
|
||||
params = {
|
||||
'lines': lines
|
||||
}
|
||||
response = call_api(config, 'get', '/node/{node}/log'.format(node=node), params=params)
|
||||
|
||||
if response.status_code != 200:
|
||||
return False, response.json().get('message', '')
|
||||
|
||||
node_log = response.json()['data']
|
||||
|
||||
# Shrink the log buffer to length lines
|
||||
shrunk_log = node_log.split('\n')[-lines:]
|
||||
loglines = '\n'.join(shrunk_log)
|
||||
|
||||
return True, loglines
|
||||
|
||||
|
||||
def follow_node_log(config, node, lines=10):
|
||||
"""
|
||||
Return and follow node log lines from the API
|
||||
|
||||
API endpoint: GET /node/{node}/log
|
||||
API arguments: lines={lines}
|
||||
API schema: {"name":"{nodename}","data":"{node_log}"}
|
||||
"""
|
||||
# We always grab 500 to match the follow call, but only _show_ `lines` number
|
||||
params = {
|
||||
'lines': 500
|
||||
}
|
||||
response = call_api(config, 'get', '/node/{node}/log'.format(node=node), params=params)
|
||||
|
||||
if response.status_code != 200:
|
||||
return False, response.json().get('message', '')
|
||||
|
||||
# Shrink the log buffer to length lines
|
||||
node_log = response.json()['data']
|
||||
shrunk_log = node_log.split('\n')[-int(lines):]
|
||||
loglines = '\n'.join(shrunk_log)
|
||||
|
||||
# Print the initial data and begin following
|
||||
print(loglines, end='')
|
||||
|
||||
while True:
|
||||
# Grab the next line set (500 is a reasonable number of lines per second; any more are skipped)
|
||||
try:
|
||||
params = {
|
||||
'lines': 500
|
||||
}
|
||||
response = call_api(config, 'get', '/node/{node}/log'.format(node=node), params=params)
|
||||
new_node_log = response.json()['data']
|
||||
except Exception:
|
||||
break
|
||||
# Split the new and old log strings into constitutent lines
|
||||
old_node_loglines = node_log.split('\n')
|
||||
new_node_loglines = new_node_log.split('\n')
|
||||
# Set the node log to the new log value for the next iteration
|
||||
node_log = new_node_log
|
||||
# Remove the lines from the old log until we hit the first line of the new log; this
|
||||
# ensures that the old log is a string that we can remove from the new log entirely
|
||||
for index, line in enumerate(old_node_loglines, start=0):
|
||||
if line == new_node_loglines[0]:
|
||||
del old_node_loglines[0:index]
|
||||
break
|
||||
# Rejoin the log lines into strings
|
||||
old_node_log = '\n'.join(old_node_loglines)
|
||||
new_node_log = '\n'.join(new_node_loglines)
|
||||
# Remove the old lines from the new log
|
||||
diff_node_log = new_node_log.replace(old_node_log, "")
|
||||
# If there's a difference, print it out
|
||||
if diff_node_log:
|
||||
print(diff_node_log, end='')
|
||||
# Wait a second
|
||||
time.sleep(1)
|
||||
|
||||
return True, ''
|
||||
|
||||
|
||||
def node_info(config, node):
|
||||
"""
|
||||
Get information about node
|
||||
|
@ -540,6 +540,43 @@ def node_unflush(node, wait):
|
||||
cleanup(retcode, retmsg)
|
||||
|
||||
|
||||
###############################################################################
|
||||
# pvc node log
|
||||
###############################################################################
|
||||
@click.command(name='log', short_help='Show logs of a node.')
|
||||
@click.argument(
|
||||
'node'
|
||||
)
|
||||
@click.option(
|
||||
'-l', '--lines', 'lines', default=None, show_default=False,
|
||||
help='Display this many log lines from the end of the log buffer. [default: 1000; with follow: 10]'
|
||||
)
|
||||
@click.option(
|
||||
'-f', '--follow', 'follow', is_flag=True, default=False,
|
||||
help='Follow the log buffer; output may be delayed by a few seconds relative to the live system. The --lines value defaults to 10 for the initial output.'
|
||||
)
|
||||
@cluster_req
|
||||
def node_log(node, lines, follow):
|
||||
"""
|
||||
Show node logs of virtual machine DOMAIN on its current node in a pager or continuously. DOMAIN may be a UUID or name. Note that migrating a VM to a different node will cause the log buffer to be overwritten by entries from the new node.
|
||||
"""
|
||||
|
||||
# Set the default here so we can handle it
|
||||
if lines is None:
|
||||
if follow:
|
||||
lines = 10
|
||||
else:
|
||||
lines = 1000
|
||||
|
||||
if follow:
|
||||
retcode, retmsg = pvc_node.follow_node_log(config, node, lines)
|
||||
else:
|
||||
retcode, retmsg = pvc_node.view_node_log(config, node, lines)
|
||||
click.echo_via_pager(retmsg)
|
||||
retmsg = ''
|
||||
cleanup(retcode, retmsg)
|
||||
|
||||
|
||||
###############################################################################
|
||||
# pvc node info
|
||||
###############################################################################
|
||||
@ -4707,6 +4744,7 @@ cli_node.add_command(node_primary)
|
||||
cli_node.add_command(node_flush)
|
||||
cli_node.add_command(node_ready)
|
||||
cli_node.add_command(node_unflush)
|
||||
cli_node.add_command(node_log)
|
||||
cli_node.add_command(node_info)
|
||||
cli_node.add_command(node_list)
|
||||
|
||||
|
Reference in New Issue
Block a user