zonemgr.py.in 22.4 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!@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.

18
"""
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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
class ZonemgrRefresh:
    """This class will maintain and manage zone refresh info.
    It also provides methods to keep track of zone timers and 
Jerry's avatar
Jerry committed
97
98
99
100
    do zone refresh. 
    Zone timers can be started by calling run_timer(), and it 
    can be stopped by calling shutdown() in another thread.

101
    """
102

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

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

Jerry's avatar
Jerry committed
124
    def _set_zone_timer(self, zone_name_class, max, jitter):
125
        """Set zone next refresh time."""
Jerry's avatar
Jerry committed
126
        self._set_zone_next_refresh_time(zone_name_class, self._get_current_time() + \
127
                                            self._random_jitter(max, jitter))
128

Jerry's avatar
Jerry committed
129
    def _set_zone_refresh_timer(self, zone_name_class):
130
131
132
        """Set zone next refresh time after zone refresh success.
           now + refresh*3/4 <= next_refresh_time <= now + refresh
           """
133
134
        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
135
        self._set_zone_timer(zone_name_class, zone_refresh_time, (1 * zone_refresh_time) / 4)
136

Jerry's avatar
Jerry committed
137
    def _set_zone_retry_timer(self, zone_name_class):
138
139
140
        """Set zone next refresh time after zone refresh fail.
           now + retry*3/4 <= next_refresh_time <= now + retry
           """
141
142
        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
143
        self._set_zone_timer(zone_name_class, zone_retry_time, (1 * zone_retry_time) / 4)
144

Jerry's avatar
Jerry committed
145
    def _set_zone_notify_timer(self, zone_name_class):
146
147
148
        """Set zone next refresh time after receiving notify
           next_refresh_time = now 
        """
Jerry's avatar
Jerry committed
149
        self._set_zone_timer(zone_name_class, 0, 0)
150

Jerry's avatar
Jerry committed
151
    def _zone_not_exist(self, zone_name_class):
152
        """ Zone doesn't belong to zonemgr"""
Jerry's avatar
Jerry committed
153
154
155
156
157
        if zone_name_class in self._zonemgr_refresh_info.keys():
            return False
        return True

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

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

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

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

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

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

        return False

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

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

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

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

        return None

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

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

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

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

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

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

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

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

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

Jerry's avatar
Jerry committed
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():
276
            # Does the zone expired?
Jerry's avatar
Jerry committed
277
278
            if (ZONE_EXPIRED != self._get_zone_state(zone_name_class) and 
                self._zone_is_expired(zone_name_class)):
279
                log_msg("Zone (%s, %s) is expired." % zone_name_class)
Jerry's avatar
Jerry committed
280
                self._set_zone_state(zone_name_class, ZONE_EXPIRED)
281

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

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

299
            # Find the zone need do refresh
Jerry's avatar
Jerry committed
300
301
            if (self._get_zone_next_refresh_time(zone_need_refresh) < self._get_current_time()):
                break
302

Jerry's avatar
Jerry committed
303
        return zone_need_refresh 
304
305

    
Jerry's avatar
Jerry committed
306
    def _do_refresh(self, zone_name_class):
307
        """Do zone refresh."""
308
        log_msg("Do refresh for zone (%s, %s)." % zone_name_class)
Jerry's avatar
Jerry committed
309
310
311
        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)
312
        # If the zone has notify master, send notify command to xfrin module
313
        if notify_master:
Jerry's avatar
Jerry committed
314
315
            param = {"zone_name" : zone_name_class[0],
                     "zone_class" : zone_name_class[1],
316
                     "master" : notify_master
317
                     }
Jerry's avatar
Jerry committed
318
            self._send_command(XFRIN_MODULE_NAME, ZONE_NOTIFY_COMMAND, param) 
Jerry's avatar
Jerry committed
319
            self._clear_zone_notifier_master(zone_name_class)
320
321
        # Send refresh command to xfrin module
        else:
Jerry's avatar
Jerry committed
322
323
324
            param = {"zone_name" : zone_name_class[0],
                     "zone_class" : zone_name_class[1]
                    }
Jerry's avatar
Jerry committed
325
            self._send_command(XFRIN_MODULE_NAME, ZONE_REFRESH_COMMAND, param)
326
327
328

    def _zone_mgr_is_empty(self):
        """Does zone manager has no zone?"""
Jerry's avatar
Jerry committed
329
        if not len(self._zonemgr_refresh_info):
330
331
332
333
            return True

        return False

334
335
    def _run_timer(self):
        while self._running:
336
            # Zonemgr has no zone.
337
            if self._zone_mgr_is_empty():
Jerry's avatar
Jerry committed
338
                timeout = LOWERBOUND_RETRY
339
            else:
340
341
342
343
344
345
346
347
348
                zone_need_refresh = self._find_need_do_refresh_zone()
                # If don't get zone with minimum next refresh time, set timer timeout = LOWERBOUND_REFRESH
                if not zone_need_refresh:
                    timeout = LOWERBOUND_RETRY
                else:
                    timeout = self._get_zone_next_refresh_time(zone_need_refresh) - self._get_current_time()
                    if (timeout < 0):
                        self._do_refresh(zone_need_refresh)
                        continue
349

350
351
            """ Wait for the socket notification for a maximum time of timeout 
            in seconds (as float)."""
352
            try:
Jerry's avatar
Jerry committed
353
                rlist, wlist, xlist = select.select([self._check_sock, self._read_sock], [], [], timeout)
354
355
356
357
            except select.error as e:
                if e.args[0] == errno.EINTR:
                    (rlist, wlist, xlist) = ([], [], [])
                else:
Jerry's avatar
Jerry committed
358
                    sys.stderr.write("[b10-zonemgr] Error with select(); %s\n" % e)
359
360
                    break

Jerry's avatar
Jerry committed
361
362
            for fd in rlist:
                if fd == self._read_sock: # awaken by shutdown socket 
363
364
365
                    # self._running will be False by now, if it is not a false
                    # alarm
                    continue
Jerry's avatar
Jerry committed
366
367
                if fd == self._check_sock: # awaken by check socket
                    self._check_sock.recv(32)
Jerry's avatar
Jerry committed
368

369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
    def run_timer(self, daemon=False):
        """
        Keep track of zone timers. Spawns and starts a thread. The thread object is returned.

        You can stop it by calling shutdown().
        """
        # Small sanity check
        if self._running:
            raise RuntimeError("Trying to run the timers twice at the same time")

        # Prepare the launch
        self._running = True
        (self._read_sock, self._write_sock) = socket.socketpair()

        # Start the thread
        self._thread = threading.Thread(target = self._run_timer, args = ())
        if daemon:
            self._thread.setDaemon(True)
        self._thread.start()

        # Return the thread to anyone interested
        return self._thread

Jerry's avatar
Jerry committed
392
    def shutdown(self):
393
394
395
396
397
398
399
400
401
        """
        Stop the run_timer() thread. Block until it finished. This must be
        called from a different thread.
        """
        if not self._running:
            raise RuntimeError("Trying to shutdown, but not running")

        # Ask the thread to stop
        self._running = False
Jerry's avatar
Jerry committed
402
        self._write_sock.send(b'shutdown') # make self._read_sock readble
403
404
405
406
407
408
        # Wait for it to actually finnish
        self._thread.join()
        # Wipe out what we do not need
        self._thread = None
        self._read_sock = None
        self._write_sock = None
409

410
411
412
class Zonemgr:
    """Zone manager class."""
    def __init__(self):
413
414
        self._setup_session()
        self._db_file = self.get_db_file()
415
        # Create socket pair for communicating between main thread and zonemgr timer thread 
Jerry's avatar
Jerry committed
416
        self._master_socket, self._slave_socket = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM)
417
        self._zone_refresh = ZonemgrRefresh(self._cc, self._db_file, self._slave_socket)
418
        self._zone_refresh.run_timer()
419

420
        self._lock = threading.Lock()
421
422
423
        self._shutdown_event = threading.Event()

    def _setup_session(self):
424
425
426
        """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."""
427
428
429
430
        self._cc = isc.cc.Session()
        self._module_cc = isc.config.ModuleCCSession(SPECFILE_LOCATION,
                                                  self.config_handler,
                                                  self.command_handler)
431
        self._module_cc.add_remote_config(AUTH_SPECFILE_LOCATION)
432
433
434
435
        self._config_data = self._module_cc.get_full_config()
        self._module_cc.start()

    def get_db_file(self):
Jerry's avatar
Jerry committed
436
        db_file, is_default = self._module_cc.get_remote_config_value(AUTH_MODULE_NAME, "database_file")
437
438
439
        # 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)
440
441
442
443
444
        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):
445
446
447
        """Shutdown the zonemgr process. the thread which is keeping track of zone
        timers should be terminated.
        """ 
Jerry's avatar
Jerry committed
448
449
        self._zone_refresh.shutdown()

Jerry's avatar
Jerry committed
450
        self._slave_socket.close()
Jerry's avatar
Jerry committed
451
        self._master_socket.close()
452
453
454
        self._shutdown_event.set()

    def config_handler(self, new_config):
455
        """Update config data."""
456
457
458
459
460
461
462
463
        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
464
    def _parse_cmd_params(self, args, command):
465
466
        zone_name = args.get("zone_name")
        if not zone_name:
467
            raise ZonemgrException("zone name should be provided")
468

Jerry's avatar
Jerry committed
469
470
        zone_class = args.get("zone_class")
        if not zone_class:
471
            raise ZonemgrException("zone class should be provided")
Jerry's avatar
Jerry committed
472
473
474
475

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

476
477
478
        master_str = args.get("master")
        if not master_str:
            raise ZonemgrException("master address should be provided")
479

Jerry's avatar
Jerry committed
480
        return ((zone_name, zone_class), master_str)
481
482
483


    def command_handler(self, command, args):
484
485
486
487
        """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. """
488
        answer = create_answer(0)
Jerry's avatar
Jerry committed
489
        if command == ZONE_NOTIFY_COMMAND:
Jerry's avatar
Jerry committed
490
            """ Handle Auth notify command"""
491
            # master is the source sender of the notify message.
Jerry's avatar
Jerry committed
492
            zone_name_class, master = self._parse_cmd_params(args, command)
493
            log_msg("Received notify command for zone (%s, %s)." % zone_name_class)
494
            with self._lock:
495
                self._zone_refresh.zone_handle_notify(zone_name_class, master)
496
            # Send notification to zonemgr timer thread
Jerry's avatar
Jerry committed
497
            self._master_socket.send(b" ")# make self._slave_socket readble
498

Jerry's avatar
Jerry committed
499
        elif command == ZONE_XFRIN_SUCCESS_COMMAND:
500
            """ Handle xfrin success command"""
Jerry's avatar
Jerry committed
501
            zone_name_class = self._parse_cmd_params(args, command)
502
            with self._lock:
503
                self._zone_refresh.zone_refresh_success(zone_name_class)
Jerry's avatar
Jerry committed
504
            self._master_socket.send(b" ")# make self._slave_socket readble
505

Jerry's avatar
Jerry committed
506
        elif command == ZONE_XFRIN_FAILED_COMMAND:
Jerry's avatar
Jerry committed
507
            """ Handle xfrin fail command"""
Jerry's avatar
Jerry committed
508
            zone_name_class = self._parse_cmd_params(args, command)
509
            with self._lock:
510
                self._zone_refresh.zone_refresh_fail(zone_name_class)
Jerry's avatar
Jerry committed
511
            self._master_socket.send(b" ")# make self._slave_socket readble
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550

        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:
Jeremy C. Reed's avatar
Jeremy C. Reed committed
551
        sys.stderr.write("[b10-zonemgr] exit zonemgr process\n")
552
    except isc.cc.session.SessionError as e:
553
        sys.stderr.write("[b10-zonemgr] Error creating zonemgr, " 
Jeremy C. Reed's avatar
Jeremy C. Reed committed
554
                           "is the command channel daemon running?\n")
555
556
    except isc.cc.session.SessionTimeout as e:
        sys.stderr.write("[b10-zonemgr] Error creating zonemgr, " 
Jeremy C. Reed's avatar
Jeremy C. Reed committed
557
                           "is the configuration manager running?\n")
558
    except isc.config.ModuleCCSessionError as e:
Jeremy C. Reed's avatar
Jeremy C. Reed committed
559
        sys.stderr.write("[b10-zonemgr] exit zonemgr process: %s\n" % str(e))
560
561
562
563

    if zonemgrd:
        zonemgrd.shutdown()