[master] analog, a script to receive logs from a remote install.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



---
 anaconda.spec.in    |    1 +
 scripts/Makefile.am |    3 +
 scripts/analog      |  244 +++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 248 insertions(+), 0 deletions(-)
 create mode 100755 scripts/analog

diff --git a/anaconda.spec.in b/anaconda.spec.in
index c855935..c6dbf6a 100644
--- a/anaconda.spec.in
+++ b/anaconda.spec.in
@@ -200,6 +200,7 @@ update-desktop-database &> /dev/null || :
 /lib/udev/rules.d/70-anaconda.rules
 %{_bindir}/mini-wm
 %{_sbindir}/anaconda
+%{_bindir}/analog
 %ifarch i386 i486 i586 i686 x86_64
 %{_sbindir}/gptsync
 %{_sbindir}/showpart
diff --git a/scripts/Makefile.am b/scripts/Makefile.am
index 1c59338..a2b53e6 100644
--- a/scripts/Makefile.am
+++ b/scripts/Makefile.am
@@ -25,4 +25,7 @@ dist_scripts_DATA    = mk-images.* pyrc.py
 dist_noinst_SCRIPTS  = getlangnames.py upd-bootimage upd-initrd upd-kernel \
                        makeupdates
 
+analogdir = $(bindir)/
+dist_analog_SCRIPTS = analog
+
 MAINTAINERCLEANFILES = Makefile.in
diff --git a/scripts/analog b/scripts/analog
new file mode 100755
index 0000000..ef41f4e
--- /dev/null
+++ b/scripts/analog
@@ -0,0 +1,244 @@
+#! /usr/bin/python 
+#
+# analog: Remote logging manager for the Red Hat Installer
+#
+# Copyright (C) 2010
+# Red Hat, Inc.  All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Ales Kozumplik <akozumpl@xxxxxxxxxx>
+#
+
+import errno
+import optparse
+import os
+import os.path
+import signal
+import sys
+
+DEFAULT_PORT = 6080
+DEFAULT_ANALOG_DIR = '.analog'
+COMMANDS = ['start', 'stop']
+USAGE = "%prog cmd [options]"
+COMMANDS = """Commands:
+  start    start a new syslog daemon
+  stop     stop a running syslog daemon
+"""
+
+RSYSLOG_COMMAND = "/sbin/rsyslogd -c 4 -f %(cfg_file_name)s -i %(pid_file_name)s"
+RSYSLOG_TEMPLATE ="""
+#### MODULES ####
+# Provides TCP syslog reception
+$ModLoad imtcp.so  
+$InputTCPServerRun %(port)s
+
+#### GLOBAL DIRECTIVES ####
+
+# Use default timestamp format
+$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat
+
+# File syncing capability is disabled by default. This feature is usually not required, 
+# not useful and an extreme performance hit
+#$ActionFileEnableSync on
+
+
+#### RULES ####
+
+$template anaconda_tty4, "%%timestamp:8:$:date-rfc3164%%,%%timestamp:1:3:date-subseconds%% %%syslogseverity-text:::uppercase%% %%programname%%:%%msg%%\\n"
+$template anaconda_debug, "%%syslogfacility-text%%|%%hostname%%|%%syslogseverity-text%%|%%syslogtag%%|%%msg%%\\n"
+$template anaconda_syslog, "%%timestamp:8:$:date-rfc3164%%,%%timestamp:1:3:date-subseconds%% %%syslogseverity-text:::uppercase%% %%programname%%:%%msg%%\\n"
+
+*.*                                                  %(directory)s/out_all_debug.log;anaconda_debug
+
+kern.*;\\
+daemon.*                                             %(directory)s/syslog;anaconda_syslog
+
+:programname, contains, "loader"                     %(directory)s/anaconda.log;anaconda_syslog
+:programname, contains, "anaconda"                   %(directory)s/anaconda.log;anaconda_syslog
+:programname, contains, "program"                    %(directory)s/program.log;anaconda_syslog
+:programname, contains, "storage"                    %(directory)s/storage.log;anaconda_syslog
+:hostname, contains, "sysimage"                      %(directory)s/install.log.syslog;anaconda_syslog
+
+# discard those that we logged
+:programname, contains, "rsyslogd"                   ~
+:programname, contains, "loader"                     ~
+:programname, contains, "anaconda"                   ~
+:programname, contains, "program"                    ~
+:programname, contains, "storage"                    ~
+:hostname, contains, "sysimage"                      ~
+kern.*                                               ~
+daemon.*                                             ~
+# dump the rest
+*.*                                                  %(directory)s/unknown_source.log;anaconda_debug
+
+"""
+
+# option parsing
+class OptParserError(Exception):
+    def __init__(self, msg, parser):
+        Exception.__init__(self, msg, parser)
+        self.msg = msg
+        self.parser = parser
+
+class AnalogError(Exception):
+    def __init__(self, msg):
+        Exception.__init__(self, msg)
+        self.msg = msg
+
+def get_opts():
+    parser = optparse.OptionParser(usage=USAGE,
+                                   add_help_option=False)
+    parser.add_option ('-h', '--help', action="callback", callback=help_and_exit,
+                       help="Display this help")
+    parser.add_option ('-p', type="int", dest="port", 
+                       default=DEFAULT_PORT, 
+                       help="TCP port the rsyslog daemon will listen on")
+    (options, args) = parser.parse_args()
+    if len(args) < 1:
+        raise OptParserError("no command given", parser)
+    cmd = args[0]
+    args = args[1:]
+    if cmd not in COMMANDS:
+        raise OptParserError("unknown command %s" % cmd, parser)
+    if cmd in ['start', 'stop'] and len(args) != 1:
+        raise OptParserError("no job name specified for '%s'" % cmd, parser)
+    return (cmd, options, args)
+
+def help_and_exit(option, opt, value, parser):
+    parser.print_help()
+    print
+    print COMMANDS
+    sys.exit(0)
+
+# helper functions
+def get_pid(analog_dir, jobname):
+    """Returns PID of the corresponding rsyslogd or None if it can't be found."""
+    location = get_pid_location(analog_dir, jobname)
+    try: 
+        with open(location) as pidfile:
+            pid = int(pidfile.read())
+    except IOError:
+        return None
+    return pid
+    
+def get_pid_location(analog_dir, jobname):
+    return os.path.join(analog_dir, jobname + '.pid')
+
+# the main Analog class
+class Analog(object):
+    def __init__(self):
+        self.base_dir = os.getcwd()
+        self.analog_dir = os.path.join(self.base_dir, DEFAULT_ANALOG_DIR)
+
+    def execute(self, cmd, opts, args):
+        job = None
+        if cmd == 'start':
+            job_name = args[0]
+            log_dir = os.path.join(self.base_dir, job_name)
+            job = StartJob(self.analog_dir, job_name, log_dir, opts.port)
+        elif cmd == 'stop':
+            job_name = args[0]
+            job = StopJob(self.analog_dir, job_name)
+        job.run()
+
+    def find_analog_dir(self):
+        if os.access(self.analog_dir, os.R_OK | os.W_OK | os.X_OK):
+            return True
+        return False
+    
+    def init_analog_dir(self):
+        print 'initializing .analog dir'
+        os.mkdir(self.dir)
+
+class Job(object):
+    def run(self):
+        raise NotImplementedError()
+        
+
+class StartJob(Job):
+    def __init__(self, analog_dir, job_name, log_dir, port):
+        self.analog_dir = analog_dir
+        self.config_file_name = None
+        self.job_name = job_name
+        self.log_dir = log_dir
+        self.port = port
+    
+    def generate_rsyslog_config(self):
+        values = {
+            "directory" : self.log_dir,
+            "port"      : self.port
+            }
+        config = RSYSLOG_TEMPLATE % values
+        self.config_file_name = os.path.join(self.analog_dir, self.job_name + ".conf")
+        with open(self.config_file_name, 'w+') as config_file:
+            config_file.write(config)
+    
+    def prepare_log_dir(self):
+        try:
+            os.mkdir(self.log_dir)
+        except OSError as e:
+            if e.errno == errno.EEXIST:
+                pass
+            else:
+                raise e
+
+    def run(self):
+        print 'starting rsyslog daemon, listening on port %d\nlogging under %s' % (
+            self.port, self.log_dir)
+        self.generate_rsyslog_config()
+        self.prepare_log_dir()
+        self.start_daemon()
+        
+    def start_daemon(self):
+        pid_location = get_pid_location(self.analog_dir, self.job_name)
+        values = {
+            "cfg_file_name" : self.config_file_name,
+            "pid_file_name" : pid_location
+            }
+        cmd = RSYSLOG_COMMAND % values
+        rc = os.system(cmd)
+        return rc
+
+class StopJob(Job):
+    def __init__(self, analog_dir, job_name):
+        self.analog_dir = analog_dir
+        self.job_name = job_name
+        
+    def run(self):
+        self.pid = get_pid(self.analog_dir, self.job_name)
+        if self.pid is None:
+            raise AnalogError("no running job of name '%s' found" % self.job_name)
+        print 'stopping daemon %d' % self.pid
+        self.stop_daemon()
+        
+    def stop_daemon(self):
+        os.kill(self.pid, signal.SIGTERM)
+
+if __name__ == "__main__":
+    try:
+        (cmd, options, args) = get_opts()
+    except OptParserError as exc:
+        exc.parser.error(exc.msg)
+        sys.exit(1)
+    analog = Analog()
+    if not analog.find_analog_dir():
+        analog.init_analog_dir()
+    try:
+        analog.execute(cmd, options, args)
+    except AnalogError as e:
+        print(e)
+        sys.exit(1)
+
+    sys.exit(0)
-- 
1.6.6

_______________________________________________
Anaconda-devel-list mailing list
Anaconda-devel-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/anaconda-devel-list

[Index of Archives]     [Kickstart]     [Fedora Users]     [Fedora Legacy List]     [Fedora Maintainers]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [Yosemite Photos]     [KDE Users]     [Fedora Tools]
  Powered by Linux