Skip to content

Commit ae5a5f1

Browse files
author
Jiri Pirko
committed
initial
Signed-off-by: Jiri Pirko <[email protected]>
0 parents  commit ae5a5f1

File tree

100 files changed

+5785
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

100 files changed

+5785
-0
lines changed

.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
.*.rej
2+
*.rej
3+
.*~
4+
*~
5+
.#*
6+
# additional patterns:
7+
*.pyc
8+
*.pyo
9+
*.gz
10+
*.orig

COPYING

Lines changed: 339 additions & 0 deletions
Large diffs are not rendered by default.

Common/Daemon.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
"""
2+
This module defines Daemon class useful to daemonize process
3+
4+
Copyright 2011 Red Hat, Inc.
5+
Licensed under the GNU General Public License, version 2 as
6+
published by the Free Software Foundation; see COPYING for details.
7+
"""
8+
9+
__author__ = """
10+
[email protected] (Jiri Pirko)
11+
"""
12+
13+
import logging
14+
import os
15+
import sys
16+
17+
class Daemon:
18+
def __init__(self, pidfile):
19+
self._pidfile = pidfile
20+
self._pid_written = False
21+
22+
def __del__(self):
23+
if self._pid_written:
24+
self._del_pidfile()
25+
26+
def _read_pid(self):
27+
try:
28+
handle = file(self._pidfile, "r")
29+
pid = int(handle.read().strip())
30+
handle.close()
31+
except IOError:
32+
pid = None
33+
return pid
34+
35+
def _write_pid(self, pid):
36+
handle = file(self._pidfile, "w")
37+
handle.write("%s\n" % str(pid))
38+
handle.close()
39+
self._pid_written = True
40+
41+
def _del_pidfile(self):
42+
try:
43+
os.remove(self._pidfile)
44+
except OSError, e:
45+
if e.errno != 2:
46+
raise(e)
47+
48+
def _check_pid(self, pid):
49+
try:
50+
os.kill(pid, 0)
51+
except OSError:
52+
return False
53+
return True
54+
55+
def daemonize(self):
56+
pid = self._read_pid()
57+
if pid:
58+
if self._check_pid(pid):
59+
logging.error("pidfile in use")
60+
os.exit(1)
61+
else:
62+
self._del_pidfile()
63+
try:
64+
pid = os.fork()
65+
if pid > 0:
66+
sys.exit(0)
67+
pid = os.getpid()
68+
self._write_pid(pid)
69+
logging.info("deamonized with pid %d" % pid)
70+
except OSError, e:
71+
logging.error("fork failed: %d (%s)\n" % (e.errno, e.strerror))
72+
sys.exit(1)

Common/ExecCmd.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
"""
2+
This module defines exec_cmd useful for running commands
3+
4+
Copyright 2011 Red Hat, Inc.
5+
Licensed under the GNU General Public License, version 2 as
6+
published by the Free Software Foundation; see COPYING for details.
7+
"""
8+
9+
__author__ = """
10+
[email protected] (Jiri Pirko)
11+
"""
12+
13+
import logging
14+
import subprocess
15+
16+
class ExecCmdFail(Exception):
17+
pass
18+
19+
def log_output(log_func, out_type, out):
20+
log_func("%s:\n"
21+
"----------------------------\n"
22+
"%s"
23+
"----------------------------"
24+
% (out_type, out))
25+
26+
def exec_cmd(cmd, die_on_err=True, log_outputs=True):
27+
cmd = cmd.rstrip(" ")
28+
logging.debug("Executing: \"%s\"" % cmd)
29+
subp = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
30+
stderr=subprocess.PIPE)
31+
(data_stdout, data_stderr) = subp.communicate()
32+
33+
'''
34+
When we should not die on error, do not print anything and let
35+
the caller to decide what to do.
36+
'''
37+
if log_outputs:
38+
if data_stdout:
39+
log_output(logging.debug, "Stdout", data_stdout)
40+
if data_stderr:
41+
log_output(logging.error, "Stderr", data_stderr)
42+
if subp.returncode and die_on_err:
43+
logging.error("Command failed with error \"%d\"" % subp.returncode)
44+
raise ExecCmdFail
45+
46+
return data_stdout, data_stderr

Common/LoggingServer.py

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
"""
2+
Logging server.
3+
Listen connection from logging client.
4+
5+
Copyright 2011 Red Hat, Inc.
6+
Licensed under the GNU General Public License, version 2 as
7+
published by the Free Software Foundation; see COPYING for details.
8+
"""
9+
10+
__autor__ = """
11+
[email protected] (Jiri Zupka)
12+
"""
13+
14+
import socket, struct, cPickle, logging
15+
from Common.Logs import Logs
16+
import signal, sys, os, select, time
17+
from Common.Utils import die_when_parent_die
18+
19+
20+
class LoggingServer:
21+
DEFAULT_PORT = 9998
22+
def __init__(self, port, root_path, debug):
23+
self.port = port
24+
self.pid = None
25+
self.socket = None
26+
self.stopped = False
27+
self.root_path = root_path
28+
self.debug = debug
29+
self.childSocket = {}
30+
31+
32+
def server_stop_handler(self, sig, frame):
33+
"""
34+
Call function. Used for signal handle.
35+
"""
36+
if (sig == signal.SIGTERM):
37+
for sock in self.childSocket.itervalues():
38+
sock[2].close()
39+
self.socket.shutdown(socket.SHUT_RDWR)
40+
self.socket.close()
41+
sys.exit()
42+
43+
44+
def start(self):
45+
"""
46+
Start logging server as separate process.
47+
48+
@param port: Port on which logging server listen.
49+
@return: Pid of logging process.
50+
"""
51+
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
52+
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
53+
try:
54+
self.socket.bind(('0.0.0.0',self.port))
55+
except socket.error, e:
56+
if (e.errno == 98):
57+
logging.error("Another Logging server listen"
58+
" on port %d" % self.port)
59+
raise
60+
self.pid = os.fork()
61+
if not self.pid:
62+
die_when_parent_die()
63+
signal.signal(signal.SIGTERM, self.server_stop_handler)
64+
self._forked()
65+
else:
66+
time.sleep(0.5)
67+
68+
69+
def prepare_logging(self, root_path, sock):
70+
address = sock[1][0]
71+
slave_root_path = os.path.join(root_path, address)
72+
try:
73+
os.mkdir(slave_root_path)
74+
except OSError, e:
75+
if e.errno != 17:
76+
raise
77+
logger = logging.getLogger(address)
78+
Logs(self.debug, False, logger,
79+
log_root=slave_root_path,
80+
to_display=False)
81+
return (logger, address, sock[0])
82+
83+
84+
def recv_slave_log(self, logger, address, sock):
85+
try:
86+
dataLen = sock.recv(4)
87+
if dataLen == '':
88+
raise Exception("Client %s close connection."
89+
% (address))
90+
dataLen = struct.unpack('>L',dataLen)[0]
91+
data = ''
92+
while (len(data) != dataLen):
93+
d = sock.recv(dataLen)
94+
if d == '':
95+
print "Client %s close connection."% (address)
96+
raise Exception("Client %s close connection."
97+
% (address))
98+
data += d
99+
report = cPickle.loads(data)
100+
record = logging.makeLogRecord(report)
101+
record.address = "(" + address + ")"
102+
logger.handle(record)
103+
except Exception,e:
104+
logger.debug(e)
105+
return False
106+
return True
107+
108+
109+
def _forked(self):
110+
"""
111+
Start logging server.
112+
113+
@param port: Port for listening.
114+
"""
115+
self.socket.listen(100)
116+
wait_socket = [self.socket.fileno()]
117+
while True:
118+
(r,w,e) = select.select(wait_socket, [], [])
119+
if (self.socket.fileno() in r):
120+
csock = self.socket.accept()
121+
slave = self.prepare_logging(self.root_path, csock)
122+
self.childSocket[csock[0].fileno()] = slave
123+
wait_socket.append(slave[2].fileno())
124+
r.remove(self.socket.fileno())
125+
for so in r:
126+
if not self.recv_slave_log(*self.childSocket[so]):
127+
self.childSocket[so][2].close()
128+
del self.childSocket[so]
129+
wait_socket.remove(so)
130+
self.socket.close()
131+
sys.exit()
132+
133+
134+
def stop(self):
135+
if self.pid and not self.stopped:
136+
self.stopped = True
137+
os.kill(self.pid, signal.SIGTERM)
138+
try:
139+
os.waitpid(self.pid, 0)
140+
except OSError, e:
141+
if e.errno == 10:
142+
pass
143+
144+
145+
def getpid(self):
146+
return self.pid
147+
148+
149+
if __name__ == '__main__':
150+
logger = logging.getLogger()
151+
c = logging.FileHandler("out.txt")
152+
logger.addHandler(c)
153+
l = LoggingServer(LoggingServer.DEFAULT_PORT)
154+
l.start()
155+
raw_input()
156+
l.stop()

0 commit comments

Comments
 (0)