"""
RosConfig - file ``/var/lib/pcp/config/pmlogger/config.ros``
============================================================
This class provides parsing for the files:
``/var/lib/pcp/config/pmlogger/config.ros``
"""
from insights import parser, Parser
from insights.specs import Specs
from insights.parsr import EOF, EOL, Char, Literal, Many, OneLineComment, Opt, QuotedString, String, WSChar
import string
# https://man7.org/linux/man-pages/man1/pmlogger.1.html#CONFIGURATION_FILE_SYNTAX
WS = Many(WSChar | EOL | OneLineComment("#"))
Log = WS >> Literal("log") << WS
MandatoryOn = WS >> Literal("mandatory on") << WS
MandatoryOff = WS >> Literal("mandatory off") << WS
MandatoryMaybe = WS >> Literal("mandatory maybe") << WS
AdvisoryOn = WS >> Literal("advisory on") << WS
AdvisoryOff = WS >> Literal("advisory off") << WS
Once = WS >> Literal("once") << WS
Default = WS >> Literal("default") << WS
Every = WS >> Literal("every") << WS
UnsignedInt = String(string.digits).map(int)
TimeUnits = WS >> String(string.ascii_letters) << WS
Freq = Opt(Every) >> (UnsignedInt + TimeUnits)
Interval = Once | Default | Freq
OnStates = MandatoryOn | AdvisoryOn
OtherStates = MandatoryMaybe | MandatoryOff | AdvisoryOff
Preamble = Opt(Log) >> ((OnStates + Interval) | OtherStates)
LeftBrace = WS >> Char("{") << WS
RightBrace = WS >> Char("}") << WS
Comma = WS >> Char(",") << WS
Name = WS >> String(string.ascii_letters + string.digits + "-._") << WS
LeftBracket = WS >> Char('[') << WS
RightBracket = WS >> Char(']') << WS
InstanceName = QuotedString | UnsignedInt | Name
InstanceNames = LeftBracket >> InstanceName.sep_by(Comma | WS) << RightBracket
MetricSpec = Name + Opt(InstanceNames, default=[])
OneMetricSpec = MetricSpec.map(lambda s: [s])
MultipleMetricSpecs = LeftBrace >> MetricSpec.sep_by(Comma | WS) << RightBrace
MetricSpecs = (OneMetricSpec | MultipleMetricSpecs).map(dict)
LogSpec = Preamble + MetricSpecs
LogSpecs = Many(LogSpec)
AccessHeader = WS >> Literal("[access]") << WS
Allow = WS >> Literal("allow") << WS
Disallow = WS >> Literal("disallow") << WS
AllowDisallow = Allow | Disallow
EnquireOp = WS >> Literal("enquire") << WS
AdvisoryOp = WS >> Literal("advisory") << WS
MandatoryOp = WS >> Literal("mandatory") << WS
AllExceptOp = WS >> Literal("all except") << WS
AllOp = WS >> Literal("all") << WS
Colon = WS >> Literal(":") << WS
Host = String(string.ascii_letters + string.digits + ".*:\"")
HostList = WS >> Host.sep_by(Comma) << WS
Operation = EnquireOp | AdvisoryOp | MandatoryOp | AllExceptOp | AllOp
OperationList = WS >> Operation.sep_by(Comma | WS) << WS
Semicolon = WS >> Char(";") << WS
AccessRule = AllowDisallow + HostList + Colon + OperationList << Semicolon
AccessRules = Many(AccessRule)
AccessControl = AccessHeader + AccessRules
Doc = LogSpecs + Opt(AccessControl)
parse = Doc << EOF
[docs]@parser(Specs.ros_config)
class RosConfig(Parser):
"""
Sample input data is in the format::
log mandatory on default {
mem.util.used
mem.physmem
kernel.all.cpu.user
kernel.all.cpu.sys
kernel.all.cpu.nice
kernel.all.cpu.steal
kernel.all.cpu.idle
kernel.all.cpu.wait.total
disk.all.total
mem.util.cached
mem.util.bufmem
mem.util.free
}
[access]
disallow .* : all;
disallow :* : all;
allow local:* : enquire;
Examples:
>>> type(ros_input)
<class 'insights.parsers.ros_config.RosConfig'>
>>> ros_input.rules[0]['allow_disallow']
'disallow'
>>> ros_input.rules[0]['hostlist']
['.*']
>>> ros_input.rules[0]['operationlist']
['all']
>>> ros_input.specs[0].get('state')
'mandatory on'
>>> ros_input.specs[0].get('metrics')['mem.util.used']
[]
>>> ros_input.specs[0].get('metrics')['kernel.all.cpu.user']
[]
>>> ros_input.specs[0].get('logging_interval')
'default'
Attributes:
data(list): All parsed options and log files are stored in this
list.
specs(list of dicts): List of the ROS specifications present in
config.ros file.
rules(list of dicts): List of access control rules applied for
config.ros file.
"""
[docs] def parse_content(self, content):
self.data = parse("\n".join(content))
self.specs = []
specifications = self.data[0]
for spec in specifications:
state = spec[0][0]
logging_interval = spec[0][1] if state.endswith('on') else None
self.specs.append({'state': state, 'logging_interval': logging_interval, 'metrics': spec[1]})
access_rules = self.data[1][1]
self.rules = []
for rule in access_rules:
self.rules.append({'allow_disallow': rule[0], 'hostlist': rule[1], 'operationlist': rule[3]})