1# -*- coding: utf-8 -*- 2 3""" 4Get information about running/failed units and boot process 5""" 6 7import re 8import subprocess 9 10from logparse import config 11from logparse.formatting import* 12from logparse.load_parsers import Parser 13from logparse.util import resolve 14 15# The following list changes with each systemd version. 16# Run `systemctl --state=help` to view currently implemented states. 17# The numbers correspond to degrees of severity for later formatting. 18BAD_STATES = {"bad":4,"failed":4,"not-found":4,"bad-setting":2, 19"error":3,"masked":2,"dead":3,"abandoned":3} 20SYS_STATUS = {'running':0,'initializing':1,'starting':1,'stopping':1, 21'degraded':3,'unknown':4,'offline':5} 22 23 24classUnit(): 25""" 26 Class with some basic variables to represent a systemd unit. 27 """ 28 29def__init__(self, name, loaded, active, sub, description): 30 self.name = name 31 self.loaded = loaded 32 self.active = active 33 self.sub = sub 34 self.description = description 35 36defstatus(): 37""" 38 Finds the status of a unit on-demand with `systemctl is-active`. 39 Currently not used anywhere. 40 """ 41try: 42 p = subprocess.Popen(["systemctl","is-active", self.name], 43 stdout=subprocess.PIPE) 44(output, err) = p.communicate() 45 status = output.decode('utf-8') 46return status 47exceptExceptionas e: 48 logger.warning("Failed to get status for unit{0}:{1}".format( 49 self.name,str(e))) 50 51 52classSystemd(Parser): 53 54def__init__(self): 55super().__init__() 56 self.name ="systemd" 57 self.info ="Information about running/failed units and boot process" 58 59defparse_log(self): 60 61 logger.debug("Starting systemd section") 62 section =Section("systemd") 63 64# Get overall system status 65try: 66 p = subprocess.Popen(["systemctl","is-system-running"], 67 stdout = subprocess.PIPE) 68(output, err) = p.communicate() 69exceptExceptionas e: 70 logger.warning("Failed to get system status: "+str(e)) 71else: 72 status_raw =str(output.decode('utf-8')).split()[0] 73 section.append_data(Data("System status", [status_raw], 74 severity=SYS_STATUS[status_raw])) 75 76# Get summary of systemd units 77try: 78 p = subprocess.Popen( 79["systemctl","list-units"], stdout = subprocess.PIPE) 80(output, err) = p.communicate() 81exceptExceptionas e: 82 logger.warning("Failed to get list of unit files: "+str(e)) 83 units_raw =None 84else: 85 units_raw = output.decode('utf-8') 86 unit_properties = [Unit(*line.split(maxsplit=4)) 87for line in units_raw.replace("●"," ") \ 88.splitlines()[1:-7]] 89 unit_states = {} 90 91for u in unit_properties: 92if not u.sub in unit_states: 93 unit_states[u.sub] = [] 94 unit_states[u.sub].append(u.name) 95 96 ok_data =Data() 97 98for state, unit_list in unit_states.items(): 99if state in BAD_STATES: 100 logger.debug("Found critical unit{0}with status{1}" 101.format(u.name, u.sub)) 102 section.append_data(Data( 103plural(state +" unit",len(unit_list)), unit_list, 104 severity=BAD_STATES[state]) 105.truncl(config.prefs.getint("logparse","maxlist"))) 106else: 107 ok_data.items.append(" ".join([str(len(unit_list)), state])) 108 109iflen(ok_data.items) >0 \ 110and config.prefs.getboolean("systemd","show-all"): 111 ok_data.subtitle =plural("unit",len(ok_data.items)) \ 112+" in a non-critical state" 113 ok_data.truncl(config.prefs.getint("logparse","maxlist")) 114 section.append_data(ok_data) 115 116 logger.info("Finished systemd section") 117return section 118 119defcheck_dependencies(self): 120 121# Check if systemctl is set up 122 cmd ="systemctl --version" 123if self._check_dependency_command(cmd)[0] !=0: 124return(False, ["systemctl"]) 125else: 126return(True,None)