zonemgr.py.in 21.8 KB
Newer Older
1
2
3
#!@PYTHON@

# Copyright (C) 2010  Internet Systems Consortium.
4
# Copyright (C) 2010  CZ NIC
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
#
# 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
36
import errno
37
38
39
from isc.datasrc import sqlite3_ds
from optparse import OptionParser, OptionValueError
from isc.config.ccsession import *
Michal Vaner's avatar
Michal Vaner committed
40
41
42
import isc.utils.process

isc.utils.process.rename()
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

# 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"

61
# define module name
Jerry's avatar
Jerry committed
62
63
XFRIN_MODULE_NAME = 'Xfrin'
AUTH_MODULE_NAME = 'Auth'
64

65
# define command name
Jerry's avatar
Jerry committed
66
67
ZONE_XFRIN_FAILED_COMMAND = 'zone_xfrin_failed'
ZONE_XFRIN_SUCCESS_COMMAND = 'zone_new_data_ready'
68
ZONE_REFRESH_COMMAND = 'refresh_from_zonemgr'
Jerry's avatar
Jerry committed
69
ZONE_NOTIFY_COMMAND = 'notify'
70

71
72
73
74
75
# define zone state
ZONE_OK = 0
ZONE_REFRESHING = 1
ZONE_EXPIRED = 2

76
77
78
79
80
81
82
83
84
85
86
87
# 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))

88
89
90
class ZonemgrException(Exception):
    pass

91
92
93
94
95
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.
    """
96

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

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

Jerry's avatar
Jerry committed
118
    def _set_zone_timer(self, zone_name_class, max, jitter):
119
120
        """Set zone next refresh time. 
        jitter should not be bigger than half the original value."""
Jerry's avatar
Jerry committed
121
        self._set_zone_next_refresh_time(zone_name_class, self._get_current_time() + \
122
                                            self._random_jitter(max, jitter))
123

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

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

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

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

    def zone_refresh_success(self, zone_name_class):
153
        """Update zone info after zone refresh success"""
Jerry's avatar
Jerry committed
154
        if (self._zone_not_exist(zone_name_class)):
155
156
            raise ZonemgrException("[b10-zonemgr] Zone (%s, %s) doesn't "
                                   "belong to zonemgr" % zone_name_class)
157
            return
158
        self.zonemgr_reload_zone(zone_name_class)
Jerry's avatar
Jerry committed
159
160
161
        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())
162

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

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

185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
    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

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

Jerry's avatar
Jerry committed
211
    def _zone_is_expired(self, zone_name_class):
212
213
        """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
214
215
        zone_last_refresh_time = self._get_zone_last_refresh_time(zone_name_class)
        if (ZONE_EXPIRED == self._get_zone_state(zone_name_class) or
216
217
218
219
220
            zone_last_refresh_time + zone_expired_time <= self._get_current_time()):
            return True

        return False

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

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

Jerry's avatar
Jerry committed
227
228
    def _set_zone_last_refresh_time(self, zone_name_class, time):
        self._zonemgr_refresh_info[zone_name_class]["last_refresh_time"] = time
229

Jerry's avatar
Jerry committed
230
231
232
    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"] 
233
234
235

        return None

Jerry's avatar
Jerry committed
236
237
    def _set_zone_notifier_master(self, zone_name_class, master_addr):
        self._zonemgr_refresh_info[zone_name_class]["notify_master"] = master_addr
238

Jerry's avatar
Jerry committed
239
240
241
    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"]
242

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

Jerry's avatar
Jerry committed
246
247
    def _set_zone_state(self, zone_name_class, zone_state):
        self._zonemgr_refresh_info[zone_name_class]["zone_state"] = zone_state 
248

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

Jerry's avatar
Jerry committed
252
253
    def _set_zone_refresh_timeout(self, zone_name_class, time):
        self._zonemgr_refresh_info[zone_name_class]["refresh_timeout"] = time
254

Jerry's avatar
Jerry committed
255
256
    def _get_zone_next_refresh_time(self, zone_name_class):
        return self._zonemgr_refresh_info[zone_name_class]["next_refresh_time"]
257

Jerry's avatar
Jerry committed
258
259
    def _set_zone_next_refresh_time(self, zone_name_class, time):
        self._zonemgr_refresh_info[zone_name_class]["next_refresh_time"] = time
260
261

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

Jerry's avatar
Jerry committed
269
270
271
272
273
274
275
    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():
            zone_state = self._get_zone_state(zone_name_class)
276
            # If hasn't received refresh response but are within refresh timeout, skip the zone
277
            if (ZONE_REFRESHING == zone_state and
Jerry's avatar
Jerry committed
278
                (self._get_zone_refresh_timeout(zone_name_class) > self._get_current_time())):
279
280
                continue
                    
Jerry's avatar
Jerry committed
281
            # Get the zone with minimum next_refresh_time 
282
            if ((zone_need_refresh is None) or 
Jerry's avatar
Jerry committed
283
                (self._get_zone_next_refresh_time(zone_name_class) < 
284
                 self._get_zone_next_refresh_time(zone_need_refresh))):
Jerry's avatar
Jerry committed
285
286
                zone_need_refresh = zone_name_class

287
            # Find the zone need do refresh
Jerry's avatar
Jerry committed
288
289
            if (self._get_zone_next_refresh_time(zone_need_refresh) < self._get_current_time()):
                break
290

Jerry's avatar
Jerry committed
291
        return zone_need_refresh 
292
293

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

    def _zone_mgr_is_empty(self):
        """Does zone manager has no zone?"""
Jerry's avatar
Jerry committed
317
        if not len(self._zonemgr_refresh_info):
318
319
320
321
322
            return True

        return False

    def run_timer(self):
323
        """Keep track of zone timers."""
324
        while True:
325
            # Zonemgr has no zone.
326
            if self._zone_mgr_is_empty():
327
                time.sleep(self._lowerbound_retry) # A better time?
328
329
                continue

Jerry's avatar
Jerry committed
330
            zone_need_refresh = self._find_need_do_refresh_zone()
331
            # If don't get zone with minimum next refresh time, set timer timeout = lowerbound_retry 
Jerry's avatar
Jerry committed
332
            if not zone_need_refresh:
333
                timeout = self._lowerbound_retry 
334
            else:
335
336
                timeout = self._get_zone_next_refresh_time(zone_need_refresh) - self._get_current_time()
                if (timeout < 0):
Jerry's avatar
Jerry committed
337
                    self._do_refresh(zone_need_refresh)
338
339
                    continue

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

356
357
358
359
360
361
362
    def update_config_data(self, new_config):
        """ update ZonemgrRefresh config """
        self._lowerbound_refresh = new_config.get('lowerbound_refresh')
        self._lowerbound_retry = new_config.get('lowerbound_retry')
        self._max_transfer_timeout = new_config.get('max_transfer_timeout')
        self._jitter_scope = new_config.get('jitter_scope')

363

364
365
366
class Zonemgr:
    """Zone manager class."""
    def __init__(self):
367
        self._zone_refresh = None
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, self._config_data)
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
        self._config_data = self._module_cc.get_full_config()
Jerry's avatar
Jerry committed
394
        self._config_data_check(self._config_data)
395
396
397
        self._module_cc.start()

    def get_db_file(self):
Jerry's avatar
Jerry committed
398
        db_file, is_default = self._module_cc.get_remote_config_value(AUTH_MODULE_NAME, "database_file")
399
400
401
        # 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)
402
403
404
405
406
        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):
407
408
409
        """Shutdown the zonemgr process. the thread which is keeping track of zone
        timers should be terminated.
        """ 
Jerry's avatar
Jerry committed
410
        self._slave_socket.close()
Jerry's avatar
Jerry committed
411
        self._master_socket.close()
412
413
414
415
416
417
418
419
420

        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):
421
        """ Update config data. """
422
423
424
425
426
427
        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]
428

Jerry's avatar
Jerry committed
429
        self._config_data_check(self._config_data)
430
431
432
        if (self._zone_refresh):
            self._zone_refresh.update_config_data(self._config_data)

433
434
        return answer

Jerry's avatar
Jerry committed
435
436
437
438
439
440
441
442
    def _config_data_check(self, config_data):
        ''' Check whether the new config data is valid or 
        not. '''                                          
        # jitter should not be bigger than half of the original value
        if config_data.get('jitter_scope') > 0.5:
            config_data['jitter_scope'] = 0.5
            log_msg("[b10-zonemgr] jitter_scope should not be bigger than 0.5.") 

Jerry's avatar
Jerry committed
443
    def _parse_cmd_params(self, args, command):
444
445
        zone_name = args.get("zone_name")
        if not zone_name:
446
            raise ZonemgrException("zone name should be provided")
447

Jerry's avatar
Jerry committed
448
449
        zone_class = args.get("zone_class")
        if not zone_class:
450
            raise ZonemgrException("zone class should be provided")
Jerry's avatar
Jerry committed
451
452
453
454

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

455
456
457
        master_str = args.get("master")
        if not master_str:
            raise ZonemgrException("master address should be provided")
458

Jerry's avatar
Jerry committed
459
        return ((zone_name, zone_class), master_str)
460
461
462


    def command_handler(self, command, args):
463
464
465
466
        """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. """
467
        answer = create_answer(0)
Jerry's avatar
Jerry committed
468
        if command == ZONE_NOTIFY_COMMAND:
Jerry's avatar
Jerry committed
469
            """ Handle Auth notify command"""
470
            # master is the source sender of the notify message.
Jerry's avatar
Jerry committed
471
            zone_name_class, master = self._parse_cmd_params(args, command)
472
            log_msg("Received notify command for zone (%s, %s)." % zone_name_class)
473
            with self._lock:
474
                self._zone_refresh.zone_handle_notify(zone_name_class, master)
475
            # Send notification to zonemgr timer thread
476
            self._master_socket.send(b" ")
477

Jerry's avatar
Jerry committed
478
        elif command == ZONE_XFRIN_SUCCESS_COMMAND:
479
            """ Handle xfrin success command"""
Jerry's avatar
Jerry committed
480
            zone_name_class = self._parse_cmd_params(args, command)
481
            with self._lock:
482
                self._zone_refresh.zone_refresh_success(zone_name_class)
483
            self._master_socket.send(b" ")
484

Jerry's avatar
Jerry committed
485
        elif command == ZONE_XFRIN_FAILED_COMMAND:
Jerry's avatar
Jerry committed
486
            """ Handle xfrin fail command"""
Jerry's avatar
Jerry committed
487
            zone_name_class = self._parse_cmd_params(args, command)
488
            with self._lock:
489
                self._zone_refresh.zone_refresh_fail(zone_name_class)
490
            self._master_socket.send(b" ")
491
492
493
494
495
496
497
498
499
500
501

        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():
502
            self._module_cc.check_command(False)
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529

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:
Jeremy C. Reed's avatar
Jeremy C. Reed committed
530
        sys.stderr.write("[b10-zonemgr] exit zonemgr process\n")
531
    except isc.cc.session.SessionError as e:
532
        sys.stderr.write("[b10-zonemgr] Error creating zonemgr, " 
Jeremy C. Reed's avatar
Jeremy C. Reed committed
533
                           "is the command channel daemon running?\n")
534
535
    except isc.cc.session.SessionTimeout as e:
        sys.stderr.write("[b10-zonemgr] Error creating zonemgr, " 
Jeremy C. Reed's avatar
Jeremy C. Reed committed
536
                           "is the configuration manager running?\n")
537
    except isc.config.ModuleCCSessionError as e:
Jeremy C. Reed's avatar
Jeremy C. Reed committed
538
        sys.stderr.write("[b10-zonemgr] exit zonemgr process: %s\n" % str(e))
539
540
541
542

    if zonemgrd:
        zonemgrd.shutdown()