|
@@ -1,6 +1,6 @@
|
|
|
#!@PYTHON@
|
|
|
|
|
|
-# Copyright (C) 2010 Internet Systems Consortium.
|
|
|
+# Copyright (C) 2010-2013 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
|
|
@@ -34,12 +34,14 @@ import threading
|
|
|
import select
|
|
|
import socket
|
|
|
import errno
|
|
|
-from isc.datasrc import sqlite3_ds
|
|
|
from optparse import OptionParser, OptionValueError
|
|
|
from isc.config.ccsession import *
|
|
|
import isc.util.process
|
|
|
from isc.log_messages.zonemgr_messages import *
|
|
|
from isc.notify import notify_out
|
|
|
+from isc.server_common.datasrc_clients_mgr import DataSrcClientsMgr, ConfigError
|
|
|
+from isc.datasrc import DataSourceClient, ZoneFinder
|
|
|
+from isc.dns import *
|
|
|
|
|
|
# Initialize logging for called modules.
|
|
|
isc.log.init("b10-zonemgr", buffer=True)
|
|
@@ -66,7 +68,9 @@ if "B10_FROM_BUILD" in os.environ:
|
|
|
else:
|
|
|
PREFIX = "@prefix@"
|
|
|
DATAROOTDIR = "@datarootdir@"
|
|
|
- SPECFILE_PATH = "@datadir@/@PACKAGE@".replace("${datarootdir}", DATAROOTDIR).replace("${prefix}", PREFIX)
|
|
|
+ SPECFILE_PATH = "@datadir@/@PACKAGE@".replace("${datarootdir}",
|
|
|
+ DATAROOTDIR).replace("${prefix}",
|
|
|
+ PREFIX)
|
|
|
AUTH_SPECFILE_PATH = SPECFILE_PATH
|
|
|
|
|
|
SPECFILE_LOCATION = SPECFILE_PATH + "/zonemgr.spec"
|
|
@@ -76,7 +80,6 @@ __version__ = "BIND10"
|
|
|
|
|
|
# define module name
|
|
|
XFRIN_MODULE_NAME = 'Xfrin'
|
|
|
-AUTH_MODULE_NAME = 'Auth'
|
|
|
|
|
|
# define command name
|
|
|
ZONE_REFRESH_COMMAND = 'refresh_from_zonemgr'
|
|
@@ -103,19 +106,24 @@ class ZonemgrRefresh:
|
|
|
can be stopped by calling shutdown() in another thread.
|
|
|
"""
|
|
|
|
|
|
- def __init__(self, db_file, slave_socket, module_cc_session):
|
|
|
- self._mccs = module_cc_session
|
|
|
+ def __init__(self, slave_socket, module_cc):
|
|
|
+ self._module_cc = module_cc
|
|
|
self._check_sock = slave_socket
|
|
|
- self._db_file = db_file
|
|
|
self._zonemgr_refresh_info = {}
|
|
|
self._lowerbound_refresh = None
|
|
|
self._lowerbound_retry = None
|
|
|
self._max_transfer_timeout = None
|
|
|
self._refresh_jitter = None
|
|
|
self._reload_jitter = None
|
|
|
- self.update_config_data(module_cc_session.get_full_config(),
|
|
|
- module_cc_session)
|
|
|
+ self.update_config_data(module_cc.get_full_config(), module_cc)
|
|
|
self._running = False
|
|
|
+ # This is essentially private, but we allow tests to customize it.
|
|
|
+ self._datasrc_clients_mgr = DataSrcClientsMgr()
|
|
|
+ # data_sources configuration should be ready with cfgmgr, so this
|
|
|
+ # shouldn't fail; if it ever does we simply propagate the exception
|
|
|
+ # to terminate the program.
|
|
|
+ self._module_cc.add_remote_config_by_name('data_sources',
|
|
|
+ self._datasrc_config_handler)
|
|
|
|
|
|
def _random_jitter(self, max, jitter):
|
|
|
"""Imposes some random jitters for refresh and
|
|
@@ -133,27 +141,32 @@ class ZonemgrRefresh:
|
|
|
def _set_zone_timer(self, zone_name_class, max, jitter):
|
|
|
"""Set zone next refresh time.
|
|
|
jitter should not be bigger than half the original value."""
|
|
|
- self._set_zone_next_refresh_time(zone_name_class, self._get_current_time() + \
|
|
|
+ self._set_zone_next_refresh_time(zone_name_class,
|
|
|
+ self._get_current_time() +
|
|
|
self._random_jitter(max, jitter))
|
|
|
|
|
|
def _set_zone_refresh_timer(self, zone_name_class):
|
|
|
"""Set zone next refresh time after zone refresh success.
|
|
|
now + refresh - refresh_jitter <= next_refresh_time <= now + refresh
|
|
|
"""
|
|
|
- zone_refresh_time = float(self._get_zone_soa_rdata(zone_name_class).split(" ")[REFRESH_OFFSET])
|
|
|
+ zone_refresh_time = float(self._get_zone_soa_rdata(zone_name_class).
|
|
|
+ split(" ")[REFRESH_OFFSET])
|
|
|
zone_refresh_time = max(self._lowerbound_refresh, zone_refresh_time)
|
|
|
- self._set_zone_timer(zone_name_class, zone_refresh_time, self._refresh_jitter * zone_refresh_time)
|
|
|
+ self._set_zone_timer(zone_name_class, zone_refresh_time,
|
|
|
+ self._refresh_jitter * zone_refresh_time)
|
|
|
|
|
|
def _set_zone_retry_timer(self, zone_name_class):
|
|
|
"""Set zone next refresh time after zone refresh fail.
|
|
|
now + retry - retry_jitter <= next_refresh_time <= now + retry
|
|
|
"""
|
|
|
- if (self._get_zone_soa_rdata(zone_name_class) is not None):
|
|
|
- zone_retry_time = float(self._get_zone_soa_rdata(zone_name_class).split(" ")[RETRY_OFFSET])
|
|
|
+ if self._get_zone_soa_rdata(zone_name_class) is not None:
|
|
|
+ zone_retry_time = float(self._get_zone_soa_rdata(zone_name_class).
|
|
|
+ split(" ")[RETRY_OFFSET])
|
|
|
else:
|
|
|
zone_retry_time = 0.0
|
|
|
zone_retry_time = max(self._lowerbound_retry, zone_retry_time)
|
|
|
- self._set_zone_timer(zone_name_class, zone_retry_time, self._refresh_jitter * zone_retry_time)
|
|
|
+ self._set_zone_timer(zone_name_class, zone_retry_time,
|
|
|
+ self._refresh_jitter * zone_retry_time)
|
|
|
|
|
|
def _set_zone_notify_timer(self, zone_name_class):
|
|
|
"""Set zone next refresh time after receiving notify
|
|
@@ -167,19 +180,22 @@ class ZonemgrRefresh:
|
|
|
|
|
|
def zone_refresh_success(self, zone_name_class):
|
|
|
"""Update zone info after zone refresh success"""
|
|
|
- if (self._zone_not_exist(zone_name_class)):
|
|
|
- logger.error(ZONEMGR_UNKNOWN_ZONE_SUCCESS, zone_name_class[0], zone_name_class[1])
|
|
|
+ if self._zone_not_exist(zone_name_class):
|
|
|
+ logger.error(ZONEMGR_UNKNOWN_ZONE_SUCCESS, zone_name_class[0],
|
|
|
+ zone_name_class[1])
|
|
|
raise ZonemgrException("[b10-zonemgr] Zone (%s, %s) doesn't "
|
|
|
"belong to zonemgr" % zone_name_class)
|
|
|
self.zonemgr_reload_zone(zone_name_class)
|
|
|
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())
|
|
|
+ self._set_zone_last_refresh_time(zone_name_class,
|
|
|
+ self._get_current_time())
|
|
|
|
|
|
def zone_refresh_fail(self, zone_name_class):
|
|
|
"""Update zone info after zone refresh fail"""
|
|
|
- if (self._zone_not_exist(zone_name_class)):
|
|
|
- logger.error(ZONEMGR_UNKNOWN_ZONE_FAIL, zone_name_class[0], zone_name_class[1])
|
|
|
+ if self._zone_not_exist(zone_name_class):
|
|
|
+ logger.error(ZONEMGR_UNKNOWN_ZONE_FAIL, zone_name_class[0],
|
|
|
+ zone_name_class[1])
|
|
|
raise ZonemgrException("[b10-zonemgr] Zone (%s, %s) doesn't "
|
|
|
"belong to zonemgr" % zone_name_class)
|
|
|
# Is zone expired?
|
|
@@ -199,11 +215,6 @@ class ZonemgrRefresh:
|
|
|
zone; the Auth module should have rejected the case where it's not
|
|
|
even authoritative for the zone.
|
|
|
|
|
|
- Note: to be more robust and less independent from other module's
|
|
|
- behavior, it's probably safer to check the authority condition here,
|
|
|
- too. But right now it uses SQLite3 specific API (to be deprecated),
|
|
|
- so we rather rely on Auth.
|
|
|
-
|
|
|
Parameters:
|
|
|
zone_name_class (Name, RRClass): the notified zone name and class.
|
|
|
master (str): textual address of the NOTIFY sender.
|
|
@@ -219,35 +230,86 @@ class ZonemgrRefresh:
|
|
|
|
|
|
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]
|
|
|
+ self._zonemgr_refresh_info[zone_name_class]["zone_soa_rdata"] = \
|
|
|
+ self._get_zone_soa(zone_name_class)
|
|
|
|
|
|
def zonemgr_add_zone(self, zone_name_class):
|
|
|
""" Add a zone into zone manager."""
|
|
|
-
|
|
|
- logger.debug(DBG_ZONEMGR_BASIC, ZONEMGR_LOAD_ZONE, zone_name_class[0], zone_name_class[1])
|
|
|
+ logger.debug(DBG_ZONEMGR_BASIC, ZONEMGR_LOAD_ZONE, zone_name_class[0],
|
|
|
+ zone_name_class[1])
|
|
|
zone_info = {}
|
|
|
- zone_soa = sqlite3_ds.get_zone_soa(str(zone_name_class[0]), self._db_file)
|
|
|
+ zone_soa = self._get_zone_soa(zone_name_class)
|
|
|
if zone_soa is None:
|
|
|
logger.warn(ZONEMGR_NO_SOA, zone_name_class[0], zone_name_class[1])
|
|
|
zone_info["zone_soa_rdata"] = None
|
|
|
zone_reload_time = 0.0
|
|
|
else:
|
|
|
- zone_info["zone_soa_rdata"] = zone_soa[7]
|
|
|
- zone_reload_time = float(zone_soa[7].split(" ")[RETRY_OFFSET])
|
|
|
+ zone_info["zone_soa_rdata"] = zone_soa
|
|
|
+ zone_reload_time = float(zone_soa.split(" ")[RETRY_OFFSET])
|
|
|
zone_info["zone_state"] = ZONE_OK
|
|
|
zone_info["last_refresh_time"] = self._get_current_time()
|
|
|
self._zonemgr_refresh_info[zone_name_class] = zone_info
|
|
|
- # Imposes some random jitters to avoid many zones need to do refresh at the same time.
|
|
|
+ # Imposes some random jitters to avoid many zones need to do refresh
|
|
|
+ # at the same time.
|
|
|
zone_reload_time = max(self._lowerbound_retry, zone_reload_time)
|
|
|
- self._set_zone_timer(zone_name_class, zone_reload_time, self._reload_jitter * zone_reload_time)
|
|
|
+ self._set_zone_timer(zone_name_class, zone_reload_time,
|
|
|
+ self._reload_jitter * zone_reload_time)
|
|
|
+
|
|
|
+ def _get_zone_soa(self, zone_name_class):
|
|
|
+ """Retrieve the current SOA RR of the zone to be transferred."""
|
|
|
+
|
|
|
+ def get_zone_soa_rrset(datasrc_client, zone_name, zone_class):
|
|
|
+ """Retrieve the current SOA RR of the zone to be transferred."""
|
|
|
+ # get the zone finder. this must be SUCCESS (not even
|
|
|
+ # PARTIALMATCH) because we are specifying the zone origin name.
|
|
|
+ result, finder = datasrc_client.find_zone(zone_name)
|
|
|
+ if result != DataSourceClient.SUCCESS:
|
|
|
+ # The data source doesn't know the zone. In the context in
|
|
|
+ # which this function is called, this shouldn't happen.
|
|
|
+ raise ZonemgrException(
|
|
|
+ "unexpected result: zone %s/%s doesn't exist" %
|
|
|
+ (zone_name.to_text(True), str(zone_class)))
|
|
|
+ result, soa_rrset, _ = finder.find(zone_name, RRType.SOA)
|
|
|
+ if result != ZoneFinder.SUCCESS:
|
|
|
+ logger.warn(ZONEMGR_NO_SOA,
|
|
|
+ zone_name.to_text(True), str(zone_class))
|
|
|
+ return None
|
|
|
+ return soa_rrset
|
|
|
+
|
|
|
+ # Identify the data source to which the zone content is transferred,
|
|
|
+ # and get the current zone SOA from the data source (if available).
|
|
|
+ datasrc_client = None
|
|
|
+ clist = self._datasrc_clients_mgr.get_client_list(zone_name_class[1])
|
|
|
+ if clist is None:
|
|
|
+ return None
|
|
|
+ try:
|
|
|
+ datasrc_client = clist.find(zone_name_class[0], True, False)[0]
|
|
|
+ if datasrc_client is None: # can happen, so log it separately.
|
|
|
+ logger.error(ZONEMGR_DATASRC_UNKNOWN,
|
|
|
+ zone_name_class[0] + '/' + zone_name_class[1])
|
|
|
+ return None
|
|
|
+ zone_soa = get_zone_soa_rrset(datasrc_client,
|
|
|
+ Name(zone_name_class[0]),
|
|
|
+ RRClass(zone_name_class[1]))
|
|
|
+ if zone_soa == None:
|
|
|
+ return None
|
|
|
+ else:
|
|
|
+ return zone_soa.get_rdata()[0].to_text()
|
|
|
+ except isc.datasrc.Error as ex:
|
|
|
+ # rare case error. re-raise as ZonemgrException so it'll be logged
|
|
|
+ # in command_handler().
|
|
|
+ raise ZonemgrException('unexpected failure in datasrc module: ' +
|
|
|
+ str(ex))
|
|
|
|
|
|
def _zone_is_expired(self, zone_name_class):
|
|
|
"""Judge whether a zone is expired or not."""
|
|
|
- zone_expired_time = float(self._get_zone_soa_rdata(zone_name_class).split(" ")[EXPIRED_OFFSET])
|
|
|
- zone_last_refresh_time = self._get_zone_last_refresh_time(zone_name_class)
|
|
|
+ zone_expired_time = float(self._get_zone_soa_rdata(zone_name_class).
|
|
|
+ split(" ")[EXPIRED_OFFSET])
|
|
|
+ zone_last_refresh_time = \
|
|
|
+ self._get_zone_last_refresh_time(zone_name_class)
|
|
|
if (ZONE_EXPIRED == self._get_zone_state(zone_name_class) or
|
|
|
- zone_last_refresh_time + zone_expired_time <= self._get_current_time()):
|
|
|
+ zone_last_refresh_time + zone_expired_time <=
|
|
|
+ self._get_current_time()):
|
|
|
return True
|
|
|
|
|
|
return False
|
|
@@ -262,16 +324,19 @@ class ZonemgrRefresh:
|
|
|
self._zonemgr_refresh_info[zone_name_class]["last_refresh_time"] = time
|
|
|
|
|
|
def _get_zone_notifier_master(self, zone_name_class):
|
|
|
- if ("notify_master" in self._zonemgr_refresh_info[zone_name_class].keys()):
|
|
|
+ if ("notify_master" in
|
|
|
+ self._zonemgr_refresh_info[zone_name_class].keys()):
|
|
|
return self._zonemgr_refresh_info[zone_name_class]["notify_master"]
|
|
|
|
|
|
return None
|
|
|
|
|
|
def _set_zone_notifier_master(self, zone_name_class, master_addr):
|
|
|
- self._zonemgr_refresh_info[zone_name_class]["notify_master"] = master_addr
|
|
|
+ self._zonemgr_refresh_info[zone_name_class]["notify_master"] = \
|
|
|
+ master_addr
|
|
|
|
|
|
def _clear_zone_notifier_master(self, zone_name_class):
|
|
|
- if ("notify_master" in self._zonemgr_refresh_info[zone_name_class].keys()):
|
|
|
+ if ("notify_master" in
|
|
|
+ self._zonemgr_refresh_info[zone_name_class].keys()):
|
|
|
del self._zonemgr_refresh_info[zone_name_class]["notify_master"]
|
|
|
|
|
|
def _get_zone_state(self, zone_name_class):
|
|
@@ -295,7 +360,7 @@ class ZonemgrRefresh:
|
|
|
def _send_command(self, module_name, command_name, params):
|
|
|
"""Send command between modules."""
|
|
|
try:
|
|
|
- self._mccs.rpc_call(command_name, module_name, params=params)
|
|
|
+ self._module_cc.rpc_call(command_name, module_name, params=params)
|
|
|
except socket.error:
|
|
|
# FIXME: WTF? Where does socket.error come from? And how do we ever
|
|
|
# dare ignore such serious error? It can only be broken link to
|
|
@@ -314,7 +379,8 @@ class ZonemgrRefresh:
|
|
|
# If hasn't received refresh response but are within refresh
|
|
|
# timeout, skip the zone
|
|
|
if (ZONE_REFRESHING == zone_state and
|
|
|
- (self._get_zone_refresh_timeout(zone_name_class) > self._get_current_time())):
|
|
|
+ (self._get_zone_refresh_timeout(zone_name_class) >
|
|
|
+ self._get_current_time())):
|
|
|
continue
|
|
|
|
|
|
# Get the zone with minimum next_refresh_time
|
|
@@ -324,7 +390,8 @@ class ZonemgrRefresh:
|
|
|
zone_need_refresh = zone_name_class
|
|
|
|
|
|
# Find the zone need do refresh
|
|
|
- if (self._get_zone_next_refresh_time(zone_need_refresh) < self._get_current_time()):
|
|
|
+ if (self._get_zone_next_refresh_time(zone_need_refresh) <
|
|
|
+ self._get_current_time()):
|
|
|
break
|
|
|
|
|
|
return zone_need_refresh
|
|
@@ -332,9 +399,12 @@ class ZonemgrRefresh:
|
|
|
|
|
|
def _do_refresh(self, zone_name_class):
|
|
|
"""Do zone refresh."""
|
|
|
- logger.debug(DBG_ZONEMGR_BASIC, ZONEMGR_REFRESH_ZONE, zone_name_class[0], zone_name_class[1])
|
|
|
+ logger.debug(DBG_ZONEMGR_BASIC, ZONEMGR_REFRESH_ZONE,
|
|
|
+ zone_name_class[0], zone_name_class[1])
|
|
|
self._set_zone_state(zone_name_class, ZONE_REFRESHING)
|
|
|
- self._set_zone_refresh_timeout(zone_name_class, self._get_current_time() + self._max_transfer_timeout)
|
|
|
+ self._set_zone_refresh_timeout(zone_name_class,
|
|
|
+ self._get_current_time() +
|
|
|
+ self._max_transfer_timeout)
|
|
|
notify_master = self._get_zone_notifier_master(zone_name_class)
|
|
|
# If the zone has notify master, send notify command to xfrin module
|
|
|
if notify_master:
|
|
@@ -351,13 +421,6 @@ class ZonemgrRefresh:
|
|
|
}
|
|
|
self._send_command(XFRIN_MODULE_NAME, ZONE_REFRESH_COMMAND, param)
|
|
|
|
|
|
- def _zone_mgr_is_empty(self):
|
|
|
- """Does zone manager has no zone?"""
|
|
|
- if not len(self._zonemgr_refresh_info):
|
|
|
- return True
|
|
|
-
|
|
|
- return False
|
|
|
-
|
|
|
def _run_timer(self, start_event):
|
|
|
while self._running:
|
|
|
# Notify run_timer that we already started and are inside the loop.
|
|
@@ -367,24 +430,29 @@ class ZonemgrRefresh:
|
|
|
if start_event:
|
|
|
start_event.set()
|
|
|
start_event = None
|
|
|
- # If zonemgr has no zone, set timer timeout to self._lowerbound_retry.
|
|
|
- if self._zone_mgr_is_empty():
|
|
|
+ # If zonemgr has no zone, set timeout to minimum
|
|
|
+ if not self._zonemgr_refresh_info:
|
|
|
timeout = self._lowerbound_retry
|
|
|
else:
|
|
|
zone_need_refresh = self._find_need_do_refresh_zone()
|
|
|
- # If don't get zone with minimum next refresh time, set timer timeout to self._lowerbound_retry.
|
|
|
+ # If don't get zone with minimum next refresh time, set
|
|
|
+ # timeout to minimum
|
|
|
if not zone_need_refresh:
|
|
|
timeout = self._lowerbound_retry
|
|
|
else:
|
|
|
- timeout = self._get_zone_next_refresh_time(zone_need_refresh) - self._get_current_time()
|
|
|
- if (timeout < 0):
|
|
|
+ timeout = \
|
|
|
+ self._get_zone_next_refresh_time(zone_need_refresh) - \
|
|
|
+ self._get_current_time()
|
|
|
+ if timeout < 0:
|
|
|
self._do_refresh(zone_need_refresh)
|
|
|
continue
|
|
|
|
|
|
""" Wait for the socket notification for a maximum time of timeout
|
|
|
in seconds (as float)."""
|
|
|
try:
|
|
|
- rlist, wlist, xlist = select.select([self._check_sock, self._read_sock], [], [], timeout)
|
|
|
+ rlist, wlist, xlist = \
|
|
|
+ select.select([self._check_sock, self._read_sock],
|
|
|
+ [], [], timeout)
|
|
|
except select.error as e:
|
|
|
if e.args[0] == errno.EINTR:
|
|
|
(rlist, wlist, xlist) = ([], [], [])
|
|
@@ -403,8 +471,8 @@ class ZonemgrRefresh:
|
|
|
|
|
|
def run_timer(self, daemon=False):
|
|
|
"""
|
|
|
- Keep track of zone timers. Spawns and starts a thread. The thread object
|
|
|
- is returned.
|
|
|
+ Keep track of zone timers. Spawns and starts a thread. The thread
|
|
|
+ object is returned.
|
|
|
|
|
|
You can stop it by calling shutdown().
|
|
|
"""
|
|
@@ -429,6 +497,20 @@ class ZonemgrRefresh:
|
|
|
# Return the thread to anyone interested
|
|
|
return self._thread
|
|
|
|
|
|
+ def _datasrc_config_handler(self, new_config, config_data):
|
|
|
+ """Configuration handler of the 'data_sources' module.
|
|
|
+
|
|
|
+ The actual handling is delegated to the DataSrcClientsMgr class;
|
|
|
+ this method is a simple wrapper.
|
|
|
+
|
|
|
+ This is essentially private, but implemented as 'protected' so tests
|
|
|
+ can refer to it; other external use is prohibited.
|
|
|
+ """
|
|
|
+ try:
|
|
|
+ self._datasrc_clients_mgr.reconfigure(new_config, config_data)
|
|
|
+ except isc.server_common.datasrc_clients_mgr.ConfigError as ex:
|
|
|
+ logger.error(ZONEMGR_DATASRC_CONFIG_ERROR, ex)
|
|
|
+
|
|
|
def shutdown(self):
|
|
|
"""
|
|
|
Stop the run_timer() thread. Block until it finished. This must be
|
|
@@ -450,7 +532,7 @@ class ZonemgrRefresh:
|
|
|
self._read_sock = None
|
|
|
self._write_sock = None
|
|
|
|
|
|
- def update_config_data(self, new_config, module_cc_session):
|
|
|
+ def update_config_data(self, new_config, module_cc):
|
|
|
""" update ZonemgrRefresh config """
|
|
|
# Get a new value, but only if it is defined (commonly used below)
|
|
|
# We don't use "value or default", because if value would be
|
|
@@ -499,7 +581,7 @@ class ZonemgrRefresh:
|
|
|
# Currently we use an explicit get_default_value call
|
|
|
# in case the class hasn't been set. Alternatively, we
|
|
|
# could use
|
|
|
- # module_cc_session.get_value('secondary_zones[INDEX]/class')
|
|
|
+ # module_cc.get_value('secondary_zones[INDEX]/class')
|
|
|
# To get either the value that was set, or the default if
|
|
|
# it wasn't set.
|
|
|
# But the real solution would be to make new_config a type
|
|
@@ -509,7 +591,7 @@ class ZonemgrRefresh:
|
|
|
if 'class' in secondary_zone:
|
|
|
rr_class = secondary_zone['class']
|
|
|
else:
|
|
|
- rr_class = module_cc_session.get_default_value(
|
|
|
+ rr_class = module_cc.get_default_value(
|
|
|
'secondary_zones/class')
|
|
|
# Convert rr_class to and from RRClass to check its value
|
|
|
try:
|
|
@@ -521,10 +603,12 @@ class ZonemgrRefresh:
|
|
|
required[name_class] = True
|
|
|
# Add it only if it isn't there already
|
|
|
if not name_class in self._zonemgr_refresh_info:
|
|
|
- # If we are not able to find it in database, log an warning
|
|
|
+ # If we are not able to find it in database, log an
|
|
|
+ # warning
|
|
|
self.zonemgr_add_zone(name_class)
|
|
|
# Drop the zones that are no longer there
|
|
|
- # Do it in two phases, python doesn't like deleting while iterating
|
|
|
+ # Do it in two phases, python doesn't like deleting while
|
|
|
+ # iterating
|
|
|
to_drop = []
|
|
|
for old_zone in self._zonemgr_refresh_info:
|
|
|
if not old_zone in required:
|
|
@@ -539,10 +623,11 @@ class Zonemgr:
|
|
|
def __init__(self):
|
|
|
self._zone_refresh = None
|
|
|
self._setup_session()
|
|
|
- self._db_file = self.get_db_file()
|
|
|
- # Create socket pair for communicating between main thread and zonemgr timer thread
|
|
|
- self._master_socket, self._slave_socket = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
|
- self._zone_refresh = ZonemgrRefresh(self._db_file, self._slave_socket, self._module_cc)
|
|
|
+ # Create socket pair for communicating between main thread and zonemgr
|
|
|
+ # timer thread
|
|
|
+ self._master_socket, self._slave_socket = \
|
|
|
+ socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
|
+ self._zone_refresh = ZonemgrRefresh(self._slave_socket, self._module_cc)
|
|
|
self._zone_refresh.run_timer()
|
|
|
|
|
|
self._lock = threading.Lock()
|
|
@@ -550,9 +635,10 @@ class Zonemgr:
|
|
|
self.running = False
|
|
|
|
|
|
def _setup_session(self):
|
|
|
- """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."""
|
|
|
+ """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.
|
|
|
+ """
|
|
|
self._module_cc = isc.config.ModuleCCSession(SPECFILE_LOCATION,
|
|
|
self.config_handler,
|
|
|
self.command_handler)
|
|
@@ -561,18 +647,9 @@ class Zonemgr:
|
|
|
self._config_data_check(self._config_data)
|
|
|
self._module_cc.start()
|
|
|
|
|
|
- def get_db_file(self):
|
|
|
- db_file, is_default = self._module_cc.get_remote_config_value(AUTH_MODULE_NAME, "database_file")
|
|
|
- # 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)
|
|
|
- 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):
|
|
|
"""Shutdown the zonemgr process. The thread which is keeping track of
|
|
|
- zone timers should be terminated.
|
|
|
+ zone timers should be terminated.
|
|
|
"""
|
|
|
self._zone_refresh.shutdown()
|
|
|
|
|
@@ -596,7 +673,8 @@ class Zonemgr:
|
|
|
self._config_data_check(complete)
|
|
|
if self._zone_refresh is not None:
|
|
|
try:
|
|
|
- self._zone_refresh.update_config_data(complete, self._module_cc)
|
|
|
+ self._zone_refresh.update_config_data(complete,
|
|
|
+ self._module_cc)
|
|
|
except Exception as e:
|
|
|
answer = create_answer(1, str(e))
|
|
|
ok = False
|
|
@@ -608,7 +686,8 @@ class Zonemgr:
|
|
|
def _config_data_check(self, config_data):
|
|
|
"""Check whether the new config data is valid or
|
|
|
not. It contains only basic logic, not full check against
|
|
|
- database."""
|
|
|
+ database.
|
|
|
+ """
|
|
|
# jitter should not be bigger than half of the original value
|
|
|
if config_data.get('refresh_jitter') > 0.5:
|
|
|
config_data['refresh_jitter'] = 0.5
|
|
@@ -625,7 +704,7 @@ class Zonemgr:
|
|
|
logger.error(ZONEMGR_NO_ZONE_CLASS)
|
|
|
raise ZonemgrException("zone class should be provided")
|
|
|
|
|
|
- if (command != ZONE_NOTIFY_COMMAND):
|
|
|
+ if command != ZONE_NOTIFY_COMMAND:
|
|
|
return (zone_name, zone_class)
|
|
|
|
|
|
master_str = args.get("master")
|
|
@@ -641,7 +720,8 @@ class Zonemgr:
|
|
|
ZONE_NOTIFY_COMMAND is issued by Auth process;
|
|
|
ZONE_NEW_DATA_READY_CMD and ZONE_XFRIN_FAILED are issued by
|
|
|
Xfrin process;
|
|
|
- shutdown is issued by a user or Init process. """
|
|
|
+ shutdown is issued by a user or Init process.
|
|
|
+ """
|
|
|
answer = create_answer(0)
|
|
|
if command == ZONE_NOTIFY_COMMAND:
|
|
|
""" Handle Auth notify command"""
|