source: fedd/fedd.py @ 0a20ef8

axis_examplecompt_changesinfo-opsversion-1.30version-2.00version-3.01version-3.02
Last change on this file since 0a20ef8 was 0a20ef8, checked in by Ted Faber <faber@…>, 16 years ago

Cleaner split for module definition

  • Property mode set to 100755
File size: 5.3 KB
Line 
1#!/usr/local/bin/python
2
3import sys
4
5from optparse import OptionParser
6
7from fedd_server import fedd_server, fedd_xmlrpc_handler, fedd_soap_handler
8from fedd_config_parser import fedd_config_parser
9from fedd_util import fedd_ssl_context
10from fedd_deter_impl import new_feddservice
11
12from threading import *
13from signal import signal, pause, SIGINT, SIGTERM
14from select import select, error
15from time import sleep
16import logging
17
18class fedd_opts(OptionParser):
19    """Encapsulate option processing in this class, rather than in main"""
20    def __init__(self):
21        OptionParser.__init__(self, usage="%prog [opts] (--help for details)",
22                version="0.1")
23
24        self.set_defaults(logfile=None, debug=0)
25
26        self.add_option("-d", "--debug", action="count", dest="debug", 
27                help="Set debug.  Repeat for more information")
28        self.add_option("-f", "--configfile", action="store",
29                default="/usr/local/etc/fedd.conf",
30                dest="configfile", help="Configuration file (required)")
31        self.add_option("-l", "--logfile", action="store", dest="logfile", 
32                help="File to send log messages to")
33        self.add_option("--trace", action="store_const", dest="tracefile", 
34                const=sys.stderr, help="Print SOAP exchange to stderr")
35
36servers_active = True       # Sub-servers run while this is True
37servers = [ ]               # fedd_server instances instantiated from services
38servers_lock = Lock()       # Lock to manipulate servers from sub-server threads
39
40def shutdown(sig, frame):
41    """
42    On a signal, stop running sub-servers. 
43   
44    This is connected to signals below
45    """
46    global servers_active, flog
47
48    servers_active = False
49    flog.info("Received signal %d, shutting down" % sig);
50
51def run_server(s):
52    """
53    Operate a subserver, shutting down when servers_active is false.
54
55    Each server (that is host/port/transport triple) has a thread running this
56    function, so each can handle requests independently.  They all call in to
57    the same implementation, which must manage its own synchronization.
58    """
59    global servers_active   # Not strictly needed: servers_active is only read
60    global servers          # List of active servers
61    global servers_lock     # Lock to manipulate servers
62
63    while servers_active:
64        try:
65            i, o, e = select((s,), (), (), 1.0)
66            if s in i: s.handle_request()
67        except error:
68            # The select call seems to get interrupted by signals as well as
69            # the main thread.  This essentially ignores signals in this
70            # thread.
71            pass
72
73    # Done.  Remove us from the list
74    servers_lock.acquire()
75    servers.remove(s)
76    servers_lock.release()
77
78opts, args = fedd_opts().parse_args()
79
80# Logging setup
81flog = logging.getLogger("fedd")
82ffmt = logging.Formatter("%(asctime)s %(name)s %(message)s",
83        '%d %b %y %H:%M:%S')
84
85if opts.logfile: fh = logging.FileHandler(opts.logfile)
86else: fh = logging.StreamHandler(sys.stdout)
87
88# The handler will print anything, setting the logger level will affect what
89# gets recorded.
90fh.setLevel(logging.DEBUG)
91
92if opts.debug: flog.setLevel(logging.DEBUG)
93else: flog.setLevel(logging.INFO)
94
95fh.setFormatter(ffmt)
96flog.addHandler(fh)
97
98
99
100# Initialize the implementation
101if opts.configfile != None: 
102    try:
103        config= fedd_config_parser()
104        config.read(opts.configfile)
105    except e:
106        sys.exit("Cannot parse confgi file: %s" % e)
107else: 
108    sys.exit("--configfile is required")
109
110try:
111    impl = new_feddservice(config)
112except RuntimeError, e:
113    str = getattr(e, 'desc', None) or getattr(e,'message', None) or \
114            "No message"
115    sys.exit("Error configuring fedd: %s" % str)
116
117if impl.cert_file == None:
118    sys.exit("Must supply certificate file (probably in config)")
119
120# Create the SSL credentials
121ctx = None
122while ctx == None:
123    try:
124        ctx = fedd_ssl_context(impl.cert_file, impl.trusted_certs, 
125                password=impl.cert_pwd)
126    except SSL.SSLError, e:
127        if str(e) != "bad decrypt" or impl.cert_pwd != None:
128            raise
129
130services = config.get("globals", "services", "23235")
131
132for s in services.split(","):
133    s = s.strip()
134    colons = s.count(":")
135    try:
136        if colons == 0:
137            p = int(s)
138            h = ''
139            t = 'soap'
140        elif colons == 1:
141            p, t  = s.split(":")
142            p = int(p)
143            h = ''
144        elif colons == 2:
145            h, p, t  = s.split(":")
146            p = int(p)
147        else:
148            flog.error("Invalid service specification %s ignored." % s)
149            continue
150    except ValueError:
151        flog.error("Error converting port to integer in %s: spec ignored" % s)
152        continue
153
154    t = t.lower()
155    try:
156        if t == 'soap':
157            servers.append(fedd_server((h, p), fedd_soap_handler, ctx, impl))
158        elif t == 'xmlrpc':
159            servers.append(fedd_server((h, p), fedd_xmlrpc_handler, ctx, impl))
160        else:
161            flog.error("Invalid transport specification (%s) in service %s" % \
162                    (t, s))
163            continue
164    except socket_error, e:
165        flog.error("Cannot create server for %s: %s" % (s, e[1]))
166        continue
167
168#  Make sure that there are no malformed servers in the list
169servers = [ s for s in servers if s ]
170
171# Catch signals
172signal(SIGINT, shutdown)
173signal(SIGTERM, shutdown)
174
175# Start the servers
176for s in servers:
177    Thread(target=run_server, args=(s,)).start()
178
179# Main thread waits for signals
180while servers_active:
181    sleep(1.0)
182
183#Once shutdown starts wait for all the servers to terminate.
184while True:
185    servers_lock.acquire()
186    if len(servers) == 0: 
187        servers_lock.release()
188        flog.info("All servers exited.  Terminating")
189        sys.exit(0)
190    servers_lock.release()
191    sleep(1)
192
Note: See TracBrowser for help on using the repository browser.