"""
Reports on automatic installation activity by examining the logs in
/var/log/cobbler.
"""
from builtins import object
from past.utils import old_div
import glob
import time
import gzip
import re
from cobbler import clogger
# ARRAY INDEXES
MOST_RECENT_START = 0
MOST_RECENT_STOP = 1
MOST_RECENT_TARGET = 2
SEEN_START = 3
SEEN_STOP = 4
STATE = 5
[docs]class CobblerStatusReport(object):
def __init__(self, collection_mgr, mode, logger=None):
"""
Constructor
"""
self.collection_mgr = collection_mgr
self.settings = collection_mgr.settings()
self.ip_data = {}
self.mode = mode
if logger is None:
logger = clogger.Logger()
self.logger = logger
# -------------------------------------------------------
[docs] def scan_logfiles(self):
"""
Scan the install log-files - starting with the oldest file.
:return:
"""
unsorted_files = glob.glob("/var/log/cobbler/install.log*")
files_dict = dict()
log_id_re = re.compile(r'install.log.(\d+)')
for fname in unsorted_files:
id_match = log_id_re.search(fname)
if id_match:
files_dict[int(id_match.group(1))] = fname
files = list()
sorted_ids = sorted(files_dict, key=files_dict.get, reverse=True)
for file_id in sorted_ids:
files.append(files_dict[file_id])
if '/var/log/cobbler/install.log' in unsorted_files:
files.append('/var/log/cobbler/install.log')
for fname in files:
if fname.endswith('.gz'):
fd = gzip.open(fname)
else:
fd = open(fname)
data = fd.read()
for line in data.split("\n"):
tokens = line.split()
if len(tokens) == 0:
continue
(profile_or_system, name, ip, start_or_stop, ts) = tokens
self.catalog(profile_or_system, name, ip, start_or_stop, ts)
fd.close()
# ------------------------------------------------------
[docs] def catalog(self, profile_or_system, name, ip, start_or_stop, ts):
ip_data = self.ip_data
if ip not in ip_data:
ip_data[ip] = [-1, -1, "?", 0, 0, "?"]
elem = ip_data[ip]
ts = float(ts)
mrstart = elem[MOST_RECENT_START]
mrstop = elem[MOST_RECENT_STOP]
mrtarg = elem[MOST_RECENT_TARGET]
if start_or_stop == "start":
if mrstart < ts:
mrstart = ts
mrtarg = "%s:%s" % (profile_or_system, name)
elem[SEEN_START] += 1
if start_or_stop == "stop":
if mrstop < ts:
mrstop = ts
mrtarg = "%s:%s" % (profile_or_system, name)
elem[SEEN_STOP] += 1
elem[MOST_RECENT_START] = mrstart
elem[MOST_RECENT_STOP] = mrstop
elem[MOST_RECENT_TARGET] = mrtarg
# -------------------------------------------------------
[docs] def process_results(self):
# FIXME: this should update the times here
tnow = int(time.time())
for ip in list(self.ip_data.keys()):
elem = self.ip_data[ip]
start = int(elem[MOST_RECENT_START])
stop = int(elem[MOST_RECENT_STOP])
if (stop > start):
elem[STATE] = "finished"
else:
delta = tnow - start
min = old_div(delta, 60)
sec = delta % 60
if min > 100:
elem[STATE] = "unknown/stalled"
else:
elem[STATE] = "installing (%sm %ss)" % (min, sec)
return self.ip_data
[docs] def get_printable_results(self):
format = "%-15s|%-20s|%-17s|%-17s"
ip_data = self.ip_data
ips = list(ip_data.keys())
ips.sort()
line = (
"ip",
"target",
"start",
"state",
)
buf = format % line
for ip in ips:
elem = ip_data[ip]
if elem[MOST_RECENT_START] > -1:
start = time.ctime(elem[MOST_RECENT_START])
else:
start = "Unknown"
line = (
ip,
elem[MOST_RECENT_TARGET],
start,
elem[STATE]
)
buf += "\n" + format % line
return buf
# -------------------------------------------------------
[docs] def run(self):
"""
Calculate and print a automatic installation status report.
"""
self.scan_logfiles()
results = self.process_results()
if self.mode == "text":
return self.get_printable_results()
else:
return results