summaryrefslogtreecommitdiffstats
path: root/scripts/automation/trex_control_plane/server/extended_daemon_runner.py
blob: 1813ed481a85a92f25d6a249f317571ae9134d41 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#!/usr/bin/python

import outer_packages
import lockfile
from daemon import runner,daemon
from daemon.runner import *
import os, sys
from argparse import ArgumentParser
from trex_server import trex_parser
try:
    from termstyle import termstyle
except ImportError:
    import termstyle


def daemonize_parser(parser_obj, action_funcs, help_menu):
    """Update the regular process parser to deal with daemon process options"""
    parser_obj.description += " (as a daemon process)"
    parser_obj.usage = None
    parser_obj.add_argument("action", choices=action_funcs,
                            action="store", help=help_menu)
    return


class ExtendedDaemonRunner(runner.DaemonRunner):
    """ Controller for a callable running in a separate background process.

    The first command-line argument is the action to take:

    * 'start': Become a daemon and call `app.run()`.
    * 'stop': Exit the daemon process specified in the PID file.
    * 'restart': Stop, then start.

        """

    help_menu = """Specify action command to be applied on server.
    (*) start      : start the application in as a daemon process.
    (*) show       : prompt an updated status of daemon process (running/ not running).
    (*) stop       : exit the daemon process.
    (*) restart    : stop, then start again the application as daemon process
    (*) start-live : start the application in live mode (no daemon process).
    """

    def __init__(self, app, parser_obj):
        """ Set up the parameters of a new runner.
            THIS METHOD INTENTIONALLY DO NOT INVOKE SUPER __init__() METHOD

            :param app: The application instance; see below.
            :return: ``None``.

            The `app` argument must have the following attributes:

            * `stdin_path`, `stdout_path`, `stderr_path`: Filesystem paths
              to open and replace the existing `sys.stdin`, `sys.stdout`,
              `sys.stderr`.

            * `pidfile_path`: Absolute filesystem path to a file that will
              be used as the PID file for the daemon. If ``None``, no PID
              file will be used.

            * `pidfile_timeout`: Used as the default acquisition timeout
              value supplied to the runner's PID lock file.

            * `run`: Callable that will be invoked when the daemon is
              started.

            """
        super(runner.DaemonRunner, self).__init__()
        # update action_funcs to support more operations
        self.update_action_funcs()

        daemonize_parser(parser_obj, self.action_funcs, ExtendedDaemonRunner.help_menu)
        args = parser_obj.parse_args()
        self.action = unicode(args.action)

        self.app = app
        self.daemon_context = daemon.DaemonContext()
        self.daemon_context.stdin = open(app.stdin_path, 'rt')
        self.daemon_context.stdout = open(app.stdout_path, 'w+t')
        self.daemon_context.stderr = open(app.stderr_path,
                                          'a+t', buffering=0)

        self.pidfile = None
        if app.pidfile_path is not None:
            self.pidfile = make_pidlockfile(app.pidfile_path, app.pidfile_timeout)
        self.daemon_context.pidfile = self.pidfile

        # mask out all arguments that aren't relevant to main app script

    def update_action_funcs(self):
        self.action_funcs.update({u'start-live': self._start_live, u'show': self._show})     # add key (=action), value (=desired func)

    @staticmethod
    def _start_live(self):
        self.app.run()

    @staticmethod
    def _show(self):
        if self.pidfile.is_locked():
            print termstyle.red("T-Rex server daemon is running")
        else:
            print termstyle.red("T-Rex server daemon is NOT running")

    def do_action(self):
        self.__prevent_duplicate_runs()
        self.__prompt_init_msg()
        try:
            super(ExtendedDaemonRunner, self).do_action()
            if self.action == 'stop':
                self.__verify_termination()
        except runner.DaemonRunnerStopFailureError:
            if self.action == 'restart':
                # error means server wasn't running in the first place- so start it!
                self.action = 'start'
                self.do_action()

    
    def __prevent_duplicate_runs(self):
        if self.action == 'start' and self.pidfile.is_locked():
            print termstyle.green("Server daemon is already running")
            exit(1)
        elif self.action == 'stop' and not self.pidfile.is_locked():
            print termstyle.green("Server daemon is not running")
            exit(1)

    def __prompt_init_msg(self):
        if self.action == 'start':
            print termstyle.green("Starting daemon server...")
        elif self.action == 'stop':
            print termstyle.green("Stopping daemon server...")

    def __verify_termination(self):
        pass
#       import time
#       while self.pidfile.is_locked():
#           time.sleep(2)
#           self._stop()
#


if __name__ == "__main__":
    pass