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