alarm_manager.py 5.02 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
""" Alarm manager for TCP logs. The module launches an
:class:`~AlarmManager.AlarmManager` object which will
listen for alarm logs over a TCP socket."""

# Imports
from sys import argv
from configparser import Error as ConfigError
from argparse import ArgumentParser, Namespace

# Third party
Carlos Vigo's avatar
Carlos Vigo committed
11
from lab_utils.custom_logging import configure_logging, getLogger
12
13
14
15
16
17
18
19
20
21
from lab_utils.socket_comm import Client
from zc.lockfile import LockError

# Local packages
from alarm_manager.AlarmManager import AlarmManager
from alarm_manager.__project__ import (
    __documentation__ as docs_url,
    __module_name__ as module,
    __description__ as prog_desc,
)
Carlos Vigo's avatar
Carlos Vigo committed
22
23
24


def alarm_manager():
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
    """The main routine. It parses the input argument and acts accordingly.

    If the module is called with no argument or with the 'start' option,
    an :class:`~AlarmManager.AlarmManager` object will be started, provided
    one is not already running. Arguments two and three, if supplied, are the
    alarm and the logging configuration files respectively.

    If the module is called with any other argument besides 'start', a TCP
    message will be sent to the running instance of the alarm manager, and
    its reply will be printed."""

    # The argument parser
    ap = ArgumentParser(
        prog=module,
        description=prog_desc,
        add_help=True,
        epilog='Check out the package documentation for more information:\n{}'.format(docs_url)
    )

    # Optional arguments
    ap.add_argument(
        '-l',
        '--logging-config-file',
        help='configuration file with the logging options',
        default=None,
        dest='logging_config_file',
        type=str,
    )
    ap.add_argument(
        '-s',
        '--server-config-file',
        help='configuration file with the Alarm Manager options',
        default=None,
        dest='server_config_file',
        type=str,
    )
    ap.add_argument(
        '-a',
        '--address',
        help='host address',
        default=None,
        dest='host',
        type=str
    )
    ap.add_argument(
        '-p',
        '--port',
        help='host port',
        default=None,
        dest='port',
        type=int
    )

    # Main positional argument: control
    choices_list = [
        'run',
        'quit',
        'status',
    ]
    help_desc = 'starts, stops or checks the status of the Alarm Manager'
    ap.add_argument(
        dest='control',
        choices=choices_list,
        type=str,
        help=help_desc,
        default='status',
        nargs='?',
    )

    # Parse the arguments
    args: Namespace = ap.parse_args(args=argv[1:])

    # Setup logging
    configure_logging(
        config_file=args.logging_config_file,
        logger_name='Alarm Manager'
    )

    # Call appropriate function
    if args.control == 'run':
        run(args)
    else:
        send_message(args)


def send_message(args: Namespace):
    """ Sends a string message to a running
    :class:`AlarmManager` object over TCP."""

    try:
        # Start a client
        c = Client(
            config_file=args.server_config_file,
            host=args.host,
            port=args.port,
        )
        getLogger().info('Opening connection to the Alarm Manager server on {h}:{p}'.format(
            h=c.host,
            p=c.port
        ))

        # Send message and get reply
        getLogger().info('Sending message: %s', args.control)
        reply = c.send_message(args.control)
        getLogger().info(reply)

    except ConfigError as e:
        getLogger().error('Did you provide a valid configuration file?')

    except OSError as e:
        getLogger().error('Maybe the Alarm Manager server is not running, or running elsewhere')

    except BaseException as e:
        # Undefined exception, full traceback to be printed
        getLogger().exception("{}: {}".format(type(e).__name__, e))

    else:
        exit(0)
    exit(1)


def run(args: Namespace):
    """ Launches an :class:`AlarmManager` object."""

    try:
        # Start the daemon
        getLogger().info('Starting Alarm Manager server...')
        the_alarm_manager = AlarmManager(
            config_file=args.server_config_file,
            pid_file_name='/tmp/alarm_manager.pid',
            host=args.host,
            port=args.port,
        )
        the_alarm_manager.start_daemon()
        getLogger().info('Alarm Manager server stopped, bye!')

    except ConfigError as e:
        getLogger().error("{}: {}".format(type(e).__name__, e))
        getLogger().error('Did you provide a valid configuration file?')

    except OSError as e:
        getLogger().error("{}: {}".format(type(e).__name__, e))
        getLogger().error('Possible socket error, do you have permissions to the socket?')

    except LockError as e:
        getLogger().error("{}: {}".format(type(e).__name__, e))
        getLogger().error('Alarm Manager daemon is probably running elsewhere.')

    except BaseException as e:
        # Undefined exception, full traceback to be printed
        getLogger().exception("{}: {}".format(type(e).__name__, e))

    else:
        exit(0)

    exit(1)