summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHariharasubramanian R <hramasub@in.ibm.com>2016-04-01 07:29:39 -0500
committerHariharasubramanian R <hramasub@in.ibm.com>2016-04-01 07:29:39 -0500
commit0ae14c7bdbed84d52c90646c132abd22df597465 (patch)
tree7f9c09a8089b0d44e26c73f2ec1d517034c6cac7
parent448e8d839d37532d2667b9a38bb3aadb6c804e2e (diff)
downloadphosphor-networkd-0ae14c7bdbed84d52c90646c132abd22df597465.tar.gz
phosphor-networkd-0ae14c7bdbed84d52c90646c132abd22df597465.zip
Log management service to stream journals/syslogs to a remote syslog server.
-rwxr-xr-xlogman.py266
1 files changed, 266 insertions, 0 deletions
diff --git a/logman.py b/logman.py
new file mode 100755
index 0000000..05ca191
--- /dev/null
+++ b/logman.py
@@ -0,0 +1,266 @@
+#!/usr/bin/env python
+
+from subprocess import call
+import sys
+import subprocess
+import dbus
+import string
+import socket
+import os
+import fcntl
+import time
+import glib
+import gobject
+import dbus.service
+import dbus.mainloop.glib
+
+DBUS_NAME = 'org.openbmc.LogManager'
+ERRL_INTF_NAME = 'org.openbmc.Errl'
+SRVC_INTF_NAME = 'org.openbmc.Service'
+OBJ_NAME_RSYSLOG = '/org/openbmc/LogManager/rsyslog'
+
+'''
+ Object Path > /org/openbmc/LogManager/rsyslog
+ Interface:Method > org.openbmc.Service.Enable dict:string:string
+ Interface:Method > org.openbmc.Service.Disable
+'''
+
+class JournalUtils ():
+ def _isvalidip(self, family, ipaddr):
+ if family == socket.AF_INET:
+ try:
+ socket.inet_pton(socket.AF_INET, ipaddr)
+ except AttributeError: # no inet_pton here, sorry
+ try:
+ socket.inet_aton(ipaddr)
+ except socket.error:
+ return False
+ return ipaddr.count('.') == 3
+ except socket.error: # not a valid address
+ return False
+
+ return True
+
+ elif family == socket.AF_INET6:
+ try:
+ socket.inet_pton(socket.AF_INET6, ipaddr)
+ except socket.error: # not a valid address
+ return False
+ return True
+
+ else: return False
+
+class Rsyslog (dbus.service.Object):
+ def __init__(self, bus, name):
+ self.bus = bus
+ self.name = name
+ dbus.service.Object.__init__(self,bus,name)
+
+ @dbus.service.method(dbus.PROPERTIES_IFACE, "ss", "v")
+ def Get(self, iface, ppty):
+ return self.GetAll(iface)[ppty]
+
+ @dbus.service.method(dbus.PROPERTIES_IFACE, 's', 'a{sv}')
+ def GetAll(self, iface):
+ if iface == ERRL_INTF_NAME:
+ status, remote_ip, remote_port = self.Status()
+ return {'status': status, 'ipaddr': remote_ip, 'port': remote_port }
+ else:
+ raise dbus.exceptions.DBusException('org.openbmc.UnknownInterface',
+ 'This object does not implement the %s interface' % iface)
+
+ @dbus.service.method(SRVC_INTF_NAME, "a{sv}", "x")
+ def Enable (self, argv_dict):
+ remote_ip = ""
+ remote_port = 0
+
+ params = len (argv_dict)
+ if params > 2 : ValueError("Invalid Parameters")
+
+ for property_name in argv_dict:
+ if property_name == "ipaddr":
+ remote_ip = argv_dict [property_name]
+ elif property_name == "port":
+ remote_port = argv_dict [property_name]
+ else:
+ raise ValueError("Invalid Argument: IP Address/Port expected.")
+
+ if not remote_ip:
+ cur_remote = self._GetConfig ('Remote')
+ if not cur_remote:
+ raise ValueError("Invalid Remote Syslog IP Address")
+ else:
+ cur_remote = cur_remote[3:]
+ remote_ip, port_str = cur_remote.split (":")
+ remote_port = int(port_str)
+ if not util._isvalidip (socket.AF_INET, remote_ip): raise ValueError, "Malformed IP Address"
+ if not remote_port : remote_port = 514
+ if remote_port > 65535 : raise ValueError("Invalid Remote Syslog Port")
+
+ remote_addr = remote_ip + ":" + str(remote_port)
+ r = self._ModifyService('Remote', remote_addr)
+
+ cur_options = self._GetConfig ('Options')
+ new_options = self._GetOptions()
+
+ if cur_options != new_options:
+ r = self._ModifyService('Options', new_options)
+ r = self._RestartService ()
+
+ return r
+
+ @dbus.service.method(SRVC_INTF_NAME, "as", "x")
+ def Disable (self, argv_list):
+ params = len (argv_list)
+ if params : ValueError("Invalid Parameters")
+
+ remote = self._GetConfig ('Remote')
+ if not remote : return 0
+
+ r = self._ModifyService('Options', '-C') # FIXME: Restore current options minus the remote.
+ r = self._RestartService ()
+ return r
+
+ def Status (self):
+ remote = self._GetConfig ('Remote')
+ if not remote : return ("Disabled", "0.0.0.0", 0)
+
+ cur_remote = remote[3:]
+ remote_ip, remote_port = cur_remote.split (":")
+
+ options = self._GetConfig ('Options')
+ if not options : return ("Disabled", remote_ip, remote_port)
+
+ if remote in options : return ("Enabled", remote_ip, remote_port)
+
+ return ("Disabled", remote_ip, remote_port)
+
+ def _ModifyService (self, opt, val):
+ if not os.path.isfile(syslog_service_bbx_file):
+ r = call (["cp", syslog_service_lib_file, syslog_service_bbx_file])
+ r = call (["ln", "-s", syslog_service_bbx_file, syslog_service_cfg_file])
+
+ if not os.path.isfile(syslog_service_env_file):
+ env_file = open(syslog_service_env_file, 'w')
+ env_file.write ("OPTIONS=\"-C\"")
+ env_file.close()
+
+ if opt not in OptionKeys: raise ValueError("Invalid Option")
+
+ self._ModifyParam (opt, val)
+
+ return 0
+
+ def _StopService (self):
+ r = call (["systemctl", "stop", "syslog"])
+ r = call (["systemctl", "--no-reload", "kill", "syslog"])
+ return r
+
+ def _StartService (self):
+ r = call (["systemctl", "daemon-reload"])
+ r = call (["systemctl", "start", "syslog"])
+ return r
+
+ def _RestartService (self):
+ r = self._StopService()
+ r = self._StartService()
+ return r
+
+ def _ModifyParam (self, opt, val):
+ env_file = open(syslog_service_env_file, 'r')
+ tmp_file = open(syslog_service_tmp_file, 'w')
+
+ optkey = OptionKeySwitchMap [opt]['key']
+ for line in env_file:
+ if line[0] == '#':
+ tmp_file.write(line)
+ continue
+ curkey = line.strip().split ("=")[0]
+ if curkey != optkey :
+ tmp_file.write(line)
+
+ tmp_file.write(optkey + "=\"" + OptionKeySwitchMap[opt]['switch'] + val + "\"" + "\n")
+
+ env_file.close ()
+ tmp_file.close ()
+
+ r = call (["cp", syslog_service_tmp_file, syslog_service_env_file])
+ return r
+
+ def _GetConfig (self, opt):
+ with open(syslog_service_env_file, "r") as f:
+ for line in f:
+ if line[0] == '#': continue
+ config = line.split ("=")
+ var = config [0]
+ if var == OptionKeySwitchMap[opt]['key']:
+ val = config [1]
+ val = val[1:-2] # FIXME: Why is there a trailing space ???
+ return val
+ return ""
+
+ def _GetOptions(self):
+ cfg = {}
+ i = 0
+
+ for opt in OptionKeys:
+ if opt == 'Options' : continue
+ cfg [i] = self._GetConfig(opt)
+ i+=1
+
+ options = ''
+ j = 0
+ while j<i-1:
+ if cfg[j] : options += cfg [j]
+ j+=1
+
+ return options
+
+def main():
+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+ bus = dbus.SystemBus()
+ name = dbus.service.BusName(DBUS_NAME, bus)
+
+ global util
+ global rsys
+ global syslog_service_lib_file
+ global syslog_service_bbx_file
+ global syslog_service_cfg_file
+ global syslog_service_env_file
+ global syslog_service_tmp_file
+ global OptionKeys
+ global OptionKeySwitchMap
+
+ OptionKeys = ['Options', 'Outfile', 'Priority', 'Smaller', 'RotateSize', 'RotateNum', 'Remote', 'LocalAndNet', 'DropDup', 'SharedMem', 'ConfFile', 'MarkTime', 'Printk']
+ OptionKeySwitchMap = {
+ 'Options' : { 'switch' : "", 'key' : "OPTIONS" },
+ 'Outfile' : { 'switch' : "-O ", 'key' : "OBMC_SYSLOG_OUTFILE" },
+ 'Priority' : { 'switch' : "-O ", 'key' : "OBMC_SYSLOG_PRIORITY" },
+ 'Smaller' : { 'switch' : "-S ", 'key' : "OBMC_SYSLOG_SMALLER" },
+ 'RotateSize' : { 'switch' : "-s ", 'key' : "OBMC_SYSLOG_ROTATESIZE" },
+ 'RotateNum' : { 'switch' : "-b ", 'key' : "OBMC_SYSLOG_ROTATENUM" },
+ 'Remote' : { 'switch' : "-R ", 'key' : "OBMC_SYSLOG_REMOTE" },
+ 'LocalAndNet' : { 'switch' : "-L ", 'key' : "OBMC_SYSLOG_LOCALNET" },
+ 'DropDup' : { 'switch' : "-D ", 'key' : "OBMC_SYSLOG_DROPDUP" },
+ 'SharedMem' : { 'switch' : "-C ", 'key' : "OBMC_SYSLOG_SHAREDMEM" },
+ 'ConfFile' : { 'switch' : "-f ", 'key' : "OBMC_SYSLOG_CONFFILE" },
+ 'MarkTime' : { 'switch' : "-m ", 'key' : "OBMC_SYSLOG_MARKTIME" },
+ 'Printk' : { 'switch' : "-K ", 'key' : "OBMC_SYSLOG_PRINTK" }
+ }
+
+ syslog_service_lib_file = '/lib/systemd/system/busybox-syslog.service'
+ syslog_service_bbx_file = '/etc/systemd/system/busybox-syslog.service'
+ syslog_service_cfg_file = '/etc/systemd/system/syslog.service'
+ syslog_service_env_file = '/etc/default/busybox-syslog'
+ syslog_service_tmp_file = '/tmp/busybox-syslog.tmp'
+
+ util = JournalUtils ()
+ rsys = Rsyslog (bus, OBJ_NAME_RSYSLOG)
+
+ mainloop = gobject.MainLoop()
+ print("Started")
+ mainloop.run()
+
+if __name__ == '__main__':
+ sys.exit(main())
+
OpenPOWER on IntegriCloud