|
@@ -0,0 +1,529 @@
|
|
|
+#!@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 struct
|
|
|
+import random
|
|
|
+import threading
|
|
|
+import select
|
|
|
+import socket
|
|
|
+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"
|
|
|
+ UNIX_SOCKET_FILE= os.environ["B10_FROM_BUILD"] + "/zonemgr_conn"
|
|
|
+else:
|
|
|
+ PREFIX = "@prefix@"
|
|
|
+ DATAROOTDIR = "@datarootdir@"
|
|
|
+ SPECFILE_PATH = "@datadir@/@PACKAGE@".replace("${datarootdir}", DATAROOTDIR).replace("${prefix}", PREFIX)
|
|
|
+ AUTH_SPECFILE_PATH = SPECFILE_PATH
|
|
|
+ UNIX_SOCKET_FILE = "@@LOCALSTATEDIR@@/zonemgr_conn"
|
|
|
+
|
|
|
+SPECFILE_LOCATION = SPECFILE_PATH + "/zonemgr.spec"
|
|
|
+AUTH_SPECFILE_LOCATION = AUTH_SPECFILE_PATH + "/auth.spec"
|
|
|
+
|
|
|
+__version__ = "BIND10"
|
|
|
+
|
|
|
+#default master port
|
|
|
+DEFAULT_MASTER_PORT = "53"
|
|
|
+
|
|
|
+# define zone state
|
|
|
+ZONE_OK = 0
|
|
|
+ZONE_REFRESHING = 1
|
|
|
+ZONE_EXPIRED = 2
|
|
|
+
|
|
|
+# smallest refresh timeout
|
|
|
+LOWERBOUND_REFRESH = 1
|
|
|
+# smallest retry timeout
|
|
|
+LOWERBOUND_RETRY = 1
|
|
|
+# max zone transfer timeout
|
|
|
+MAX_TRANSFER_TIMEOUT = 14400
|
|
|
+
|
|
|
+class ZonemgrException(Exception):
|
|
|
+ pass
|
|
|
+
|
|
|
+class ZoneRefreshInfo:
|
|
|
+ """This class will maintain and manage zone refresh info"""
|
|
|
+
|
|
|
+ def __init__(self, cc, db_file, sock_file):
|
|
|
+ self._cc = cc
|
|
|
+ self._sock_file = sock_file
|
|
|
+ self._db_file = db_file
|
|
|
+ self._zone_name_list = []
|
|
|
+ self._zones_refresh_info = []
|
|
|
+
|
|
|
+ def _random_jitter(self, max, jitter):
|
|
|
+ """Imposes some random jitters for refresh and
|
|
|
+ retry timers to avoid many zones need to do refresh
|
|
|
+ at the same time."""
|
|
|
+ if 0 == jitter:
|
|
|
+ return max
|
|
|
+ return max - random.normalvariate(max, jitter) % jitter
|
|
|
+
|
|
|
+ def _get_current_time(self):
|
|
|
+ return time.time()
|
|
|
+
|
|
|
+ def _set_timer(self, zone_index, max, jitter):
|
|
|
+ self._zones_refresh_info[zone_index]["timeout"] = self._get_current_time() + \
|
|
|
+ self._random_jitter(max, jitter)
|
|
|
+
|
|
|
+ def _set_timer_refresh(self, zone_index):
|
|
|
+ """Set timer for zone refresh timeout after zone refresh success."""
|
|
|
+ zone_refresh_time = float(self._get_zone_soa_rdata(zone_index).split(" ")[3])
|
|
|
+ if (zone_refresh_time < LOWERBOUND_REFRESH):
|
|
|
+ zone_refresh_time = LOWERBOUND_REFRESH
|
|
|
+ self._set_timer(zone_index, zone_refresh_time, (1 * zone_refresh_time) / 4)
|
|
|
+
|
|
|
+ def _set_timer_retry(self, zone_index):
|
|
|
+ """Set timer for zone retry timeout after zone refresh fail."""
|
|
|
+ zone_retry_time = float(self._get_zone_soa_rdata(zone_index).split(" ")[4])
|
|
|
+ if (zone_retry_time < LOWERBOUND_RETRY):
|
|
|
+ zone_retry_time = LOWERBOUND_RETRY
|
|
|
+ self._set_timer(zone_index, zone_retry_time, (1 * zone_retry_time) / 4)
|
|
|
+
|
|
|
+ def _set_timer_notify(self, zone_index):
|
|
|
+ """Set timer for a zone after receiving notify"""
|
|
|
+ self._set_timer(zone_index, 0, 0)
|
|
|
+
|
|
|
+ def zone_refresh_success(self, zone_name):
|
|
|
+ """Update zone update info after zone refresh success"""
|
|
|
+ zone_index = self._get_zone_index(zone_name)
|
|
|
+ if (-1 == zone_index):
|
|
|
+ raise ZonemgrException("[b10-zonemgr] Zone %s doesn't belong to zonemgr" % zone_name)
|
|
|
+ return
|
|
|
+ self._zonemgr_reload_zone(zone_index)
|
|
|
+ self._set_timer_refresh(zone_index)
|
|
|
+ self._set_zone_state(zone_index, ZONE_OK)
|
|
|
+ self._set_zone_last_refresh_time(zone_index, self._get_current_time())
|
|
|
+
|
|
|
+ def zone_refresh_fail(self, zone_name):
|
|
|
+ """Update zone update info after zone refresh fail"""
|
|
|
+ zone_index = self._get_zone_index(zone_name)
|
|
|
+ if (-1 == zone_index):
|
|
|
+ raise ZonemgrException("[b10-zonemgr] Zone %s doesn't belong to zonemgr" % zone_name)
|
|
|
+ return
|
|
|
+ self._set_zone_state(zone_index, ZONE_OK)
|
|
|
+ self._set_timer_retry(zone_index)
|
|
|
+
|
|
|
+ def zone_handle_notify(self, zone_name, master, port):
|
|
|
+ """Handle zone notify"""
|
|
|
+ zone_index = self._get_zone_index(zone_name)
|
|
|
+ if (-1 == zone_index):
|
|
|
+ raise ZonemgrException("[b10-zonemgr] Notified zone %s doesn't belong to zonemgr" % zone_name)
|
|
|
+ return
|
|
|
+ self._set_zone_notifier_master(zone_index, [master, port])
|
|
|
+ self._set_timer_notify(zone_index)
|
|
|
+
|
|
|
+ def _build_zonemgr_refresh_info(self):
|
|
|
+ for zone_name, zone_class in sqlite3_ds.get_zones_info(self._db_file):
|
|
|
+ zone_info = {}
|
|
|
+ self._zone_name_list.append(str(zone_name))
|
|
|
+ zone_soa = sqlite3_ds.get_zone_soa(str(zone_name), self._db_file)
|
|
|
+ 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["timeout"] = self._get_current_time() + float(zone_soa[7].split(" ")[3])
|
|
|
+ self._zones_refresh_info.append(zone_info)
|
|
|
+
|
|
|
+ def _get_zone_index(self, zone_name):
|
|
|
+ """Get zone index in zone_refresh_list by zone name."""
|
|
|
+ if (str(zone_name) in self._zone_name_list):
|
|
|
+ zone_index = self._zone_name_list.index(str(zone_name))
|
|
|
+ return zone_index
|
|
|
+
|
|
|
+ return -1
|
|
|
+
|
|
|
+ def _zone_is_expired(self, zone_index):
|
|
|
+ zone_expired_time = float(self._get_zone_soa_rdata(zone_index).split(" ")[5])
|
|
|
+ zone_last_refresh_time = self._get_zone_last_refresh_time(zone_index)
|
|
|
+ if (ZONE_EXPIRED == self._get_zone_state(zone_index) or
|
|
|
+ zone_last_refresh_time + zone_expired_time <= self._get_current_time()):
|
|
|
+ return True
|
|
|
+
|
|
|
+ return False
|
|
|
+
|
|
|
+ def _get_zone_soa_rdata(self, zone_index):
|
|
|
+ return self._zones_refresh_info[zone_index]["zone_soa_rdata"]
|
|
|
+
|
|
|
+ def _zonemgr_reload_zone(self, zone_index):
|
|
|
+ zone_name = self._zone_name_list[zone_index]
|
|
|
+ zone_soa = sqlite3_ds.get_zone_soa(str(zone_name), self._db_file)
|
|
|
+ self._zones_refresh_info[zone_index]["zone_soa_rdata"] = zone_soa[7]
|
|
|
+
|
|
|
+ def _get_zone_last_refresh_time(self, zone_index):
|
|
|
+ return self._zones_refresh_info[zone_index]["last_refresh_time"]
|
|
|
+
|
|
|
+ def _set_zone_last_refresh_time(self, zone_index, time):
|
|
|
+ self._zones_refresh_info[zone_index]["last_refresh_time"] = time
|
|
|
+
|
|
|
+ def _get_zone_notifier_master(self, zone_index):
|
|
|
+ if ("notify_master" in self._zones_refresh_info[zone_index].keys()):
|
|
|
+ return self._zones_refresh_info[zone_index]["notify_master"]
|
|
|
+
|
|
|
+ return None
|
|
|
+
|
|
|
+ def _set_zone_notifier_master(self, zone_index, master_addr):
|
|
|
+ self._zones_refresh_info[zone_index]["notify_master"] = master_addr
|
|
|
+
|
|
|
+ def _clear_zone_notifier_master(self, zone_index):
|
|
|
+ if ("notify_master" in self._zones_refresh_info[zone_index].keys()):
|
|
|
+ del self._zones_refresh_info[zone_index]["notify_master"]
|
|
|
+
|
|
|
+ def _get_zone_state(self, zone_index):
|
|
|
+ return self._zones_refresh_info[zone_index]["zone_state"]
|
|
|
+
|
|
|
+ def _set_zone_state(self, zone_index, zone_state):
|
|
|
+ self._zones_refresh_info[zone_index]["zone_state"] = zone_state
|
|
|
+
|
|
|
+ def _get_zone_refresh_timeout(self, zone_index):
|
|
|
+ return self._zones_refresh_info[zone_index]["fresh_timeout"]
|
|
|
+
|
|
|
+ def _set_zone_refresh_timeout(self, zone_index, time):
|
|
|
+ self._zones_refresh_info[zone_index]["fresh_timeout"] = time
|
|
|
+
|
|
|
+ def _get_zone_timeout(self, zone_index):
|
|
|
+ return self._zones_refresh_info[zone_index]["timeout"]
|
|
|
+
|
|
|
+ def _set_zone_timeout(self, zone_index, timeout):
|
|
|
+ self._zones_refresh_info[zone_index]["timeout"] = timeout
|
|
|
+
|
|
|
+ def _send_command(self, module_name, command_name, params):
|
|
|
+ msg = create_command(command_name, params)
|
|
|
+ self._cc.group_sendmsg(msg, module_name)
|
|
|
+
|
|
|
+ def _find_minimum_timeout_zone(self):
|
|
|
+ minimum_index = -1
|
|
|
+ for i in range(0, len(self._zones_refresh_info)):
|
|
|
+ # Does the zone expired?
|
|
|
+ if (ZONE_EXPIRED != self._get_zone_state(i) and
|
|
|
+ self._zone_is_expired(i)):
|
|
|
+ self._set_zone_state(i, ZONE_EXPIRED)
|
|
|
+
|
|
|
+ zone_state = self._get_zone_state(i)
|
|
|
+ # If zone is expired and doesn't receive notify, skip the zone
|
|
|
+ if (ZONE_EXPIRED == zone_state and
|
|
|
+ (not self._get_zone_notifier_master(i))):
|
|
|
+ continue
|
|
|
+
|
|
|
+ # If hasn't received xfr response within xfr timeout, skip the zone
|
|
|
+ if (ZONE_REFRESHING == zone_state and
|
|
|
+ (self._get_zone_refresh_timeout(i) > self._get_current_time())):
|
|
|
+ continue
|
|
|
+
|
|
|
+ # Get the zone with minimum timeout
|
|
|
+ if ((-1 == minimum_index) or
|
|
|
+ (self._get_zone_timeout(i) < self._get_zone_timeout(minimum_index))):
|
|
|
+ minimum_index = i
|
|
|
+
|
|
|
+ return minimum_index
|
|
|
+
|
|
|
+
|
|
|
+ def _do_refresh(self, zone_index):
|
|
|
+ """Do zone refresh"""
|
|
|
+ zone_name = self._zone_name_list[zone_index]
|
|
|
+ self._set_zone_state(zone_index, ZONE_REFRESHING)
|
|
|
+ self._set_zone_refresh_timeout(zone_index, self._get_current_time() + MAX_TRANSFER_TIMEOUT)
|
|
|
+ notify_master = self._get_zone_notifier_master(zone_index)
|
|
|
+ # If has notify master, send notify command to xfrin module
|
|
|
+ if notify_master:
|
|
|
+ param = {"zone_name" : zone_name,
|
|
|
+ "master" : notify_master[0],
|
|
|
+ "port" : notify_master[1]
|
|
|
+ }
|
|
|
+ self._send_command("Xfrin", "notify", param)
|
|
|
+ self._clear_zone_notifier_master(zone_index)
|
|
|
+ # Send refresh command to xfrin module
|
|
|
+ else:
|
|
|
+ param = {"zone_name" : zone_name}
|
|
|
+ self._send_command("Xfrin", "refresh", param)
|
|
|
+
|
|
|
+ def _connect_server(self):
|
|
|
+ """Connect to unix domain socket"""
|
|
|
+ try:
|
|
|
+ self._socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
|
+ self._socket.connect(self._sock_file)
|
|
|
+ except socket.error as err:
|
|
|
+ raise ZonemgrException("Can't connect to socket")
|
|
|
+
|
|
|
+ def _zone_mgr_is_empty(self):
|
|
|
+ """Does zone manager has no zone?"""
|
|
|
+ if not len(self._zones_refresh_info):
|
|
|
+ return True
|
|
|
+
|
|
|
+ return False
|
|
|
+
|
|
|
+ def run_timer(self):
|
|
|
+ """Keep track of zone timers"""
|
|
|
+ self._build_zonemgr_refresh_info()
|
|
|
+ self._connect_server()
|
|
|
+ while True:
|
|
|
+ if self._zone_mgr_is_empty():
|
|
|
+ continue
|
|
|
+
|
|
|
+ minimum_index = self._find_minimum_timeout_zone()
|
|
|
+ # If don't get zone with minimum timeout, timer will wait LOWERBOUND_REFRESH
|
|
|
+ if (-1 == minimum_index):
|
|
|
+ timeout = LOWERBOUND_REFRESH
|
|
|
+ else:
|
|
|
+ timeout = self._get_zone_timeout(minimum_index) - self._get_current_time()
|
|
|
+ if (timeout < 0):
|
|
|
+ self._do_refresh(minimum_index)
|
|
|
+ continue
|
|
|
+
|
|
|
+ # Start timer, wait for timeout if not received notification
|
|
|
+ try:
|
|
|
+ (rlist, wlist, xlist) = select.select([self._socket], [], [], timeout)
|
|
|
+ if rlist:
|
|
|
+ self._socket.recv(32)
|
|
|
+ except ValueError as e:
|
|
|
+ sys.stderr.write("[b10-zonemgr] Socket has been closed\n")
|
|
|
+ break
|
|
|
+ except select.error as e:
|
|
|
+ if e.args[0] == errno.EINTR:
|
|
|
+ (rlist, wlist, xlist) = ([], [], [])
|
|
|
+ else:
|
|
|
+ sys.stderr.write("[b10-zonemgr] Error with select(): %s\n" % err)
|
|
|
+ break
|
|
|
+
|
|
|
+
|
|
|
+ def shutdown(self):
|
|
|
+ """Close socket"""
|
|
|
+ self._socket.close()
|
|
|
+
|
|
|
+
|
|
|
+def start_timer(zone_refresh_info):
|
|
|
+ """Keep track of zone timers"""
|
|
|
+ zone_refresh_info.run_timer()
|
|
|
+
|
|
|
+
|
|
|
+class Zonemgr:
|
|
|
+
|
|
|
+ def __init__(self, verbose = False):
|
|
|
+ self._setup_session()
|
|
|
+ self._db_file = self.get_db_file()
|
|
|
+ self._sock_file = UNIX_SOCKET_FILE
|
|
|
+
|
|
|
+ self._create_notify_socket(self._sock_file)
|
|
|
+ self._start_zone_refresh_timer()
|
|
|
+
|
|
|
+ self._conn, addr = self._socket.accept()
|
|
|
+ self._shutdown_event = threading.Event()
|
|
|
+ self._verbose = verbose
|
|
|
+
|
|
|
+ def _create_notify_socket(self, sock_file):
|
|
|
+ """Create a unix domain socket to inform timer a new notify has arrived"""
|
|
|
+ self._remove_unused_sock_file(sock_file)
|
|
|
+ self._socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
|
+ self._socket.bind(sock_file)
|
|
|
+ self._socket.listen(2)
|
|
|
+
|
|
|
+ def _start_zone_refresh_timer(self):
|
|
|
+ """Start a new thread to run zone refresh timer"""
|
|
|
+ self._zone_refresh_info = ZoneRefreshInfo(self._cc, self._db_file, self._sock_file)
|
|
|
+ listener = threading.Thread(target = start_timer, args = (self._zone_refresh_info,))
|
|
|
+ listener.start()
|
|
|
+
|
|
|
+ def _setup_session(self):
|
|
|
+ self._cc = isc.cc.Session()
|
|
|
+ self._module_cc = isc.config.ModuleCCSession(SPECFILE_LOCATION,
|
|
|
+ self.config_handler,
|
|
|
+ self.command_handler)
|
|
|
+ self._module_cc.add_remote_config(AUTH_SPECFILE_LOCATION);
|
|
|
+ self._config_data = self._module_cc.get_full_config()
|
|
|
+ self._module_cc.start()
|
|
|
+
|
|
|
+ def get_db_file(self):
|
|
|
+ db_file, is_default = self._module_cc.get_remote_config_value("Auth", "database_file")
|
|
|
+ if is_default and "B10_FROM_BUILD" in os.environ:
|
|
|
+ db_file = os.environ["B10_FROM_BUILD"] + "/bind10_zones.sqlite3"
|
|
|
+ return db_file
|
|
|
+
|
|
|
+ def _remove_unused_sock_file(self, sock_file):
|
|
|
+ if self._sock_file_in_use(sock_file):
|
|
|
+ sys.stderr.write("[b10-zonemgr] Fail to start zonemgr process, unix socket"
|
|
|
+ " file '%s' is being used by another zonemgr process" % sock_file)
|
|
|
+ sys.exit(0)
|
|
|
+ else:
|
|
|
+ if not os.path.exists(sock_file):
|
|
|
+ return
|
|
|
+ try:
|
|
|
+ os.unlink(sock_file)
|
|
|
+ except OSError as err:
|
|
|
+ sys.stderr.write("[b10-zonemgr] Fail to remove file " + self._sock_file, err)
|
|
|
+ sys.exit(0)
|
|
|
+
|
|
|
+ def _sock_file_in_use(self, sock_file):
|
|
|
+ try:
|
|
|
+ sock = socket.socket(socket.AF_UNIX)
|
|
|
+ sock.connect(sock_file)
|
|
|
+ except socket.error as err:
|
|
|
+ return False
|
|
|
+
|
|
|
+ return True
|
|
|
+
|
|
|
+ def shutdown(self):
|
|
|
+
|
|
|
+ self._zone_refresh_info.shutdown()
|
|
|
+ try:
|
|
|
+ if (os.path.exists(self._sock_file)):
|
|
|
+ os.unlink(self._sock_file)
|
|
|
+ self._conn.close()
|
|
|
+ except Exception as e:
|
|
|
+ sys.stderr.write(str(e))
|
|
|
+
|
|
|
+ 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):
|
|
|
+ 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
|
|
|
+
|
|
|
+ def _parse_cmd_params(self, args):
|
|
|
+ zone_name = args.get("zone_name")
|
|
|
+ if not zone_name:
|
|
|
+ sys.stderr.write("zone name should be provided")
|
|
|
+
|
|
|
+ master = args.get("master")
|
|
|
+ if not master:
|
|
|
+ sys.stderr.write("master address should be provided")
|
|
|
+ check_addr(master)
|
|
|
+
|
|
|
+ port_str = args.get("port")
|
|
|
+ if not port_str:
|
|
|
+ port_str = DEFAULT_MASTER_PORT
|
|
|
+ check_port(port_str)
|
|
|
+
|
|
|
+ return (zone_name, master, port_str)
|
|
|
+
|
|
|
+
|
|
|
+ def command_handler(self, command, args):
|
|
|
+ answer = create_answer(0)
|
|
|
+ if command == "notify":
|
|
|
+ zone_name, master, port = self._parse_cmd_params(args)
|
|
|
+ self._zone_refresh_info.zone_handle_notify(zone_name, master ,port)
|
|
|
+ data = struct.pack('s', " ")
|
|
|
+ self._conn.send(data)
|
|
|
+
|
|
|
+ elif command == "zone_new_data_ready":
|
|
|
+ zone_name = args.get("zone_name")
|
|
|
+ if not zone_name:
|
|
|
+ sys.stderr.write("zone name should be provided")
|
|
|
+ self._zone_refresh_info.zone_refresh_success(zone_name)
|
|
|
+
|
|
|
+ elif command == "zone_xfr_fail":
|
|
|
+ zone_name = args.get("zone_name")
|
|
|
+ if not zone_name:
|
|
|
+ sys.stderr.write("zone name should be provided")
|
|
|
+ self._zone_refresh_info.zone_refresh_fail(zone_name)
|
|
|
+
|
|
|
+ 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 check_port(portstr):
|
|
|
+ try:
|
|
|
+ portnum = int(portstr)
|
|
|
+ if portnum < 0 or portnum > 65535:
|
|
|
+ raise ValueError("invalid port number (out of range): " + portstr)
|
|
|
+ except ValueError as err:
|
|
|
+ raise ZonemgrException("failed to resolve master addr=%s: %s" %
|
|
|
+ ( portstr, str(err)))
|
|
|
+
|
|
|
+def check_addr(addrstr):
|
|
|
+ try:
|
|
|
+ addr = socket.inet_pton(socket.AF_INET, addrstr)
|
|
|
+ return
|
|
|
+ except:
|
|
|
+ pass
|
|
|
+
|
|
|
+ try:
|
|
|
+ addr = socket.inet_pton(socket.AF_INET6, addrstr)
|
|
|
+ except Exception as err:
|
|
|
+ raise ZonemgrException("failed to resolve master addr=%s: %s" %
|
|
|
+ ( addrstr, str(err)))
|
|
|
+
|
|
|
+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:
|
|
|
+ sys.stderr.write("[b10-zonemgr] Error creating ,zonemgr"
|
|
|
+ "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()
|
|
|
+
|