source: admin/Sources/Clients/ogagent/src/opengnsys/linux/daemon.py @ 1e8645b

918-git-images-111dconfigfileconfigure-oglivegit-imageslgromero-new-oglivemainmaint-cronmount-efivarfsmultivmmultivm-ogboot-installerogClonningEngineogboot-installer-jenkinsoglive-ipv6test-python-scriptsticket-301ticket-50ticket-50-oldticket-577ticket-585ticket-611ticket-612ticket-693ticket-700ubu24tplunification2use-local-agent-oglivevarios-instalacionwebconsole3
Last change on this file since 1e8645b was c3e7c06, checked in by ramon <ramongomez@…>, 9 years ago

#718: Integrar código fuente de agente OGAgent en rama de desarrollo.

git-svn-id: https://opengnsys.es/svn/branches/version1.1@4865 a21b9725-9963-47de-94b9-378ad31fedc9

  • Property mode set to 100644
File size: 5.8 KB
Line 
1# -*- coding: utf-8 -*-
2#
3# Copyright (c) 2014 Virtual Cable S.L.
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without modification,
7# are permitted provided that the following conditions are met:
8#
9#    * Redistributions of source code must retain the above copyright notice,
10#      this list of conditions and the following disclaimer.
11#    * Redistributions in binary form must reproduce the above copyright notice,
12#      this list of conditions and the following disclaimer in the documentation
13#      and/or other materials provided with the distribution.
14#    * Neither the name of Virtual Cable S.L. nor the names of its contributors
15#      may be used to endorse or promote products derived from this software
16#      without specific prior written permission.
17#
18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28'''
29@author: : http://www.jejik.com/authors/sander_marechal/
30@see: : http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/
31'''
32
33from __future__ import unicode_literals
34import sys
35import os
36import time
37import atexit
38from opengnsys.log import logger
39
40from signal import SIGTERM
41
42
43class Daemon:
44    """
45    A generic daemon class.
46
47    Usage: subclass the Daemon class and override the run() method
48    """
49    def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
50        self.stdin = stdin
51        self.stdout = stdout
52        self.stderr = stderr
53        self.pidfile = pidfile
54
55    def daemonize(self):
56        """
57        do the UNIX double-fork magic, see Stevens' "Advanced
58        Programming in the UNIX Environment" for details (ISBN 0201563177)
59        http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
60        """
61        try:
62            pid = os.fork()
63            if pid > 0:
64                # exit first parent
65                sys.exit(0)
66        except OSError as e:
67            logger.error("fork #1 error: {}".format(e))
68            sys.stderr.write("fork #1 failed: {}\n".format(e))
69            sys.exit(1)
70
71        # decouple from parent environment
72        os.chdir("/")
73        os.setsid()
74        os.umask(0)
75
76        # do second fork
77        try:
78            pid = os.fork()
79            if pid > 0:
80                # exit from second parent
81                sys.exit(0)
82        except OSError as e:
83            logger.error("fork #2 error: {}".format(e))
84            sys.stderr.write("fork #2 failed: {}\n".format(e))
85            sys.exit(1)
86
87        # redirect standard file descriptors
88        sys.stdout.flush()
89        sys.stderr.flush()
90        si = open(self.stdin, 'r')
91        so = open(self.stdout, 'a+')
92        se = open(self.stderr, 'a+', 0)
93        os.dup2(si.fileno(), sys.stdin.fileno())
94        os.dup2(so.fileno(), sys.stdout.fileno())
95        os.dup2(se.fileno(), sys.stderr.fileno())
96
97        # write pidfile
98        atexit.register(self.delpid)
99        pid = str(os.getpid())
100        with open(self.pidfile, 'w+') as f:
101            f.write("{}\n".format(pid))
102
103    def delpid(self):
104        try:
105            os.remove(self.pidfile)
106        except Exception:
107            # Not found/not permissions or whatever...
108            pass
109
110    def start(self):
111        """
112        Start the daemon
113        """
114        logger.debug('Starting daemon')
115        # Check for a pidfile to see if the daemon already runs
116        try:
117            pf = open(self.pidfile, 'r')
118            pid = int(pf.read().strip())
119            pf.close()
120        except IOError:
121            pid = None
122
123        if pid:
124            message = "pidfile {} already exist. Daemon already running?\n".format(pid)
125            logger.error(message)
126            sys.stderr.write(message)
127            sys.exit(1)
128
129        # Start the daemon
130        self.daemonize()
131        try:
132            self.run()
133        except Exception as e:
134            logger.error('Exception running process: {}'.format(e))
135
136        if os.path.exists(self.pidfile):
137            os.remove(self.pidfile)
138
139    def stop(self):
140        """
141        Stop the daemon
142        """
143        # Get the pid from the pidfile
144        try:
145            pf = open(self.pidfile, 'r')
146            pid = int(pf.read().strip())
147            pf.close()
148        except IOError:
149            pid = None
150
151        if pid is None:
152            message = "pidfile {} does not exist. Daemon not running?\n".format(self.pidfile)
153            logger.info(message)
154            # sys.stderr.write(message)
155            return  # not an error in a restart
156
157        # Try killing the daemon process
158        try:
159            while True:
160                os.kill(pid, SIGTERM)
161                time.sleep(1)
162        except OSError as err:
163            if err.errno == 3:  # No such process
164                if os.path.exists(self.pidfile):
165                    os.remove(self.pidfile)
166            else:
167                sys.stderr.write(err)
168                sys.exit(1)
169
170    def restart(self):
171        """
172        Restart the daemon
173        """
174        self.stop()
175        self.start()
176
177    # Overridables
178    def run(self):
179        """
180        You should override this method when you subclass Daemon. It will be called after the process has been
181        daemonized by start() or restart().
182        """
Note: See TracBrowser for help on using the repository browser.