threaded log file capture and store & forward
authorOliver Maurhart <oliver.maurhart@ait.ac.at>
Mon, 19 May 2014 13:13:30 +0200
changeset 154651bf8fd169e
parent 153 ef0ace8dfc97
child 155 bcb24068c63e
child 156 caf3dd2bf081
threaded log file capture and store & forward
OpenSecurity/bin/environment.py
OpenSecurity/bin/opensecurity_client_restful_server.py
     1.1 --- a/OpenSecurity/bin/environment.py	Fri May 16 10:04:11 2014 +0200
     1.2 +++ b/OpenSecurity/bin/environment.py	Mon May 19 13:13:30 2014 +0200
     1.3 @@ -44,6 +44,8 @@
     1.4  class Environment(object):
     1.5      
     1.6      """Hold some nifty environment stuff in a dedicated class."""
     1.7 +
     1.8 +    _log_warning_shown = False
     1.9      
    1.10      def __init__(self, application = None):
    1.11          
    1.12 @@ -103,7 +105,9 @@
    1.13              if os.access('/var/log', os.W_OK):
    1.14                  return '/var/log'
    1.15              
    1.16 -            print('no permissions to write log files in /var/log, switching to ~/.log')
    1.17 +            if not Environment._log_warning_shown:
    1.18 +                print('no permissions to write log files in /var/log, switching to ~/.log')
    1.19 +                Environment._log_warning_shown = True
    1.20              
    1.21              if not os.path.exists(user_log_path):
    1.22                  os.mkdir(user_log_path)
     2.1 --- a/OpenSecurity/bin/opensecurity_client_restful_server.py	Fri May 16 10:04:11 2014 +0200
     2.2 +++ b/OpenSecurity/bin/opensecurity_client_restful_server.py	Mon May 19 13:13:30 2014 +0200
     2.3 @@ -33,19 +33,20 @@
     2.4  # imports
     2.5  
     2.6  import getpass
     2.7 +import glob
     2.8  import json
     2.9  import os
    2.10  import os.path
    2.11 +import pickle
    2.12  import platform
    2.13  import socket
    2.14  import subprocess
    2.15  import sys
    2.16 +import threading
    2.17 +import time
    2.18  import urllib
    2.19  import urllib2
    2.20  import web
    2.21 -import threading
    2.22 -import time
    2.23 -import string
    2.24  
    2.25  from opensecurity_util import logger, setupLogger, OpenSecurityException
    2.26  if sys.platform == 'win32' or sys.platform == 'cygwin':
    2.27 @@ -53,6 +54,7 @@
    2.28  
    2.29  # local
    2.30  import __init__ as opensecurity
    2.31 +from environment import Environment
    2.32  
    2.33  
    2.34  # ------------------------------------------------------------
    2.35 @@ -76,6 +78,13 @@
    2.36  # vars
    2.37  
    2.38  
    2.39 +"""lock for read/write log file"""
    2.40 +log_file_lock = threading.Lock()
    2.41 +
    2.42 +"""timer for the log file bouncer"""
    2.43 +log_file_bouncer = None
    2.44 +
    2.45 +
    2.46  """The REST server object"""
    2.47  server = None
    2.48  
    2.49 @@ -170,19 +179,13 @@
    2.50          args['user'] = getpass.getuser()
    2.51          args['system'] = platform.node() + " " + platform.system() + " " + platform.release()
    2.52  
    2.53 -        # bounce log data
    2.54 -        url_addr = 'http://GIMME-SERVER-TO-LOG-TO/log'
    2.55 +        # add these to new data to log
    2.56 +        global log_file_lock
    2.57 +        log_file_name = os.path.join(Environment('OpenSecurity').log_path, 'vm_new.log')
    2.58 +        log_file_lock.acquire()
    2.59 +        pickle.dump(args,  open(log_file_name, 'ab'))
    2.60 +        log_file_lock.release()
    2.61  
    2.62 -        # by provided a 'data' we turn this into a POST statement
    2.63 -        d = urllib.urlencode(args)
    2.64 -        req = urllib2.Request(url_addr, d)
    2.65 -        try:
    2.66 -            res = urllib2.urlopen(req)
    2.67 -        except:
    2.68 -            print('failed to contact: ' + url_addr)
    2.69 -            print('log data: ' + d)
    2.70 -            return "Failed"
    2.71 -         
    2.72          return "Ok"
    2.73  
    2.74  
    2.75 @@ -488,12 +491,88 @@
    2.76      return True
    2.77  
    2.78  
    2.79 +def _bounce_vm_logs():
    2.80 +
    2.81 +    """grab all logs from the VMs and push them to the log servers"""
    2.82 +
    2.83 +    global log_file_lock
    2.84 +
    2.85 +    # pick the highest current number
    2.86 +    cur = 0
    2.87 +    for f in glob.iglob(os.path.join(Environment('OpenSecurity').log_path, 'vm_cur.log.*')):
    2.88 +        try:
    2.89 +            n = f.split('.')[-1:][0]
    2.90 +            if cur < int(n):
    2.91 +                cur = int(n)
    2.92 +        except:
    2.93 +            pass
    2.94 +
    2.95 +    cur = cur + 1
    2.96 +
    2.97 +    # first add new vm logs to our existing one: rename the log file
    2.98 +    log_file_name_new = os.path.join(Environment('OpenSecurity').log_path, 'vm_new.log')
    2.99 +    log_file_name_cur = os.path.join(Environment('OpenSecurity').log_path, 'vm_cur.log.' + str(cur))
   2.100 +    log_file_lock.acquire()
   2.101 +    try:
   2.102 +        os.rename(log_file_name_new, log_file_name_cur)
   2.103 +        print('new log file: ' + log_file_name_cur)
   2.104 +    except:
   2.105 +        pass
   2.106 +    log_file_lock.release()
   2.107 +
   2.108 +    # now we have a list of next log files to dump
   2.109 +    log_files = glob.glob(os.path.join(Environment('OpenSecurity').log_path, 'vm_cur.log.*'))
   2.110 +    log_files.sort()
   2.111 +    for log_file in log_files:
   2.112 +
   2.113 +        try:
   2.114 +            f = open(log_file, 'rb')
   2.115 +            while True:
   2.116 +                l = pickle.load(f)
   2.117 +                _push_log(l)
   2.118 +
   2.119 +        except EOFError:
   2.120 +
   2.121 +            try:
   2.122 +                os.remove(log_file)
   2.123 +            except:
   2.124 +                logger.warning('tried to delete log file (pushed to EOF) "' + log_file + '" but failed')
   2.125 +
   2.126 +        except:
   2.127 +            logger.warning('encountered error while pushing log file "' + log_file + '"')
   2.128 +
   2.129 +    # start bouncer again ...
   2.130 +    global log_file_bouncer
   2.131 +    log_file_bouncer = threading.Timer(5.0, _bounce_vm_logs)
   2.132 +    log_file_bouncer.start()
   2.133 +
   2.134 +
   2.135 +def _push_log(log):
   2.136 +    """POST a single log to log server
   2.137 +
   2.138 +    @param  log     the log POST param
   2.139 +    """
   2.140 +
   2.141 +    url_addr = 'http://GIMME-SERVER-TO-LOG-TO/log'
   2.142 +
   2.143 +    # by provided a 'data' we turn this into a POST statement
   2.144 +    d = urllib.urlencode(log)
   2.145 +    req = urllib2.Request(url_addr, d)
   2.146 +    urllib2.urlopen(req)
   2.147 +    logger.debug('pushed log to server: ' + str(log))
   2.148 +
   2.149 +
   2.150  def _serve(port):
   2.151  
   2.152      """Start the REST server"""
   2.153  
   2.154      global server
   2.155  
   2.156 +    # start the VM-log bouncer timer
   2.157 +    global log_file_bouncer
   2.158 +    log_file_bouncer = threading.Timer(5.0, _bounce_vm_logs)
   2.159 +    log_file_bouncer.start()
   2.160 +
   2.161      # trick the web.py server 
   2.162      sys.argv = [__file__, str(port)]
   2.163      server = web.application(opensecurity_urls, globals())
   2.164 @@ -521,9 +600,12 @@
   2.165      if server is None:
   2.166          return
   2.167  
   2.168 +    global log_file_bouncer
   2.169 +    if log_file_bouncer is not None:
   2.170 +        log_file_bouncer.cancel()
   2.171 +
   2.172      server.stop()
   2.173  
   2.174 -
   2.175  # start
   2.176  if __name__ == "__main__":
   2.177      serve()