#!/usr/local/bin/python """ Version : 0.1.1 Date : 01/11/2006 Author : Gerrit Sere E-mail : gerrit.sere@coo.vlaanderen.be Info : Makes nice administration reports from legato nsradmin command Version : 0.1 - If a client is defiend in more than 1 group than leginfo.py -g group output wrong results - change code around lines 600 , schedule[actionMonth] """ import re import getopt import sys import os import datetime import copy class Legato: def __init__(self): self.nsrClients = [] self.nsrGroups = [] self.nsrLicenses = [] self.nsrPools = [] self.nsrSchedules = [] self.readLegato() def addClient(self,legatoType): self.nsrClients.append(legatoType) def addGroup(self,legatoType): legatoType['start time'] = legatoType['start time'].replace('"'," ") self.nsrGroups.append(legatoType) def addLicense(self,legatoType): legatoType['name'] = legatoType['name'].replace('\\',"") legatoType['name'] = legatoType['name'].replace('"',"") legatoType['name'] = legatoType['name'].strip() self.nsrLicenses.append(legatoType) def addPool(self,legatoType): self.nsrPools.append(legatoType) def addSchedule(self,legatoType): """ Transform some fields """ # print legatoType['action'] #--> "skip incr incr incr incr full skip " legatoType['action'] = legatoType['action'].replace('"'," ").split() # consolidate --> cons legatoType['action'] = [x[:4] for x in legatoType['action']] # Check the period overrideDate = {} if legatoType['period'] == "Month": # Store the origional text legatoType['_override'] = legatoType['override'] # You can't change these schedules # Calculate the dates for # "full first friday every month" and # "consolidate first friday every month" if "first friday every month" in legatoType['override']: year = datetime.datetime.today().year for y in range(year - 3,year + 6): for m in range(1,13): for d in range(1,8): date = datetime.date(y,m,d) if date.isoweekday() == 5: overrideDate[date.strftime("%m/%d/%Y")] = "" # Calculate dates for every quarter 1 jan, 1 apr, 1 jul, 1 oct if "every quarter" in legatoType['override']: year = datetime.datetime.today().year for y in range(year - 3,year + 6): for m in range(1,11,3): date = datetime.date(y,m,1) overrideDate[date.strftime("%m/%d/%Y")] = "" # Fill the levels if legatoType['override'] == "full first friday every month" or \ legatoType['override'] == "full every quarter": for date in overrideDate: overrideDate[date] = "full" legatoType['override'] = overrideDate elif legatoType['override'] == "consolidate first friday every month" or \ legatoType['override'] == "consolidate every quarter": for date in overrideDate: overrideDate[date] = "cons" legatoType['override'] = overrideDate elif legatoType['override'] != 'NIHIL': del(legatoType['_override']) override = legatoType['override'].replace(","," ") override = override.split() for x in range(0,len(override),2): # transfer 6/24/2005 to 06/24/2005 date = override[x + 1].split("/") date = [int(y) for y in date] date = datetime.date(date[2],date[0],date[1]) overrideDate[date.strftime("%m/%d/%Y")] = override[x] # overrideDate[override[x + 1]] = override[x] legatoType['override'] = overrideDate elif legatoType['period'] == "Week" and legatoType['override'] != 'NIHIL': override = legatoType['override'].replace(","," ") override = override.split() for x in range(0,len(override),2): # transfer 6/24/2005 to 06/24/2000 date = override[x + 1].split("/") date = [int(y) for y in date] date = datetime.date(date[2],date[0],date[1]) overrideDate[date.strftime("%m/%d/%Y")] = override[x] # overrideDate[override[x + 1]] = override[x] legatoType['override'] = overrideDate self.nsrSchedules.append(legatoType) def addLegatoType(self,legatoType): """ Add the the whole record to our main variables. """ if legatoType['type'] == 'NSR client': self.addClient(legatoType) elif legatoType['type'] == 'NSR group': self.addGroup(legatoType) elif legatoType['type'] == 'NSR license': self.addLicense(legatoType) elif legatoType['type'] == 'NSR pool': self.addPool(legatoType) elif legatoType['type'] == 'NSR schedule': self.addSchedule(legatoType) def readLegato(self): """ Read the info we get from Legato """ #file = open("nsradmin.all") file = os.popen('/usr/bin/ksh print "option Hidden:on\n print\n" | nsradmin -i -') row = "" legatoType = {} rawstr = r"""(?P[^:]*): (?P.*);""" compileObj = re.compile(rawstr) while 1: fileLine = file.readline() if not fileLine: break # if EOF fileLine = fileLine.strip() row = row + fileLine if row: if row[-1] == ";": # Now we have read a complete legato line # An Legato lines ends with a ";" # aliases: server1, server2; # Split the line matchObj = compileObj.search(row) # print matchObj.groups() , --> ('aliases','server1, server2') if matchObj.group('data'): legatoType[matchObj.group('name')] = matchObj.group('data') else: legatoType[matchObj.group('name')] = 'NIHIL' row = "" else: # add a space to the end of the line, otherwise the lines will be glued together row += " " else: """ We read an empty line, which means that we have read one legato type, ex : type: NSR notification; name: Tape mount request 2; comment: ; action: /usr/ucb/logger -p local0.alert; The value of temp is {'comment': '', 'action': '/usr/ucb/logger -p local0.alert', 'type': 'NSR notification', 'name': 'Tape mount request 2'} """ self.addLegatoType(legatoType) legatoType = {} if legatoType: self.addLegatoType(legatoType) # Don't forget the last line file.close() class Report(Legato): def __init__(self): Legato.__init__(self) def internShow(self,nsrInfo,reportFields,frontSpace=0): """ print the clients, groups, ... nsrInfo --> [ {} ,{}, ...] reportFields are the keys for the nsrInfo directory to print and also for printing the header """ reportFields = [x for x in reportFields.split(",")] reportLength = [] printInfo = [] cmd = "" try: # Calculate the column lengths (for printing ,we need the greatest) for x in reportFields: reportLength.append(len(x)) # Filter the fields we need and calculate the column length for data in nsrInfo: x = 0 printline = [] for reportField in reportFields: dataField = str(data[reportField]) printline.append(dataField) if len(dataField) > reportLength[x]: reportLength[x] = len(data[reportField]) x += 1 printInfo.append(printline) printInfo.sort() reportLength = [x + 2 for x in reportLength] for x in reportLength: cmd += "%-" + str(x) + "s" cmd = " " * frontSpace + cmd # print the header header = cmd % tuple(reportFields) print header print "-" * (len(header) + 2 + frontSpace) # Print the data for data in printInfo: print cmd % tuple(data) except KeyError: print "Error, check the reportfields !" def internShowScheduleOverrride(self,nsrScheduleOverride): override = [] dateToday = datetime.date.today() for date,level in nsrScheduleOverride.items(): date = [int(x) for x in date.split("/")] dateOverride = datetime.date(date[2],date[0],date[1]) # Skip override dates who are older then 200 days if (dateToday - dateOverride).days - 200 < 0: override.append([dateOverride,level]) override.sort() override.reverse() rows = len(override) // 4 remainder = len(override) % 4 count = len(override) # Print in 4 columns if remainder != 0: rows += 1 if count > 0: print " %-15s%-5s" * 4 % (("date","level") * 4) print " " * 5 + "-" * 95 for row in range(rows): print " %-15s%-5s" % (override[row][0].strftime("%m/%d/%Y"),override[row][1]), if row + rows < count: print " %-15s%-5s" % (override[row + rows][0].strftime("%m/%d/%Y"),override[row][1]), if row + rows * 2 < count: print " %-15s%-5s" % (override[row + rows * 2][0].strftime("%m/%d/%Y"),override[row][1]), if row + rows * 3 < count: print " %-15s%-5s" % (override[row + rows * 3][0].strftime("%m/%d/%Y"),override[row][1]), print print def findLevel(self,date,schedule): """ Find the level backup for a specific day """ dateStr = date.strftime("%m/%d/%Y") if schedule['period'] == "Week": # Is there an override date ? if dateStr in schedule['override']: level = schedule['override'][dateStr] else: dayOfWeek = date.isocalendar()[2] if dayOfWeek == 7: dayOfWeek = 0 # if Sunday level = schedule['action'][dayOfWeek] elif schedule['period'] == "Month": # Is there an override date ? if dateStr in schedule['override']: level = schedule['override'][dateStr] else: dayOfMonth = date.day level = schedule['action'][dayOfMonth - 1] else: print "The only time period I known is week or month." print "Call your python programmer." sys.exit(1) return (date.strftime("%m/%d"),level.center(5)) def showAllClients(self,*args): """ If we call it without arguments then we like to know more info about the clients With arguments we find the levels of backup for each of those clients args --> (['12/12/2005', 5,'name,schedule,...']) """ date = datetime.datetime.today() days = 1 askLevel = False reportFields = "" arguments = args[0] try: # I don't care how the arguments are passed, not 100% correct for arg in arguments: if re.match(r""".*/.*/.*""", arg): date = [int(x) for x in arg.split("/")] date = datetime.date(date[2],date[0],date[1]) askLevel = True elif re.match(r"""\d+""", arg): days = re.match(r"""\d+""", arg) if days.end() == len(arg): days = int(arg) askLevel = True else: raise "badInt" else: reportFields = arg except ValueError: print "Wrong date format !" return except "badInt": print "Wrong days format !" return # Clients with level info if askLevel: if not reportFields: reportFields = "name" # Format the client header for day in range(days): day = date + datetime.timedelta(days=day) dayStr = day.strftime("%m/%d") reportFields += "," + dayStr nsrInfo = [] data = {} # Find the level for client in self.nsrClients: # I don't want to change the self.nsrClients client = copy.deepcopy(client) schedule = [x for x in self.nsrSchedules if x['name'] == client['schedule']] schedule = schedule[0] # For how many days we like to know the level backup. for day in range(days): dayStr,level = self.findLevel(date + datetime.timedelta(days=day),schedule) client[dayStr] = level nsrInfo.append(client) if nsrInfo: self.internShow(nsrInfo,reportFields) print else: if not reportFields: reportFields = "name,group,schedule,enabler in use,save set" if self.nsrClients: self.internShow(self.nsrClients,reportFields) print def showAllGroups(self,reportFields): if not reportFields: reportFields = "name,start time" else: reportFields = reportFields[0] if self.nsrGroups: self.internShow(self.nsrGroups,reportFields) print def showInfo(self): """ Show which fields you can use in your reports" """ if self.nsrClients: fields = self.nsrClients[1].keys() fields.sort() print "Clients :" print "-" * 10 print ', '.join(fields) print print "ex. leginfo.py -C 'name,schedule,NetWorker version'" print if self.nsrGroups: fields = self.nsrGroups[1].keys() fields.sort() print "Groups :" print "-" * 10 print ', '.join(fields) print print "ex. leginfo.py -G 'name,comment,start time,interval'" print if self.nsrSchedules: fields = self.nsrSchedules[1].keys() fields.sort() print "Schedules :" print "-" * 10 print ', '.join(fields) print print "ex. leginfo.py -s 'Full' 'name,comment,action,override'" print if self.nsrPools: fields = self.nsrPools[1].keys() fields.sort() print "Pools :" print "-" * 10 print ', '.join(fields) print if self.nsrLicenses: fields = self.nsrLicenses[1].keys() fields.sort() print "Licenses :" print "-" * 10 print ', '.join(fields) print def showLicenses(self,reportFields): if not reportFields: reportFields = "name,enabler code,auth code,expiration date" else: reportFields = reportFields[0] if self.nsrLicenses: self.internShow(self.nsrLicenses,reportFields) print def showPools(self,reportFields): if not reportFields: reportFields = "name,groups,clients,save sets,levels,devices" else: reportFields = reportFields[0] nsrInfo = [] for pool in self.nsrPools: if (pool['enabled'] == 'Yes' and pool['devices'] != 'NIHIL') and ( pool['groups'] != 'NIHIL' or pool['clients'] != 'NIHIL' or pool['save sets'] != 'NIHIL' or pool['levels'] != 'NIHIL'): nsrInfo.append(pool) if nsrInfo: self.internShow(nsrInfo,reportFields) def showSchedules(self,nsrGetSchedules,reportFields): if not reportFields: reportFields = "name,period,action,override" else: reportFields = reportFields[0] # Format the action field nsrInfoWeek = [] nsrInfoMonth = [] actionWeek = ' Su Mo Tu We Th Fr Sa ' actionMonth = ' '.join([str(x).center(2) for x in range(1,32)]) for schedule in self.nsrSchedules: # Check only the schedules we want if schedule['name'] in nsrGetSchedules: schedule = copy.deepcopy(schedule) if schedule['period'] == 'Week': schedule[actionWeek] = ' '.join(schedule['action']) nsrInfoWeek.append(schedule) elif schedule['period'] == 'Month': #schedule[actionMonth] = ' '.join(x[:2] for x in schedule['action']) (works only in version 2.4) nsrInfoAction = [x[:2] for x in schedule['action']] schedule[actionMonth] = ' '.join(nsrInfoAction) nsrInfoMonth.append(schedule) if nsrInfoWeek: reportFieldsWeek = reportFields.replace('action',actionWeek) if nsrInfoMonth: reportFieldsMonth = reportFields.replace('action',actionMonth) if "override" in reportFields: if nsrInfoWeek: reportFieldsWeek = reportFieldsWeek.replace('override,','') reportFieldsWeek = reportFieldsWeek.replace(',override','') reportFieldsWeek = reportFieldsWeek.replace('override','name') if nsrInfoMonth: reportFieldsMonth = reportFieldsMonth.replace('override,','') reportFieldsMonth = reportFieldsMonth.replace(',override','') reportFieldsMonth = reportFieldsMonth.replace('override','name') for nsrWeek in nsrInfoWeek: self.internShow([nsrWeek],reportFieldsWeek) if nsrWeek['override'] != 'NIHIL': if nsrWeek.has_key('_override'): print "Override :", nsrWeek['_override'] print self.internShowScheduleOverrride(nsrWeek['override']) print for nsrMonth in nsrInfoMonth: self.internShow([nsrMonth],reportFieldsMonth) if nsrMonth['override'] != 'NIHIL': if nsrMonth.has_key('_override'): print "Override :", nsrMonth['_override'] print self.internShowScheduleOverrride(nsrMonth['override']) print else: if "action" in reportFields: if nsrInfoWeek: self.internShow(nsrInfoWeek,reportFieldsWeek) print if nsrInfoMonth: self.internShow(nsrInfoMonth,reportFieldsMonth) else: self.internShow(nsrInfoWeek+nsrInfoMonth,reportFields) def showUnknownClients(self,reportFields): nsrInfo = [] if not reportFields: reportFields = "name,group,schedule,enabler in use,save set" else: reportFields = reportFields[0] for data in self.nsrClients: if data['group'] == 'NIHIL' or data['schedule'] == 'NIHIL': nsrInfo.append(data) if nsrInfo: self.internShow(nsrInfo,reportFields) print def showGroup(self,searchGroup,*args): """ args --> (['12/12/2005', 5,'name,schedule,level']) """ getGroups = [ (x['name'],x['start time']) for x in self.nsrGroups] getGroups.sort() arguments = args[0] date = datetime.datetime.today() days = 1 reportFields = "name,schedule" try: # I don't care how the arguments are passed, not 100% correct for arg in arguments: if re.match(r""".*/.*/.*""", arg): date = [int(x) for x in arg.split("/")] date = datetime.date(date[2],date[0],date[1]) elif re.match(r"""\d+""", arg): days = re.match(r"""\d+""", arg) if days.end() == len(arg): days = int(arg) else: raise "badInt" else: reportFields = arg except ValueError: print "Wrong date format !" return except "badInt": print "Wrong days format !" return for group,startTime in getGroups: if searchGroup in group: # Print the group info nsrInfo = [] data = {} groupStr = 'group (' + date.strftime("%a %d %b %Y") + ')' data[groupStr] = group data['start time'] = startTime data['week'] = date.isocalendar()[1] nsrInfo.append(data) self.internShow(nsrInfo,groupStr + ",start time,week") # Print the clients # Format the client header for day in range(days): day = date + datetime.timedelta(days=day) dayStr = day.strftime("%m/%d") reportFields += "," + dayStr nsrInfo = [] data = {} # It is possible that a client is located in more than one group getclients = [x for x in self.nsrClients if searchGroup in x['group'] ] # Find the level for client in getclients: # I don't want to change the self.nsrClients client = copy.deepcopy(client) schedule = [x for x in self.nsrSchedules if x['name'] == client['schedule']] schedule = schedule[0] # For how many days we like to know the level backup. for day in range(days): dayStr,level = self.findLevel(date + datetime.timedelta(days=day),schedule) client[dayStr] = level nsrInfo.append(client) if nsrInfo: self.internShow(nsrInfo,reportFields,2) print def main(): try: opts,args = getopt.getopt(sys.argv[1:],"CGILPSXg:s:") except getopt.GetoptError: print "Version 0.1.1, date : 01/11/2006" print print "leginfo.py [options]" print " -C [mm/dd/yyyy] [days] [\"reportClients\"] : List all clients" print " -G [\"reportGroups\"] : List all groups and the starting hour" print " -I : Show which report fields you can use in your report" print " -L : List all licenses" print " -P : List pools which are enabled and groups or clients,save sets,levels are not empty" print " -S [\"reportSchedules\"] : List schedules for defiened clients" print " -X [\"reportClients\"] : Clients with no groups" print " -g group [mm/dd/yyyy] [days] [\"reportClients\"] : List clients in this group and the schedule of this day or asked day" print " -s schedule [\"reportSchedules\"] : List a schedule" print print "Don't mix options !!" print print "examples :" print " leginfo.py -I (use the output for the reportFields (reportClients,reportClients,reportSchedules)" print print " leginfo.py -C" print " leginfo.py -C 5" print " leginfo.py -C 12/1/2005 3 \"name,group,CPUs\"" print " leginfo.py -C \"name,group,CPUs\" 3 12/1/2005 (it doesn't matter how the arguments are passed)" print print " leginfo.py -G" print " leginfo.py -g group (change group from the output of leginfo.py -G or part of it)" print " leginfo.py -g group 'name,schedule'" print " leginfo.py -g group 12/15/2005 10 'name,schedule'" print print " leginfo.py -S" print " leginfo.py -s schedule 'name,action,period,override' (change schedule from the output of leginfo.py -S 'name' or part of it)" print "" sys.exit(1) legato = Report() for opt, arg in opts: if opt == "-C": legato.showAllClients(args) if opt == "-G": legato.showAllGroups(args) if opt == "-I": legato.showInfo() if opt == "-L": legato.showLicenses(args) if opt == "-P": legato.showPools(args) if opt == "-S": nsrGetSchedules = {} # Get only the schedules if defiened in the clients for client in legato.nsrClients: if client['enabler in use'] == 'Yes': nsrGetSchedules[client['schedule']] = '' nsrGetSchedules = nsrGetSchedules.keys() nsrGetSchedules.sort() legato.showSchedules(nsrGetSchedules,args) if opt == "-X": legato.showUnknownClients(args) if opt == "-g": """ ./leginfo.py -g group 1/1/2005 "name,schedule,..." arg --> schedule args --> ["1/1/2005","name,schedule,..."] """ legato.showGroup(arg,args) if opt == "-s": """ ./leginfo.py -g schedule "name,period,..." arg --> schedule args --> ["name,period,..."] """ nsrGetSchedules = {} # Get only the schedules if defiened in the clients for client in legato.nsrClients: if client['enabler in use'] == 'Yes': nsrGetSchedules[client['schedule']] = '' nsrGetSchedules = nsrGetSchedules.keys() nsrGetSchedules.sort() # Now get the schedules where are nsrGetSchedules = [schedule for schedule in nsrGetSchedules if arg in schedule] legato.showSchedules(nsrGetSchedules,args) if __name__ == "__main__": main()