Upload the contribution of vstf as bottleneck network framework.
[bottlenecks.git] / vstf / vstf / common / daemon.py
1 #!/usr/bin/env python
2 import sys, os, time, atexit
3 import logging
4 from signal import SIGTERM
5
6 LOG = logging.getLogger(__name__)
7
8
9 class Daemon(object):
10     """
11     A generic daemon class.
12     
13     Usage: subclass the Daemon class and override the run() method
14     """
15     def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
16         super(Daemon, self).__init__()
17         self.stdin = stdin
18         self.stdout = stdout
19         self.stderr = stderr
20         self.pidfile = pidfile
21     
22     def daemonize(self):
23         """
24         do the UNIX double-fork magic, see Stevens' "Advanced 
25         Programming in the UNIX Environment" for details (ISBN 0201563177)
26         http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
27         """
28         try: 
29             pid = os.fork() 
30             if pid > 0:
31                 sys.exit(0) 
32         except OSError, e: 
33             LOG.error("fork #1 failed: %(errno)s, %(strerror)s",
34                       {'errno':e.errno, 'strerror': e.strerror})
35             sys.exit(1)
36     
37         # decouple from parent environment
38         os.chdir("/") 
39         os.setsid() 
40         os.umask(0) 
41     
42         # do second fork
43         try: 
44             pid = os.fork() 
45             if pid > 0:
46                 # exit from second parent
47                 sys.exit(0) 
48         except OSError, e: 
49             LOG.error("fork #1 failed: %(errno)s, %(strerror)s",
50                       {'errno':e.errno, 'strerror': e.strerror})
51             sys.exit(1) 
52     
53         # redirect standard file descriptors
54         sys.stdout.flush()
55         sys.stderr.flush()
56         si = file(self.stdin, 'r')
57         so = file(self.stdout, 'a+')
58         se = file(self.stderr, 'a+', 0)
59         os.dup2(si.fileno(), sys.stdin.fileno())
60         os.dup2(so.fileno(), sys.stdout.fileno())
61         os.dup2(se.fileno(), sys.stderr.fileno())
62     
63         # write pidfile
64         atexit.register(self.delpid)
65         pid = str(os.getpid())
66         file(self.pidfile,'w+').write("%s\n" % pid)
67     
68     def delpid(self):
69         os.remove(self.pidfile)
70
71     def start(self):
72         """
73         Start the daemon
74         """
75         
76         # Check for a pidfile to see if the daemon already runs
77         try:
78             pf = file(self.pidfile,'r')
79             pid = int(pf.read().strip())
80             pf.close()
81         except IOError:
82             pid = None
83     
84         if pid:
85             message = "pidfile %s already exist. Daemon already running?\n"
86             sys.stderr.write(message % self.pidfile)
87             sys.exit(1)
88         LOG.info("daemon start to run daemonize")
89         # Start the daemon
90         self.daemonize()
91         self.run()
92
93     def stop(self):
94         """
95         Stop the daemon
96         """
97         # Get the pid from the pidfile
98         try:
99             pf = file(self.pidfile,'r')
100             pid = int(pf.read().strip())
101             pf.close()
102         except IOError:
103             pid = None
104     
105         if not pid:
106             message = "pidfile %s does not exist. Daemon not running?\n"
107             sys.stderr.write(message % self.pidfile)
108             return # not an error in a restart
109
110         # Try killing the daemon process    
111         try:
112             while 1:
113                 os.kill(pid, SIGTERM)
114                 time.sleep(0.1)
115         except OSError, err:
116             err = str(err)
117             if err.find("No such process") > 0:
118                 if os.path.exists(self.pidfile):
119                     os.remove(self.pidfile)
120             else:
121                 print str(err)
122                 sys.exit(1)
123
124     def restart(self):
125         """
126         Restart the daemon
127         """
128         self.stop()
129         self.start()
130
131     def run(self):
132         """
133         You should override this method when you subclass Daemon. 
134         It will be called after the process has been
135         daemonized by start() or restart().
136         
137         """
138         pass
139         
140     def daemon_die(self):
141         """You should this method when you shutdown daemon
142         this func will be call by stop() before kill the process
143         
144         """
145         pass