zonemgr.py.in 20.9 KB
Newer Older
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
#!@PYTHON@

# Copyright (C) 2010  Internet Systems Consortium.
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

"""\
This file implements the Secondary Manager program.

The secondary manager is one of the co-operating processes
of BIND10, which keeps track of timers and other information
necessary for BIND10 to act as a slave.
"""

import sys; sys.path.append ('@@PYTHONPATH@@')
import os
import time
import signal
import isc
import random
import threading
import select
import socket
35
import errno
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
from isc.datasrc import sqlite3_ds
from optparse import OptionParser, OptionValueError
from isc.config.ccsession import *

# If B10_FROM_BUILD is set in the environment, we use data files
# from a directory relative to that, otherwise we use the ones
# installed on the system
if "B10_FROM_BUILD" in os.environ:
    SPECFILE_PATH = os.environ["B10_FROM_BUILD"] + "/src/bin/zonemgr"
    AUTH_SPECFILE_PATH = os.environ["B10_FROM_BUILD"] + "/src/bin/auth"
else:
    PREFIX = "@prefix@"
    DATAROOTDIR = "@datarootdir@"
    SPECFILE_PATH = "@datadir@/@PACKAGE@".replace("${datarootdir}", DATAROOTDIR).replace("${prefix}", PREFIX)
    AUTH_SPECFILE_PATH = SPECFILE_PATH

SPECFILE_LOCATION = SPECFILE_PATH + "/zonemgr.spec"
AUTH_SPECFILE_LOCATION = AUTH_SPECFILE_PATH + "/auth.spec"

__version__ = "BIND10"

57
# define module name
Jerry's avatar
Jerry committed
58
59
XFRIN_MODULE_NAME = 'Xfrin'
AUTH_MODULE_NAME = 'Auth'
60

61
# define command name
Jerry's avatar
Jerry committed
62
63
ZONE_XFRIN_FAILED_COMMAND = 'zone_xfrin_failed'
ZONE_XFRIN_SUCCESS_COMMAND = 'zone_new_data_ready'
64
ZONE_REFRESH_COMMAND = 'refresh_from_zonemgr'
Jerry's avatar
Jerry committed
65
ZONE_NOTIFY_COMMAND = 'notify'
66

67
68
69
70
71
72
# define zone state
ZONE_OK = 0
ZONE_REFRESHING = 1
ZONE_EXPIRED = 2

# smallest refresh timeout
Jerry's avatar
Jerry committed
73
LOWERBOUND_REFRESH = 10
74
# smallest retry timeout
Jerry's avatar
Jerry committed
75
LOWERBOUND_RETRY = 5
76
77
78
# max zone transfer timeout
MAX_TRANSFER_TIMEOUT = 14400

79
80
81
82
83
84
85
86
87
88
89
90
# offsets of fields in the SOA RDATA
REFRESH_OFFSET = 3
RETRY_OFFSET = 4
EXPIRED_OFFSET = 5

# verbose mode
VERBOSE_MODE = False

def log_msg(msg):
    if VERBOSE_MODE:
        sys.stdout.write("[b10-zonemgr] %s\n" % str(msg))

91
92
93
class ZonemgrException(Exception):
    pass

94
95
96
97
98
class ZonemgrRefresh:
    """This class will maintain and manage zone refresh info.
    It also provides methods to keep track of zone timers and 
    do zone refresh.
    """
99

100
    def __init__(self, cc, db_file, slave_socket):
101
        self._cc = cc
102
        self._socket = slave_socket 
103
        self._db_file = db_file
Jerry's avatar
Jerry committed
104
        self._zonemgr_refresh_info = {} 
105
        self._build_zonemgr_refresh_info()
106
107
108
109
    
    def _random_jitter(self, max, jitter):
        """Imposes some random jitters for refresh and
        retry timers to avoid many zones need to do refresh
110
111
112
        at the same time. 
        The value should be between (max - jitter) and max.
        """
113
114
        if 0 == jitter:
            return max
115
        return random.uniform(max - jitter, max)
116
117
118
119

    def _get_current_time(self):
        return time.time()

Jerry's avatar
Jerry committed
120
    def _set_zone_timer(self, zone_name_class, max, jitter):
121
        """Set zone next refresh time."""
Jerry's avatar
Jerry committed
122
        self._set_zone_next_refresh_time(zone_name_class, self._get_current_time() + \
123
                                            self._random_jitter(max, jitter))
124

Jerry's avatar
Jerry committed
125
    def _set_zone_refresh_timer(self, zone_name_class):
126
127
128
        """Set zone next refresh time after zone refresh success.
           now + refresh*3/4 <= next_refresh_time <= now + refresh
           """
129
130
        zone_refresh_time = float(self._get_zone_soa_rdata(zone_name_class).split(" ")[REFRESH_OFFSET])
        zone_refresh_time = max(LOWERBOUND_REFRESH, zone_refresh_time)
Jerry's avatar
Jerry committed
131
        self._set_zone_timer(zone_name_class, zone_refresh_time, (1 * zone_refresh_time) / 4)
132

Jerry's avatar
Jerry committed
133
    def _set_zone_retry_timer(self, zone_name_class):
134
135
136
        """Set zone next refresh time after zone refresh fail.
           now + retry*3/4 <= next_refresh_time <= now + retry
           """
137
138
        zone_retry_time = float(self._get_zone_soa_rdata(zone_name_class).split(" ")[RETRY_OFFSET])
        zone_retry_time = max(LOWERBOUND_RETRY, zone_retry_time)
Jerry's avatar
Jerry committed
139
        self._set_zone_timer(zone_name_class, zone_retry_time, (1 * zone_retry_time) / 4)
140

Jerry's avatar
Jerry committed
141
    def _set_zone_notify_timer(self, zone_name_class):
142
143
144
        """Set zone next refresh time after receiving notify
           next_refresh_time = now 
        """
Jerry's avatar
Jerry committed
145
        self._set_zone_timer(zone_name_class, 0, 0)
146

Jerry's avatar
Jerry committed
147
    def _zone_not_exist(self, zone_name_class):
148
        """ Zone doesn't belong to zonemgr"""
Jerry's avatar
Jerry committed
149
150
151
152
153
        if zone_name_class in self._zonemgr_refresh_info.keys():
            return False
        return True

    def zone_refresh_success(self, zone_name_class):
154
        """Update zone info after zone refresh success"""
Jerry's avatar
Jerry committed
155
        if (self._zone_not_exist(zone_name_class)):
156
157
            raise ZonemgrException("[b10-zonemgr] Zone (%s, %s) doesn't "
                                   "belong to zonemgr" % zone_name_class)
158
            return
159
        self.zonemgr_reload_zone(zone_name_class)
Jerry's avatar
Jerry committed
160
161
162
        self._set_zone_refresh_timer(zone_name_class)
        self._set_zone_state(zone_name_class, ZONE_OK)
        self._set_zone_last_refresh_time(zone_name_class, self._get_current_time())
163

Jerry's avatar
Jerry committed
164
    def zone_refresh_fail(self, zone_name_class):
165
        """Update zone info after zone refresh fail"""
Jerry's avatar
Jerry committed
166
        if (self._zone_not_exist(zone_name_class)):
167
168
            raise ZonemgrException("[b10-zonemgr] Zone (%s, %s) doesn't "
                                   "belong to zonemgr" % zone_name_class)
169
            return
Jerry's avatar
Jerry committed
170
171
        self._set_zone_state(zone_name_class, ZONE_OK)
        self._set_zone_retry_timer(zone_name_class)
172

Jerry's avatar
Jerry committed
173
    def zone_handle_notify(self, zone_name_class, master):
174
        """Handle zone notify"""
Jerry's avatar
Jerry committed
175
        if (self._zone_not_exist(zone_name_class)):
176
177
            raise ZonemgrException("[b10-zonemgr] Notified zone (%s, %s) "
                                   "doesn't belong to zonemgr" % zone_name_class)
178
            return
Jerry's avatar
Jerry committed
179
180
        self._set_zone_notifier_master(zone_name_class, master)
        self._set_zone_notify_timer(zone_name_class)
181

182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
    def zonemgr_reload_zone(self, zone_name_class):
        """ Reload a zone."""
        zone_soa = sqlite3_ds.get_zone_soa(str(zone_name_class[0]), self._db_file)
        self._zonemgr_refresh_info[zone_name_class]["zone_soa_rdata"] = zone_soa[7]

    def zonemgr_add_zone(self, zone_name_class):
        """ Add a zone into zone manager."""
        zone_info = {}
        zone_soa = sqlite3_ds.get_zone_soa(str(zone_name_class[0]), self._db_file)
        if not zone_soa:
            raise ZonemgrException("[b10-zonemgr] zone (%s, %s) doesn't have soa." % zone_name_class)
        zone_info["zone_soa_rdata"] = zone_soa[7]
        zone_info["zone_state"] = ZONE_OK
        zone_info["last_refresh_time"] = self._get_current_time() 
        zone_info["next_refresh_time"] = self._get_current_time() + \
                                         float(zone_soa[7].split(" ")[REFRESH_OFFSET])
        self._zonemgr_refresh_info[zone_name_class] = zone_info

200
    def _build_zonemgr_refresh_info(self):
201
        """ Build zonemgr refresh info map."""
202
        log_msg("Start loading zone into zonemgr.")
Jerry's avatar
Jerry committed
203
        for zone_name, zone_class in sqlite3_ds.get_zones_info(self._db_file):
204
205
206
            zone_name_class = (zone_name, zone_class)
            self.zonemgr_add_zone(zone_name_class)
        log_msg("Finish loading zone into zonemgr.")
207

Jerry's avatar
Jerry committed
208
    def _zone_is_expired(self, zone_name_class):
209
210
        """Judge whether a zone is expired or not."""
        zone_expired_time = float(self._get_zone_soa_rdata(zone_name_class).split(" ")[EXPIRED_OFFSET])
Jerry's avatar
Jerry committed
211
212
        zone_last_refresh_time = self._get_zone_last_refresh_time(zone_name_class)
        if (ZONE_EXPIRED == self._get_zone_state(zone_name_class) or
213
214
215
216
217
            zone_last_refresh_time + zone_expired_time <= self._get_current_time()):
            return True

        return False

Jerry's avatar
Jerry committed
218
219
    def _get_zone_soa_rdata(self, zone_name_class):
        return self._zonemgr_refresh_info[zone_name_class]["zone_soa_rdata"]
220

Jerry's avatar
Jerry committed
221
222
    def _get_zone_last_refresh_time(self, zone_name_class):
        return self._zonemgr_refresh_info[zone_name_class]["last_refresh_time"]
223

Jerry's avatar
Jerry committed
224
225
    def _set_zone_last_refresh_time(self, zone_name_class, time):
        self._zonemgr_refresh_info[zone_name_class]["last_refresh_time"] = time
226

Jerry's avatar
Jerry committed
227
228
229
    def _get_zone_notifier_master(self, zone_name_class):
        if ("notify_master" in self._zonemgr_refresh_info[zone_name_class].keys()):
            return self._zonemgr_refresh_info[zone_name_class]["notify_master"] 
230
231
232

        return None

Jerry's avatar
Jerry committed
233
234
    def _set_zone_notifier_master(self, zone_name_class, master_addr):
        self._zonemgr_refresh_info[zone_name_class]["notify_master"] = master_addr
235

Jerry's avatar
Jerry committed
236
237
238
    def _clear_zone_notifier_master(self, zone_name_class):
        if ("notify_master" in self._zonemgr_refresh_info[zone_name_class].keys()):
            del self._zonemgr_refresh_info[zone_name_class]["notify_master"]
239

Jerry's avatar
Jerry committed
240
241
    def _get_zone_state(self, zone_name_class):
        return self._zonemgr_refresh_info[zone_name_class]["zone_state"]
242

Jerry's avatar
Jerry committed
243
244
    def _set_zone_state(self, zone_name_class, zone_state):
        self._zonemgr_refresh_info[zone_name_class]["zone_state"] = zone_state 
245

Jerry's avatar
Jerry committed
246
247
    def _get_zone_refresh_timeout(self, zone_name_class):
        return self._zonemgr_refresh_info[zone_name_class]["refresh_timeout"]
248

Jerry's avatar
Jerry committed
249
250
    def _set_zone_refresh_timeout(self, zone_name_class, time):
        self._zonemgr_refresh_info[zone_name_class]["refresh_timeout"] = time
251

Jerry's avatar
Jerry committed
252
253
    def _get_zone_next_refresh_time(self, zone_name_class):
        return self._zonemgr_refresh_info[zone_name_class]["next_refresh_time"]
254

Jerry's avatar
Jerry committed
255
256
    def _set_zone_next_refresh_time(self, zone_name_class, time):
        self._zonemgr_refresh_info[zone_name_class]["next_refresh_time"] = time
257
258

    def _send_command(self, module_name, command_name, params):
259
        """Send command between modules."""
260
        msg = create_command(command_name, params)
261
262
263
        try:
            self._cc.group_sendmsg(msg, module_name)
        except socket.error:
Jerry's avatar
Jerry committed
264
            sys.err.write("[b10-zonemgr] Failed to send to module %s, the session has been closed." % module_name) 
265

Jerry's avatar
Jerry committed
266
267
268
269
270
271
    def _find_need_do_refresh_zone(self):
        """Find the first zone need do refresh, if no zone need
        do refresh, return the zone with minimum next_refresh_time.
        """
        zone_need_refresh = None
        for zone_name_class in self._zonemgr_refresh_info.keys():
272
            # Does the zone expired?
Jerry's avatar
Jerry committed
273
274
            if (ZONE_EXPIRED != self._get_zone_state(zone_name_class) and 
                self._zone_is_expired(zone_name_class)):
275
                log_msg("Zone (%s, %s) is expired." % zone_name_class)
Jerry's avatar
Jerry committed
276
                self._set_zone_state(zone_name_class, ZONE_EXPIRED)
277

Jerry's avatar
Jerry committed
278
            zone_state = self._get_zone_state(zone_name_class)
279
280
            # If zone is expired and doesn't receive notify, skip the zone
            if (ZONE_EXPIRED == zone_state and 
Jerry's avatar
Jerry committed
281
                (not self._get_zone_notifier_master(zone_name_class))):
282
283
                continue

284
            # If hasn't received refresh response but are within refresh timeout, skip the zone
285
            if (ZONE_REFRESHING == zone_state and
Jerry's avatar
Jerry committed
286
                (self._get_zone_refresh_timeout(zone_name_class) > self._get_current_time())):
287
288
                continue
                    
Jerry's avatar
Jerry committed
289
290
291
            # Get the zone with minimum next_refresh_time 
            if ((None == zone_need_refresh) or 
                (self._get_zone_next_refresh_time(zone_name_class) < 
292
                 self._get_zone_next_refresh_time(zone_need_refresh))):
Jerry's avatar
Jerry committed
293
294
                zone_need_refresh = zone_name_class

295
            # Find the zone need do refresh
Jerry's avatar
Jerry committed
296
297
            if (self._get_zone_next_refresh_time(zone_need_refresh) < self._get_current_time()):
                break
298

Jerry's avatar
Jerry committed
299
        return zone_need_refresh 
300
301

    
Jerry's avatar
Jerry committed
302
    def _do_refresh(self, zone_name_class):
303
        """Do zone refresh."""
304
        log_msg("Do refresh for zone (%s, %s)." % zone_name_class)
Jerry's avatar
Jerry committed
305
306
307
        self._set_zone_state(zone_name_class, ZONE_REFRESHING)
        self._set_zone_refresh_timeout(zone_name_class, self._get_current_time() + MAX_TRANSFER_TIMEOUT) 
        notify_master = self._get_zone_notifier_master(zone_name_class)
308
        # If the zone has notify master, send notify command to xfrin module
309
        if notify_master:
Jerry's avatar
Jerry committed
310
311
            param = {"zone_name" : zone_name_class[0],
                     "zone_class" : zone_name_class[1],
312
                     "master" : notify_master
313
                     }
Jerry's avatar
Jerry committed
314
            self._send_command(XFRIN_MODULE_NAME, ZONE_NOTIFY_COMMAND, param) 
Jerry's avatar
Jerry committed
315
            self._clear_zone_notifier_master(zone_name_class)
316
317
        # Send refresh command to xfrin module
        else:
Jerry's avatar
Jerry committed
318
319
320
            param = {"zone_name" : zone_name_class[0],
                     "zone_class" : zone_name_class[1]
                    }
Jerry's avatar
Jerry committed
321
            self._send_command(XFRIN_MODULE_NAME, ZONE_REFRESH_COMMAND, param)
322
323
324

    def _zone_mgr_is_empty(self):
        """Does zone manager has no zone?"""
Jerry's avatar
Jerry committed
325
        if not len(self._zonemgr_refresh_info):
326
327
328
329
330
            return True

        return False

    def run_timer(self):
331
        """Keep track of zone timers."""
332
        while True:
333
            # Zonemgr has no zone.
334
            if self._zone_mgr_is_empty():
Jerry's avatar
Jerry committed
335
                time.sleep(LOWERBOUND_RETRY) # A better time?
336
337
                continue

Jerry's avatar
Jerry committed
338
            zone_need_refresh = self._find_need_do_refresh_zone()
339
            # If don't get zone with minimum next refresh time, set timer timeout = LOWERBOUND_REFRESH
Jerry's avatar
Jerry committed
340
            if not zone_need_refresh:
Jerry's avatar
Jerry committed
341
                timeout = LOWERBOUND_RETRY
342
            else:
343
344
                timeout = self._get_zone_next_refresh_time(zone_need_refresh) - self._get_current_time()
                if (timeout < 0):
Jerry's avatar
Jerry committed
345
                    self._do_refresh(zone_need_refresh)
346
347
                    continue

348
349
            """ Wait for the socket notification for a maximum time of timeout 
            in seconds (as float)."""
350
351
352
            try:
                (rlist, wlist, xlist) = select.select([self._socket], [], [], timeout)
                if rlist:
Jerry's avatar
Jerry committed
353
354
                    self._socket.recv(32)
            except ValueError as e:
Jerry's avatar
Jerry committed
355
                raise ZonemgrException("[b10-zonemgr] Socket has been closed\n")
Jerry's avatar
Jerry committed
356
                break
357
358
359
360
            except select.error as e:
                if e.args[0] == errno.EINTR:
                    (rlist, wlist, xlist) = ([], [], [])
                else:
361
                    raise ZonemgrException("[b10-zonemgr] Error with select(): %s\n" % e)
362
363
364
                    break


365
366
367
class Zonemgr:
    """Zone manager class."""
    def __init__(self):
368
369
        self._setup_session()
        self._db_file = self.get_db_file()
370
        # Create socket pair for communicating between main thread and zonemgr timer thread 
Jerry's avatar
Jerry committed
371
        self._master_socket, self._slave_socket = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM)
372
        self._zone_refresh= ZonemgrRefresh(self._cc, self._db_file, self._slave_socket)
373
374
        self._start_zone_refresh_timer()

375
        self._lock = threading.Lock()
376
377
378
        self._shutdown_event = threading.Event()

    def _start_zone_refresh_timer(self):
Jerry's avatar
Jerry committed
379
        """Start a new thread to keep track of zone timers"""
380
        listener = threading.Thread(target = self._zone_refresh.run_timer, args = ())
381
        listener.setDaemon(True)
382
383
384
        listener.start()

    def _setup_session(self):
385
386
387
        """Setup two sessions for zonemgr, one(self._module_cc) is used for receiving 
        commands and config data sent from other modules, another one (self._cc)
        is used to send commands to proper modules."""
388
389
390
391
        self._cc = isc.cc.Session()
        self._module_cc = isc.config.ModuleCCSession(SPECFILE_LOCATION,
                                                  self.config_handler,
                                                  self.command_handler)
392
        self._module_cc.add_remote_config(AUTH_SPECFILE_LOCATION)
393
394
395
396
        self._config_data = self._module_cc.get_full_config()
        self._module_cc.start()

    def get_db_file(self):
Jerry's avatar
Jerry committed
397
        db_file, is_default = self._module_cc.get_remote_config_value(AUTH_MODULE_NAME, "database_file")
398
399
400
        # this too should be unnecessary, but currently the
        # 'from build' override isn't stored in the config
        # (and we don't have indirect python access to datasources yet)
401
402
403
404
405
        if is_default and "B10_FROM_BUILD" in os.environ:
            db_file = os.environ["B10_FROM_BUILD"] + "/bind10_zones.sqlite3"
        return db_file

    def shutdown(self):
406
407
408
        """Shutdown the zonemgr process. the thread which is keeping track of zone
        timers should be terminated.
        """ 
Jerry's avatar
Jerry committed
409
        self._slave_socket.close()
Jerry's avatar
Jerry committed
410
        self._master_socket.close()
411
412
413
414
415
416
417
418
419

        self._shutdown_event.set()
        main_thread = threading.currentThread()
        for th in threading.enumerate():
            if th is main_thread:
                continue
            th.join()

    def config_handler(self, new_config):
420
        """Update config data."""
421
422
423
424
425
426
427
428
        answer = create_answer(0)
        for key in new_config:
            if key not in self._config_data:
                answer = create_answer(1, "Unknown config data: " + str(key))
                continue
            self._config_data[key] = new_config[key]
        return answer

Jerry's avatar
Jerry committed
429
    def _parse_cmd_params(self, args, command):
430
431
        zone_name = args.get("zone_name")
        if not zone_name:
432
            raise ZonemgrException("zone name should be provided")
433

Jerry's avatar
Jerry committed
434
435
        zone_class = args.get("zone_class")
        if not zone_class:
436
            raise ZonemgrException("zone class should be provided")
Jerry's avatar
Jerry committed
437
438
439
440

        if (command != ZONE_NOTIFY_COMMAND):
            return (zone_name, zone_class)

441
442
443
        master_str = args.get("master")
        if not master_str:
            raise ZonemgrException("master address should be provided")
444

Jerry's avatar
Jerry committed
445
        return ((zone_name, zone_class), master_str)
446
447
448


    def command_handler(self, command, args):
449
450
451
452
        """Handle command receivd from command channel.
        ZONE_NOTIFY_COMMAND is issued by Auth process; ZONE_XFRIN_SUCCESS_COMMAND 
        and ZONE_XFRIN_FAILED_COMMAND are issued by Xfrin process; shutdown is issued
        by a user or Boss process. """
453
        answer = create_answer(0)
Jerry's avatar
Jerry committed
454
        if command == ZONE_NOTIFY_COMMAND:
Jerry's avatar
Jerry committed
455
            """ Handle Auth notify command"""
456
            # master is the source sender of the notify message.
Jerry's avatar
Jerry committed
457
            zone_name_class, master = self._parse_cmd_params(args, command)
458
            log_msg("Received notify command for zone (%s, %s)." % zone_name_class)
459
            with self._lock:
460
                self._zone_refresh.zone_handle_notify(zone_name_class, master)
461
            # Send notification to zonemgr timer thread
462
            self._master_socket.send(b" ")
463

Jerry's avatar
Jerry committed
464
        elif command == ZONE_XFRIN_SUCCESS_COMMAND:
465
            """ Handle xfrin success command"""
Jerry's avatar
Jerry committed
466
            zone_name_class = self._parse_cmd_params(args, command)
467
            with self._lock:
468
                self._zone_refresh.zone_refresh_success(zone_name_class)
469
            self._master_socket.send(b" ")
470

Jerry's avatar
Jerry committed
471
        elif command == ZONE_XFRIN_FAILED_COMMAND:
Jerry's avatar
Jerry committed
472
            """ Handle xfrin fail command"""
Jerry's avatar
Jerry committed
473
            zone_name_class = self._parse_cmd_params(args, command)
474
            with self._lock:
475
                self._zone_refresh.zone_refresh_fail(zone_name_class)
476
            self._master_socket.send(b" ")
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517

        elif command == "shutdown":
            self.shutdown()

        else:
            answer = create_answer(1, "Unknown command:" + str(command))

        return answer

    def run(self):
        while not self._shutdown_event.is_set():
            self._module_cc.check_command()

zonemgrd = None

def signal_handler(signal, frame):
    if zonemgrd:
        zonemgrd.shutdown()
        sys.exit(0)

def set_signal_handler():
    signal.signal(signal.SIGTERM, signal_handler)
    signal.signal(signal.SIGINT, signal_handler)

def set_cmd_options(parser):
    parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
            help="display more about what is going on")

if '__main__' == __name__:
    try:
        parser = OptionParser()
        set_cmd_options(parser)
        (options, args) = parser.parse_args()
        VERBOSE_MODE = options.verbose

        set_signal_handler()
        zonemgrd = Zonemgr()
        zonemgrd.run()
    except KeyboardInterrupt:
        sys.stderr.write("[b10-zonemgr] exit zonemgr process")
    except isc.cc.session.SessionError as e:
518
        sys.stderr.write("[b10-zonemgr] Error creating zonemgr, " 
519
520
521
522
523
524
525
                           "is the command channel daemon running?")
    except isc.config.ModuleCCSessionError as e:
        sys.stderr.write("info", "[b10-zonemgr] exit zonemgr process:", e)

    if zonemgrd:
        zonemgrd.shutdown()