Skip to content

Commit

Permalink
Merge pull request #939 from aleksei-burlakov/feature/log-dir
Browse files Browse the repository at this point in the history
Dev: Parametrize the log dir
  • Loading branch information
liangxin1300 authored Mar 21, 2022
2 parents aa92b3f + dadec52 commit 8cf6a9d
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 27 deletions.
1 change: 1 addition & 0 deletions crmsh/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@
"timeout", "timestamp-format"
)
trace_ra_attr = "trace_ra"
trace_dir_attr = "trace_dir"
score_types = {'advisory': '0', 'mandatory': 'INFINITY'}
boolean_ops = ('or', 'and')
binary_ops = ('lt', 'gt', 'lte', 'gte', 'eq', 'ne')
Expand Down
62 changes: 47 additions & 15 deletions crmsh/ui_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -635,70 +635,101 @@ def _get_trace_rsc(self, rsc_id):
return None
return rsc

def _add_trace_op(self, rsc, op, interval):
def _add_trace_op(self, rsc, op, interval, dir):
from lxml import etree
n = etree.Element('op')
n.set('name', op)
n.set('interval', interval)
n.set(constants.trace_ra_attr, '1')
if dir is not None:
n.set(constants.trace_dir_attr, dir)
return rsc.add_operation(n)

def _trace_resource(self, context, rsc_id, rsc):
def _trace_resource(self, context, rsc_id, rsc, dir):
"""Enable RA tracing for a specified resource."""
op_nodes = rsc.node.xpath('operations/op')

def trace(name):
for o in op_nodes:
if o.get('name') == name:
return
if not self._add_trace_op(rsc, name, '0'):
if not self._add_trace_op(rsc, name, '0', dir):
context.fatal_error("Failed to add trace for %s:%s" % (rsc_id, name))
trace('start')
trace('stop')
if xmlutil.is_ms_or_promotable_clone(rsc.node):
trace('promote')
trace('demote')
for op_node in op_nodes:
rsc.set_op_attr(op_node, constants.trace_ra_attr, "1")
op_node = rsc.set_op_attr(op_node, constants.trace_ra_attr, "1")
if dir is not None:
rsc.set_op_attr(op_node, constants.trace_dir_attr, dir)

def _trace_op(self, context, rsc_id, rsc, op):
def _trace_op(self, context, rsc_id, rsc, op, dir):
"""Enable RA tracing for a specified operation."""
op_nodes = rsc.node.xpath('operations/op[@name="%s"]' % (op))
if not op_nodes:
if op == 'monitor':
context.fatal_error("No monitor operation configured for %s" % (rsc_id))
if not self._add_trace_op(rsc, op, '0'):
if not self._add_trace_op(rsc, op, '0', dir):
context.fatal_error("Failed to add trace for %s:%s" % (rsc_id, op))
for op_node in op_nodes:
rsc.set_op_attr(op_node, constants.trace_ra_attr, "1")
op_node = rsc.set_op_attr(op_node, constants.trace_ra_attr, "1")
if dir is not None:
rsc.set_op_attr(op_node, constants.trace_dir_attr, dir)

def _trace_op_interval(self, context, rsc_id, rsc, op, interval):
def _trace_op_interval(self, context, rsc_id, rsc, op, interval, dir):
"""Enable RA tracing for an operation with the exact interval."""
op_node = xmlutil.find_operation(rsc.node, op, interval)
if op_node is None and utils.crm_msec(interval) != 0:
context.fatal_error("Operation %s with interval %s not found in %s" % (op, interval, rsc_id))
if op_node is None:
if not self._add_trace_op(rsc, op, interval):
if not self._add_trace_op(rsc, op, interval, dir):
context.fatal_error("Failed to add trace for %s:%s" % (rsc_id, op))
else:
rsc.set_op_attr(op_node, constants.trace_ra_attr, "1")
op_node = rsc.set_op_attr(op_node, constants.trace_ra_attr, "1")
if dir is not None:
rsc.set_op_attr(op_node, constants.trace_dir_attr, dir)

@command.completers(compl.primitives, _raoperations)
def do_trace(self, context, rsc_id, op=None, interval=None):
'usage: trace <rsc> [<op>] [<interval>]'
def do_trace(self, context, rsc_id, *args):
'usage: trace <rsc> [<op>] [<interval>] [<log-dir>]'
usage='usage: trace <rsc> [<op>] [<interval>] [<log-dir>]'
rsc = self._get_trace_rsc(rsc_id)
if not rsc:
return False

argl = list(args)
force = "force" in utils.fetch_opts(argl, ["force"]) or config.core.force
if len(argl) > 3:
context.fatal_error(usage)
op=None
interval=None
dir=None
for arg in argl:
if arg[0] == '/':
if dir is not None:
context.fatal_error(usage)
dir = arg
elif arg.isnumeric():
if interval is not None:
context.fatal_error(usage)
interval = arg
else:
if op is not None:
context.fatal_error(usage)
op = arg

if op == "probe":
op = "monitor"
if interval is None:
interval = "0"
if op is None:
self._trace_resource(context, rsc_id, rsc)
self._trace_resource(context, rsc_id, rsc, dir)
elif interval is None:
self._trace_op(context, rsc_id, rsc, op)
self._trace_op(context, rsc_id, rsc, op, dir)
else:
self._trace_op_interval(context, rsc_id, rsc, op, interval)
self._trace_op_interval(context, rsc_id, rsc, op, interval, dir)
if not cib_factory.commit():
return False
rsc_type = rsc.node.get("type")
Expand All @@ -712,6 +743,7 @@ def do_trace(self, context, rsc_id, op=None, interval=None):
def _remove_trace(self, rsc, op_node):
logger.debug("op_node: %s", xmlutil.xml_tostring(op_node))
op_node = rsc.del_op_attr(op_node, constants.trace_ra_attr)
op_node = rsc.del_op_attr(op_node, constants.trace_dir_attr)
if rsc.is_dummy_operation(op_node):
rsc.del_operation(op_node)

Expand Down
12 changes: 6 additions & 6 deletions doc/crm.8.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1963,10 +1963,10 @@ stop <rsc> [<rsc> ...]
[[cmdhelp_resource_trace,start RA tracing]]
==== `trace`

Start tracing RA for the given operation. The trace files are
stored in `$HA_VARLIB/trace_ra`. If the operation to be traced is
monitor, note that the number of trace files can grow very
quickly.
Start tracing RA for the given operation. When `[<log-dir>]`
is not specified the trace files are stored in `$HA_VARLIB/trace_ra`.
If the operation to be traced is monitor, note that the number
of trace files can grow very quickly.

If no operation name is given, crmsh will attempt to trace all
operations for the RA. This includes any configured operations, start
Expand All @@ -1982,14 +1982,14 @@ unless an error occurred.

Usage:
...............
trace <rsc> [<op> [<interval>] ]
trace <rsc> [<op> [<interval>] [<log-dir>]]
...............
Example:
...............
trace fs start
trace webserver
trace webserver probe
trace fs monitor 0
trace fs monitor 0 /var/log/foo/bar
...............

[[cmdhelp_resource_unmanage,put a resource into unmanaged mode]]
Expand Down
12 changes: 6 additions & 6 deletions test/unittests/test_ratrace.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def test_ratrace_resource(self, mock_error):
obj = self.factory.create_from_node(etree.fromstring(xml))

# Trace the resource.
RscMgmt()._trace_resource(self.context, obj.obj_id, obj)
RscMgmt()._trace_resource(self.context, obj.obj_id, obj, '/var/lib/heartbeat/trace_ra')
self.assertEqual(obj.node.xpath('operations/op/@id'), ['r1-start-0', 'r1-stop-0'])
self.assertEqual(obj.node.xpath('operations/op[@id="r1-start-0"]/instance_attributes/nvpair[@name="trace_ra"]/@value'), ['1'])
self.assertEqual(obj.node.xpath('operations/op[@id="r1-stop-0"]/instance_attributes/nvpair[@name="trace_ra"]/@value'), ['1'])
Expand All @@ -50,7 +50,7 @@ def test_ratrace_op(self, mock_error):
obj = self.factory.create_from_node(etree.fromstring(xml))

# Trace the operation.
RscMgmt()._trace_op(self.context, obj.obj_id, obj, 'monitor')
RscMgmt()._trace_op(self.context, obj.obj_id, obj, 'monitor', '/var/lib/heartbeat/trace_ra')
self.assertEqual(obj.node.xpath('operations/op/@id'), ['r1-monitor-10'])
self.assertEqual(obj.node.xpath('operations/op[@id="r1-monitor-10"]/instance_attributes/nvpair[@name="trace_ra"]/@value'), ['1'])

Expand All @@ -73,14 +73,14 @@ def test_ratrace_new(self, mock_error):

# Trace a regular operation that is not yet defined in CIB. The request
# should succeed and introduce an op node for the operation.
RscMgmt()._trace_op(self.context, obj.obj_id, obj, 'start')
RscMgmt()._trace_op(self.context, obj.obj_id, obj, 'start', '/var/lib/heartbeat/trace_ra')
self.assertEqual(obj.node.xpath('operations/op/@id'), ['r1-start-0'])
self.assertEqual(obj.node.xpath('operations/op[@id="r1-start-0"]/instance_attributes/nvpair[@name="trace_ra"]/@value'), ['1'])

# Try tracing the monitor operation in the same way. The request should
# get rejected because no explicit interval is specified.
with self.assertRaises(ValueError) as err:
RscMgmt()._trace_op(self.context, obj.obj_id, obj, 'monitor')
RscMgmt()._trace_op(self.context, obj.obj_id, obj, 'monitor', '/var/lib/heartbeat/trace_ra')
self.assertEqual(str(err.exception), "No monitor operation configured for r1")

@mock.patch('logging.Logger.error')
Expand All @@ -95,7 +95,7 @@ def test_ratrace_op_stateful(self, mock_error):
obj = self.factory.create_from_node(etree.fromstring(xml))

# Trace the operation.
RscMgmt()._trace_op(self.context, obj.obj_id, obj, 'monitor')
RscMgmt()._trace_op(self.context, obj.obj_id, obj, 'monitor', '/var/lib/heartbeat/trace_ra')
self.assertEqual(obj.node.xpath('operations/op/@id'), ['r1-monitor-10', 'r1-monitor-11'])
self.assertEqual(obj.node.xpath('operations/op[@id="r1-monitor-10"]/instance_attributes/nvpair[@name="trace_ra"]/@value'), ['1'])
self.assertEqual(obj.node.xpath('operations/op[@id="r1-monitor-11"]/instance_attributes/nvpair[@name="trace_ra"]/@value'), ['1'])
Expand All @@ -116,7 +116,7 @@ def test_ratrace_op_interval(self, mock_error):
obj = self.factory.create_from_node(etree.fromstring(xml))

# Trace the operation.
RscMgmt()._trace_op_interval(self.context, obj.obj_id, obj, 'monitor', '10')
RscMgmt()._trace_op_interval(self.context, obj.obj_id, obj, 'monitor', '10', '/var/lib/heartbeat/trace_ra')
self.assertEqual(obj.node.xpath('operations/op/@id'), ['r1-monitor-10'])
self.assertEqual(obj.node.xpath('operations/op[@id="r1-monitor-10"]/instance_attributes/nvpair[@name="trace_ra"]/@value'), ['1'])

Expand Down

0 comments on commit 8cf6a9d

Please sign in to comment.