Revonzy Mini Shell
# This file is part of cloud-init. See LICENSE file for license information.
import calendar
from datetime import datetime
import sys
from cloudinit import util
stage_to_description = {
'finished': 'finished running cloud-init',
'init-local': 'starting search for local datasources',
'init-network': 'searching for network datasources',
'init': 'searching for network datasources',
'modules-config': 'running config modules',
'modules-final': 'finalizing modules',
'modules': 'running modules for',
'single': 'running single module ',
}
# logger's asctime format
CLOUD_INIT_ASCTIME_FMT = "%Y-%m-%d %H:%M:%S,%f"
# journctl -o short-precise
CLOUD_INIT_JOURNALCTL_FMT = "%b %d %H:%M:%S.%f %Y"
# other
DEFAULT_FMT = "%b %d %H:%M:%S %Y"
def parse_timestamp(timestampstr):
# default syslog time does not include the current year
months = [calendar.month_abbr[m] for m in range(1, 13)]
if timestampstr.split()[0] in months:
# Aug 29 22:55:26
FMT = DEFAULT_FMT
if '.' in timestampstr:
FMT = CLOUD_INIT_JOURNALCTL_FMT
dt = datetime.strptime(timestampstr + " " +
str(datetime.now().year),
FMT)
timestamp = dt.strftime("%s.%f")
elif "," in timestampstr:
# 2016-09-12 14:39:20,839
dt = datetime.strptime(timestampstr, CLOUD_INIT_ASCTIME_FMT)
timestamp = dt.strftime("%s.%f")
else:
# allow date(1) to handle other formats we don't expect
timestamp = parse_timestamp_from_date(timestampstr)
return float(timestamp)
def parse_timestamp_from_date(timestampstr):
out, _ = util.subp(['date', '+%s.%3N', '-d', timestampstr])
timestamp = out.strip()
return float(timestamp)
def parse_ci_logline(line):
# Stage Starts:
# Cloud-init v. 0.7.7 running 'init-local' at \
# Fri, 02 Sep 2016 19:28:07 +0000. Up 1.0 seconds.
# Cloud-init v. 0.7.7 running 'init' at \
# Fri, 02 Sep 2016 19:28:08 +0000. Up 2.0 seconds.
# Cloud-init v. 0.7.7 finished at
# Aug 29 22:55:26 test1 [CLOUDINIT] handlers.py[DEBUG]: \
# finish: modules-final: SUCCESS: running modules for final
# 2016-08-30T21:53:25.972325+00:00 y1 [CLOUDINIT] handlers.py[DEBUG]: \
# finish: modules-final: SUCCESS: running modules for final
#
# Nov 03 06:51:06.074410 x2 cloud-init[106]: [CLOUDINIT] util.py[DEBUG]: \
# Cloud-init v. 0.7.8 running 'init-local' at \
# Thu, 03 Nov 2016 06:51:06 +0000. Up 1.0 seconds.
#
# 2017-05-22 18:02:01,088 - util.py[DEBUG]: Cloud-init v. 0.7.9 running \
# 'init-local' at Mon, 22 May 2017 18:02:01 +0000. Up 2.0 seconds.
separators = [' - ', ' [CLOUDINIT] ']
found = False
for sep in separators:
if sep in line:
found = True
break
if not found:
return None
(timehost, eventstr) = line.split(sep)
# journalctl -o short-precise
if timehost.endswith(":"):
timehost = " ".join(timehost.split()[0:-1])
if "," in timehost:
timestampstr, extra = timehost.split(",")
timestampstr += ",%s" % extra.split()[0]
if ' ' in extra:
hostname = extra.split()[-1]
else:
hostname = timehost.split()[-1]
timestampstr = timehost.split(hostname)[0].strip()
if 'Cloud-init v.' in eventstr:
event_type = 'start'
if 'running' in eventstr:
stage_and_timestamp = eventstr.split('running')[1].lstrip()
event_name, _ = stage_and_timestamp.split(' at ')
event_name = event_name.replace("'", "").replace(":", "-")
if event_name == "init":
event_name = "init-network"
else:
# don't generate a start for the 'finished at' banner
return None
event_description = stage_to_description[event_name]
else:
(_pymodloglvl, event_type, event_name) = eventstr.split()[0:3]
event_description = eventstr.split(event_name)[1].strip()
event = {
'name': event_name.rstrip(":"),
'description': event_description,
'timestamp': parse_timestamp(timestampstr),
'origin': 'cloudinit',
'event_type': event_type.rstrip(":"),
}
if event['event_type'] == "finish":
result = event_description.split(":")[0]
desc = event_description.split(result)[1].lstrip(':').strip()
event['result'] = result
event['description'] = desc.strip()
return event
def dump_events(cisource=None, rawdata=None):
events = []
event = None
CI_EVENT_MATCHES = ['start:', 'finish:', 'Cloud-init v.']
if not any([cisource, rawdata]):
raise ValueError('Either cisource or rawdata parameters are required')
if rawdata:
data = rawdata.splitlines()
else:
data = cisource.readlines()
for line in data:
for match in CI_EVENT_MATCHES:
if match in line:
try:
event = parse_ci_logline(line)
except ValueError:
sys.stderr.write('Skipping invalid entry\n')
if event:
events.append(event)
return events, data
def main():
if len(sys.argv) > 1:
cisource = open(sys.argv[1])
else:
cisource = sys.stdin
return util.json_dumps(dump_events(cisource))
if __name__ == "__main__":
print(main())
EliteHackz.ORG
Revonzy Mini Shell
root@revonzy.com