[svn] commit: r2253 - in /branches/trac127: ./ src/bin/bind10/ src/bin/cmdctl/ src/bin/cmdctl/tests/ src/lib/python/isc/config/ src/lib/python/isc/config/tests/
BIND 10 source code commits
bind10-changes at lists.isc.org
Thu Jun 24 05:29:05 UTC 2010
Author: zhanglikun
Date: Thu Jun 24 05:29:05 2010
New Revision: 2253
Log:
1. Add support to cmdctl.spec file, now there are three configurable items for cmdctl: 'key_file', 'cert_file' and 'accounts_file', all of them can be changed in
runtime. Also there is two command spported by cmdctl: shutdown and print_settings .
2. Refator some code of cmdctl and add corresponding test cases.
3. Rename module name from 'Cmd-Ctrld' to 'Cmdctl'.
Added:
branches/trac127/src/bin/cmdctl/cmdctl.spec.pre.in
Removed:
branches/trac127/src/bin/cmdctl/cmdctl.spec
Modified:
branches/trac127/configure.ac
branches/trac127/src/bin/bind10/bind10.py.in
branches/trac127/src/bin/cmdctl/Makefile.am
branches/trac127/src/bin/cmdctl/TODO
branches/trac127/src/bin/cmdctl/cmdctl.py.in
branches/trac127/src/bin/cmdctl/tests/cmdctl_test.py
branches/trac127/src/lib/python/isc/config/cfgmgr.py
branches/trac127/src/lib/python/isc/config/tests/cfgmgr_test.py
Modified: branches/trac127/configure.ac
==============================================================================
--- branches/trac127/configure.ac (original)
+++ branches/trac127/configure.ac Thu Jun 24 05:29:05 2010
@@ -428,6 +428,7 @@
src/bin/cmdctl/cmdctl.py
src/bin/cmdctl/run_b10-cmdctl.sh
src/bin/cmdctl/tests/cmdctl_test
+ src/bin/cmdctl/cmdctl.spec.pre
src/bin/xfrin/tests/xfrin_test
src/bin/xfrin/xfrin.py
src/bin/xfrin/xfrin.spec.pre
Modified: branches/trac127/src/bin/bind10/bind10.py.in
==============================================================================
--- branches/trac127/src/bin/bind10/bind10.py.in (original)
+++ branches/trac127/src/bin/bind10/bind10.py.in Thu Jun 24 05:29:05 2010
@@ -353,7 +353,7 @@
def stop_all_processes(self):
"""Stop all processes."""
cmd = { "command": ['shutdown']}
- self.cc_session.group_sendmsg(cmd, 'Boss', 'Cmd-Ctrld')
+ self.cc_session.group_sendmsg(cmd, 'Boss', 'Cmdctl')
self.cc_session.group_sendmsg(cmd, "Boss", "ConfigManager")
self.cc_session.group_sendmsg(cmd, "Boss", "Auth")
self.cc_session.group_sendmsg(cmd, "Boss", "Xfrout")
Modified: branches/trac127/src/bin/cmdctl/Makefile.am
==============================================================================
--- branches/trac127/src/bin/cmdctl/Makefile.am (original)
+++ branches/trac127/src/bin/cmdctl/Makefile.am Thu Jun 24 05:29:05 2010
@@ -19,7 +19,7 @@
EXTRA_DIST = $(CMDCTL_CONFIGURATIONS)
EXTRA_DIST += cmdctl.spec
-CLEANFILES= b10-cmdctl cmdctl.pyc
+CLEANFILES= b10-cmdctl cmdctl.pyc cmdctl.spec
man_MANS = b10-cmdctl.8
EXTRA_DIST += $(man_MANS) b10-cmdctl.xml
@@ -30,6 +30,9 @@
xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-cmdctl.xml
endif
+
+cmdctl.spec: cmdctl.spec.pre
+ $(SED) -e "s|@@SYSCONFDIR@@|$(sysconfdir)|" cmdctl.spec.pre >$@
# TODO: does this need $$(DESTDIR) also?
# this is done here since configure.ac AC_OUTPUT doesn't expand exec_prefix
Modified: branches/trac127/src/bin/cmdctl/TODO
==============================================================================
--- branches/trac127/src/bin/cmdctl/TODO (original)
+++ branches/trac127/src/bin/cmdctl/TODO Thu Jun 24 05:29:05 2010
@@ -1,8 +1,5 @@
-. Refine code for b10-cmdctl.
-. Add value type check according module specification.
. Add return code for RESTful API document of b10-cmdctl.
-. Add more unit tests for b10-cmdctl.
. Update man page for b10-cmdctl?
+. Add check for the content of key/certificate file
+ (when cmdctl starts or is configured by bindctl).
-. Add id to each command, so the receiver knows if the response is what it wants.
-. Make cmdctl can be configured through bindctl.(after id is added)
Modified: branches/trac127/src/bin/cmdctl/cmdctl.py.in
==============================================================================
--- branches/trac127/src/bin/cmdctl/cmdctl.py.in (original)
+++ branches/trac127/src/bin/cmdctl/cmdctl.py.in Thu Jun 24 05:29:05 2010
@@ -41,6 +41,7 @@
import random
import time
import signal
+from isc.config import ccsession
from optparse import OptionParser, OptionValueError
from hashlib import sha1
try:
@@ -50,29 +51,22 @@
__version__ = 'BIND10'
URL_PATTERN = re.compile('/([\w]+)(?:/([\w]+))?/?')
+MODULE_NAME = 'Cmdctl'
# If B10_FROM_SOURCE 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_SOURCE" in os.environ:
SPECFILE_PATH = os.environ["B10_FROM_SOURCE"] + "/src/bin/cmdctl"
- SYSCONF_PATH = os.environ["B10_FROM_SOURCE"] + "/src/bin/cmdctl"
else:
PREFIX = "@prefix@"
DATAROOTDIR = "@datarootdir@"
SPECFILE_PATH = "@datadir@/@PACKAGE@".replace("${datarootdir}", DATAROOTDIR).replace("${prefix}", PREFIX)
- SYSCONF_PATH = "@sysconfdir@/@PACKAGE@".replace("${prefix}", PREFIX)
SPECFILE_LOCATION = SPECFILE_PATH + os.sep + "cmdctl.spec"
-USER_INFO_FILE = SYSCONF_PATH + os.sep + "cmdctl-accounts.csv"
-PRIVATE_KEY_FILE = SYSCONF_PATH + os.sep + "cmdctl-keyfile.pem"
-CERTIFICATE_FILE = SYSCONF_PATH + os.sep + "cmdctl-certfile.pem"
-
+
class SecureHTTPRequestHandler(http.server.BaseHTTPRequestHandler):
'''https connection request handler.
- Currently only GET and POST are supported.
-
- '''
-
+ Currently only GET and POST are supported. '''
def do_GET(self):
'''The client should send its session id in header with
the name 'cookie'
@@ -167,13 +161,13 @@
user_name = user_info.get('username')
if not user_name:
return False, ["need user name"]
- if not self.server.user_infos.get(user_name):
+ if not self.server.get_user_info(user_name):
return False, ["user doesn't exist"]
user_pwd = user_info.get('password')
if not user_pwd:
return False, ["need password"]
- local_info = self.server.user_infos.get(user_name)
+ local_info = self.server.get_user_info(user_name)
pwd_hashval = sha1((user_pwd + local_info[1]).encode())
if pwd_hashval.hexdigest() != local_info[0]:
return False, ["password doesn't match"]
@@ -214,65 +208,155 @@
'''Get all modules' config data/specification from configmanager.
receive command from client and resend it to proper module.
'''
-
- def __init__(self, verbose = False):
+ def __init__(self, httpserver, verbose = False):
+ '''When cmdctl get 'shutdown' command from boss,
+ shutdown the outer httpserver. '''
self._verbose = verbose
- self.cc = isc.cc.Session()
- self.cc.group_subscribe('Cmd-Ctrld')
- self.module_spec = self.get_module_specification()
- self.config_data = self.get_config_data()
-
+ self._httpserver = httpserver
+ self._lock = threading.Lock()
+ self._setup_session()
+ self.modules_spec = self._get_modules_specification()
+ self._config_data = self._get_config_data_from_config_manager()
+ self._serving = True
+ self._start_msg_handle_thread()
+
+ def _setup_session(self):
+ '''Setup the session for receving the commands
+ sent from other modules. There are two sessions
+ for cmdctl, one(self.module_cc) is used for receiving
+ commands sent from other modules, another one (self._cc)
+ is used to send the command from Bindctl or other tools
+ to proper modules.'''
+ self._cc = isc.cc.Session()
+ self._module_cc = isc.config.ModuleCCSession(SPECFILE_LOCATION,
+ self.config_handler,
+ self.command_handler)
+ self._cmdctl_config_data = self._module_cc.get_full_config()
+ self._module_cc.start()
+
+ def _accounts_file_check(self, filepath):
+ ''' Check whether the accounts file is valid, each row
+ should be a list with 3 items.'''
+ csvfile = None
+ errstr = None
+ try:
+ csvfile = open(filepath)
+ reader = csv.reader(csvfile)
+ for row in reader:
+ a = (row[0], row[1], row[2])
+ except (IOError, IndexError) as e:
+ errstr = 'Invalid accounts file: ' + str(e)
+ finally:
+ if csvfile:
+ csvfile.close()
+
+ return errstr
+
+ def _config_data_check(self, new_config):
+ ''' Check whether the new config data is valid or
+ not. '''
+ errstr = None
+ for key in new_config:
+ if key in ['key_file', 'cert_file']:
+ #TODO, only check whether the file exist,
+ # further check need to be done: eg. whether
+ # the private/certificate is valid.
+ path = new_config[key]
+ if not os.path.exists(path):
+ errstr = "the file doesn't exist: " + path
+ elif key == 'accounts_file':
+ errstr = self._accounts_file_check(new_config[key])
+ else:
+ errstr = 'unknown config item: ' + key
+
+ if errstr != None:
+ self.log_info('Fail to apply config data, ' + errstr)
+ return ccsession.create_answer(1, errstr)
+
+ return ccsession.create_answer(0)
+
+ def config_handler(self, new_config):
+ answer = self._config_data_check(new_config)
+ rcode, val = ccsession.parse_answer(answer)
+ if rcode != 0:
+ return answer
+
+ with self._lock:
+ for key in new_config:
+ if key in self._cmdctl_config_data:
+ self._cmdctl_config_data[key] = new_config[key]
+ return answer
+
+ def command_handler(self, command, args):
+ answer = ccsession.create_answer(0)
+ if command == ccsession.COMMAND_MODULE_SPECIFICATION_UPDATE:
+ self.modules_spec[arg[0]] = arg[1]
+
+ elif command == ccsession.COMMAND_SHUTDOWN:
+ self._httpserver.shutdown()
+ self._serving = False
+
+ elif command == 'print_settings':
+ answer = ccsession.create_answer(0, self._cmdctl_config_data)
+ else:
+ answer = ccsession.create_answer(1, 'unknown command: ' + command)
+
+ return answer
+
+ def _start_msg_handle_thread(self):
+ ''' Start one thread to handle received message from msgq.'''
+ td = threading.Thread(target=self._handle_msg_from_msgq)
+ td.daemon = True
+ td.start()
+
+ def _handle_msg_from_msgq(self):
+ '''Process all the received commands with module session. '''
+ while self._serving:
+ self._module_cc.check_command()
+
def _parse_command_result(self, rcode, reply):
'''Ignore the error reason when command rcode isn't 0, '''
if rcode != 0:
return {}
return reply
+ def _get_config_data_from_config_manager(self):
+ '''Get config data for all modules from configmanager '''
+ rcode, reply = self.send_command('ConfigManager', ccsession.COMMAND_GET_CONFIG)
+ return self._parse_command_result(rcode, reply)
+
+ def _update_config_data(self, module_name, command_name):
+ '''Get lastest config data for all modules from configmanager '''
+ if module_name == 'ConfigManager' and command_name == ccsession.COMMAND_SET_CONFIG:
+ data = self._get_config_data_from_config_manager()
+ with self._lock:
+ self._config_data = data
+
def get_config_data(self):
- '''Get config data for all modules from configmanager '''
- rcode, reply = self.send_command('ConfigManager', isc.config.ccsession.COMMAND_GET_CONFIG)
+ with self._lock:
+ data = self._config_data
+ return data
+
+ def _get_modules_specification(self):
+ '''Get all the modules' specification files. '''
+ rcode, reply = self.send_command('ConfigManager', ccsession.COMMAND_GET_MODULE_SPEC)
return self._parse_command_result(rcode, reply)
-
- def update_config_data(self, module_name, command_name):
- '''Get lastest config data for all modules from configmanager '''
- if module_name == 'ConfigManager' and command_name == isc.config.ccsession.COMMAND_SET_CONFIG:
- self.config_data = self.get_config_data()
-
- def get_module_specification(self):
- rcode, reply = self.send_command('ConfigManager', isc.config.ccsession.COMMAND_GET_MODULE_SPEC)
- return self._parse_command_result(rcode, reply)
-
- def handle_recv_msg(self):
- '''Handle received message, if 'shutdown' is received, return False'''
- (message, env) = self.cc.group_recvmsg(True)
- command, arg = isc.config.ccsession.parse_command(message)
- while command:
- if command == isc.config.ccsession.COMMAND_MODULE_SPECIFICATION_UPDATE:
- self.module_spec[arg[0]] = arg[1]
- elif command == isc.config.ccsession.COMMAND_SHUTDOWN:
- return False
- (message, env) = self.cc.group_recvmsg(True)
- command, arg = isc.config.ccsession.parse_command(message)
-
- return True
-
def send_command_with_check(self, module_name, command_name, params = None):
'''Before send the command to modules, check if module_name, command_name
parameters are legal according the spec file of the module.
- Return rcode, dict.
+ Return rcode, dict. TODO, the rcode should be defined properly.
rcode = 0: dict is the correct returned value.
rcode > 0: dict is : { 'error' : 'error reason' }
'''
-
# core module ConfigManager does not have a specification file
if module_name == 'ConfigManager':
return self.send_command(module_name, command_name, params)
- if module_name not in self.module_spec.keys():
+ if module_name not in self.modules_spec.keys():
return 1, {'error' : 'unknown module'}
- spec_obj = isc.config.module_spec.ModuleSpec(self.module_spec[module_name], False)
+ spec_obj = isc.config.module_spec.ModuleSpec(self.modules_spec[module_name], False)
errors = []
if not spec_obj.validate_command(command_name, params, errors):
return 1, {'error': errors[0]}
@@ -281,123 +365,146 @@
def send_command(self, module_name, command_name, params = None):
'''Send the command from bindctl to proper module. '''
-
- errstr = 'no error'
+ errstr = 'unknown error'
if self._verbose:
- self.log_info('[b10-cmdctl] send command \'%s\' to %s\n' %(command_name, module_name))
- try:
- msg = isc.config.ccsession.create_command(command_name, params)
- seq = self.cc.group_sendmsg(msg, module_name)
+ self.log_info('Begin send command \'%s\' to %s\n' %(command_name, module_name))
+
+ if module_name == MODULE_NAME:
+ # Process the command sent to cmdctl directly.
+ answer = self.command_handler(command_name, params)
+ else:
+ msg = ccsession.create_command(command_name, params)
+ seq = self._cc.group_sendmsg(msg, module_name)
#TODO, it may be blocked, msqg need to add a new interface waiting in timeout.
- answer, env = self.cc.group_recvmsg(False, seq)
- if answer:
- try:
- rcode, arg = isc.config.ccsession.parse_answer(answer)
- if rcode == 0:
- self.update_config_data(module_name, command_name)
- if arg != None:
- return rcode, arg
- else:
- return rcode, {}
+ answer, env = self._cc.group_recvmsg(False, seq)
+
+ if answer:
+ try:
+ rcode, arg = ccsession.parse_answer(answer)
+ if rcode == 0:
+ self._update_config_data(module_name, command_name)
+ if arg != None:
+ return rcode, arg
else:
- # todo: exception
- errstr = str(answer['result'][1])
- except isc.config.ccsession.ModuleCCSessionError as mcse:
- errstr = str("Error in ccsession answer:") + str(mcse)
- self.log_info(answer)
- except Exception as e:
- errstr = str(e)
- self.log_info('\'%s\':[b10-cmdctl] fail send command \'%s\' to %s\n' % (e, command_name, module_name))
+ return rcode, {}
+ else:
+ # TODO: exception
+ errstr = str(answer['result'][1])
+ except ccsession.ModuleCCSessionError as mcse:
+ errstr = str("Error in ccsession answer:") + str(mcse)
+ self.log_info(errstr)
return 1, {'error': errstr}
def log_info(self, msg):
sys.stdout.write("[b10-cmdctl] %s\n" % str(msg))
+ def get_cmdctl_config_data(self):
+ ''' If running in source code tree, use keyfile, certificate
+ and user accounts file in source code. '''
+ if "B10_FROM_SOURCE" in os.environ:
+ sysconf_path = os.environ["B10_FROM_SOURCE"] + "/src/bin/cmdctl/"
+ accountsfile = sysconf_path + "cmdctl-accounts.csv"
+ keyfile = sysconf_path + "cmdctl-keyfile.pem"
+ certfile = sysconf_path + "cmdctl-certfile.pem"
+ return (keyfile, certfile, accountsfile)
+
+ with self._lock:
+ keyfile = self._cmdctl_config_data.get('key_file')
+ certfile = self._cmdctl_config_data.get('cert_file')
+ accountsfile = self._cmdctl_config_data.get('accounts_file')
+
+ return (keyfile, certfile, accountsfile)
+
class SecureHTTPServer(socketserver.ThreadingMixIn, http.server.HTTPServer):
'''Make the server address can be reused.'''
allow_reuse_address = True
- def __init__(self, server_address, RequestHandlerClass, idle_timeout = 1200, verbose = False):
+ def __init__(self, server_address, RequestHandlerClass,
+ CommandControlClass,
+ idle_timeout = 1200, verbose = False):
'''idle_timeout: the max idle time for login'''
http.server.HTTPServer.__init__(self, server_address, RequestHandlerClass)
self.user_sessions = {}
self.idle_timeout = idle_timeout
- self.cmdctrl = CommandControl()
- self.__is_shut_down = threading.Event()
- self.__serving = False
+ self.cmdctl = CommandControlClass(self, verbose)
self._verbose = verbose
- self.user_infos = {}
- self._read_user_info()
-
- def _read_user_info(self):
- '''Read all user's name and its' password from csv file.'''
- csvfile = None
- try:
- csvfile = open(USER_INFO_FILE)
- reader = csv.reader(csvfile)
- for row in reader:
- self.user_infos[row[0]] = [row[1], row[2]]
- except Exception as e:
- self.log_info('[b10-cmdctl] Fail to read user information :\'%s\'\n' % e)
- finally:
- if csvfile:
- csvfile.close()
-
+ self._lock = threading.Lock()
+ self._user_infos = {}
+ self._accounts_file = None
+
+ def _create_user_info(self, accounts_file):
+ '''Read all user's name and its' salt, hashed password
+ from accounts file.'''
+ if (self._accounts_file == accounts_file) and (len(self._user_infos) > 0):
+ return
+
+ with self._lock:
+ self._user_infos = {}
+ csvfile = None
+ try:
+ csvfile = open(accounts_file)
+ reader = csv.reader(csvfile)
+ for row in reader:
+ self._user_infos[row[0]] = [row[1], row[2]]
+ except (IOError, IndexError) as e:
+ self.log_info("Fail to read user database:'%s'\n" % e)
+ finally:
+ if csvfile:
+ csvfile.close()
+
+ self._accounts_file = accounts_file
+ if len(self._user_infos) == 0:
+ self.log_info("Fail to get user information, will deny any user")
+
+ def get_user_info(self, username):
+ '''Get user's salt and hashed string. If the user
+ doesn't exist, return None, or else, the list
+ [salt, hashed password] will be returned.'''
+ with self._lock:
+ info = self._user_infos.get(username)
+ return info
+
def save_user_session_id(self, session_id):
- # Record user's id and login time.
+ ''' Record user's id and login time. '''
self.user_sessions[session_id] = time.time()
+ def _wrap_socket_in_ssl_context(self, sock, key, cert):
+ # TODO, report error when key/certificate file doesn't exist
+ try:
+ ssl_sock = ssl.wrap_socket(sock,
+ server_side = True,
+ certfile = cert,
+ keyfile = key,
+ ssl_version = ssl.PROTOCOL_SSLv23)
+ return ssl_sock
+ except ssl.SSLError as e :
+ self.log_info("Deny client's invalid connection:%s\n" % e)
+ self.close_request(sock)
+ # raise socket error to finish the request
+ raise socket.error
+
def get_request(self):
'''Get client request socket and wrap it in SSL context. '''
+ key, cert, account_file = self.cmdctl.get_cmdctl_config_data()
+ self._create_user_info(account_file)
newsocket, fromaddr = self.socket.accept()
- try:
- connstream = ssl.wrap_socket(newsocket,
- server_side = True,
- certfile = CERTIFICATE_FILE,
- keyfile = PRIVATE_KEY_FILE,
- ssl_version = ssl.PROTOCOL_SSLv23)
- return (connstream, fromaddr)
- except ssl.SSLError as e :
- self.log_info('[b10-cmdctl] deny client\'s invalid connection:\'%s\'\n' % e)
- self.close_request(newsocket)
- # raise socket error to finish the request
- raise socket.error
-
+ ssl_sock = self._wrap_socket_in_ssl_context(newsocket, key, cert)
+ return (ssl_sock, fromaddr)
def get_reply_data_for_GET(self, id, module):
'''Currently only support the following three url GET request '''
rcode, reply = http.client.NO_CONTENT, []
if not module:
if id == 'config_data':
- rcode, reply = http.client.OK, self.cmdctrl.config_data
+ rcode, reply = http.client.OK, self.cmdctl.get_config_data()
elif id == 'module_spec':
- rcode, reply = http.client.OK, self.cmdctrl.module_spec
+ rcode, reply = http.client.OK, self.cmdctl.modules_spec
return rcode, reply
-
- def serve_forever(self, poll_interval = 0.5):
- '''Start cmdctl as one tcp server. '''
- self.__serving = True
- self.__is_shut_down.clear()
- while self.__serving:
- if not self.cmdctrl.handle_recv_msg():
- break
-
- r, w, e = select.select([self], [], [], poll_interval)
- if r:
- self._handle_request_noblock()
-
- self.__is_shut_down.set()
-
- def shutdown(self):
- self.__serving = False
- self.__is_shut_down.wait()
-
-
def send_command_to_module(self, module_name, command_name, params):
- return self.cmdctrl.send_command_with_check(module_name, command_name, params)
+ return self.cmdctl.send_command_with_check(module_name, command_name, params)
def log_info(self, msg):
sys.stdout.write("[b10-cmdctl] %s\n" % str(msg))
@@ -417,7 +524,8 @@
''' Start cmdctl as one https server. '''
if verbose:
sys.stdout.write("[b10-cmdctl] starting on %s port:%d\n" %(addr, port))
- httpd = SecureHTTPServer((addr, port), SecureHTTPRequestHandler, idle_timeout, verbose)
+ httpd = SecureHTTPServer((addr, port), SecureHTTPRequestHandler,
+ CommandControl, idle_timeout, verbose)
httpd.serve_forever()
def check_port(option, opt_str, value, parser):
@@ -453,13 +561,12 @@
parser.add_option("-v", "--verbose", dest="verbose", action="store_true", default=False,
help="display more about what is going on")
-
if __name__ == '__main__':
try:
+ set_signal_handler()
parser = OptionParser(version = __version__)
set_cmd_options(parser)
(options, args) = parser.parse_args()
- set_signal_handler()
run(options.addr, options.port, options.idle_timeout, options.verbose)
except isc.cc.SessionError as se:
sys.stderr.write("[b10-cmdctl] Error creating b10-cmdctl, "
Modified: branches/trac127/src/bin/cmdctl/tests/cmdctl_test.py
==============================================================================
--- branches/trac127/src/bin/cmdctl/tests/cmdctl_test.py (original)
+++ branches/trac127/src/bin/cmdctl/tests/cmdctl_test.py Thu Jun 24 05:29:05 2010
@@ -16,6 +16,7 @@
import unittest
import socket
+import tempfile
from cmdctl import *
# Rewrite the class for unittest.
@@ -42,17 +43,20 @@
os.remove('tmp.file')
-class MySecureHTTPServer(SecureHTTPServer):
+class FakeSecureHTTPServer(SecureHTTPServer):
def __init__(self):
self.user_sessions = {}
+ self.cmdctl = FakeCommandControlForTestRequestHandler()
+ self._verbose = True
+ self._user_infos = {}
self.idle_timeout = 1200
- self.cmdctrl = MyCommandControl()
- self._verbose = False
-
-class MyCommandControl(CommandControl):
+ self._lock = threading.Lock()
+
+class FakeCommandControlForTestRequestHandler(CommandControl):
def __init__(self):
- self.config_data = {}
- self.module_spec = {}
+ self._config_data = {}
+ self.modules_spec = {}
+ self._lock = threading.Lock()
def send_command(self, mod, cmd, param):
return 0, {}
@@ -60,14 +64,17 @@
class TestSecureHTTPRequestHandler(unittest.TestCase):
def setUp(self):
+ self.old_stdout = sys.stdout
+ sys.stdout = open(os.devnull, 'w')
self.handler = MySecureHTTPRequestHandler()
- self.handler.server = MySecureHTTPServer()
+ self.handler.server = FakeSecureHTTPServer()
self.handler.server.user_sessions = {}
- self.handler.server.user_infos = {}
+ self.handler.server._user_infos = {}
self.handler.headers = {}
self.handler.rfile = open("check.tmp", 'w+b')
def tearDown(self):
+ sys.stdout = self.old_stdout
self.handler.rfile.close()
os.remove('check.tmp')
@@ -154,7 +161,7 @@
self.handler.headers['Content-Length'] = len
self.handler.rfile.seek(0, 0)
- self.handler.server.user_infos['root'] = ['aa', 'aaa']
+ self.handler.server._user_infos['root'] = ['aa', 'aaa']
ret, msg = self.handler._check_user_name_and_pwd()
self.assertTrue(ret == False)
self.assertEqual(msg, ['password doesn\'t match'])
@@ -185,7 +192,7 @@
self.handler.headers['Content-Length'] = len
self.handler.rfile.seek(0, 0)
- self.handler.server.user_infos['root'] = ['aa', 'aaa']
+ self.handler.server._user_infos['root'] = ['aa', 'aaa']
ret, msg = self.handler._check_user_name_and_pwd()
self.assertTrue(ret == False)
self.assertEqual(msg, ['need password'])
@@ -247,8 +254,8 @@
self.handler.rfile.seek(0, 0)
self.handler.path = '/module/command'
- self.handler.server.cmdctrl.module_spec = {}
- self.handler.server.cmdctrl.module_spec['module'] = self._gen_module_spec()
+ self.handler.server.cmdctl.modules_spec = {}
+ self.handler.server.cmdctl.modules_spec['module'] = self._gen_module_spec()
rcode, reply = self.handler._handle_post_request()
self.assertEqual(http.client.OK, rcode)
@@ -259,10 +266,150 @@
self.handler.rfile.seek(0, 0)
self.handler.path = '/module/command'
- self.handler.server.cmdctrl.module_spec = {}
- self.handler.server.cmdctrl.module_spec['module'] = self._gen_module_spec()
+ self.handler.server.cmdctl.modules_spec = {}
+ self.handler.server.cmdctl.modules_spec['module'] = self._gen_module_spec()
rcode, reply = self.handler._handle_post_request()
self.assertEqual(http.client.BAD_REQUEST, rcode)
+class MyCommandControl(CommandControl):
+ def _get_modules_specification(self):
+ return {}
+
+ def _get_config_data_from_config_manager(self):
+ return {}
+
+ def _setup_session(self):
+ module_spec = isc.config.module_spec_from_file(SPECFILE_LOCATION)
+ config = isc.config.config_data.ConfigData(module_spec)
+ self._cmdctl_config_data = config.get_full_config()
+
+ def _handle_msg_from_msgq(self):
+ pass
+
+class TestCommandControl(unittest.TestCase):
+
+ def setUp(self):
+ self.old_stdout = sys.stdout
+ sys.stdout = open(os.devnull, 'w')
+ self.cmdctl = MyCommandControl(None, True)
+
+ def tearDown(self):
+ sys.stdout = self.old_stdout
+
+ def _check_config(self, cmdctl):
+ key, cert, account = cmdctl.get_cmdctl_config_data()
+ self.assertIsNotNone(key)
+ self.assertIsNotNone(cert)
+ self.assertIsNotNone(account)
+
+ def test_get_cmdctl_config_data(self):
+ old_env = os.environ
+ if 'B10_FROM_SOURCE' in os.environ:
+ del os.environ['B10_FROM_SOURCE']
+ self.cmdctl.get_cmdctl_config_data()
+ self._check_config(self.cmdctl)
+ os.environ = old_env
+
+ old_env = os.environ
+ os.environ['B10_FROM_SOURCE'] = '../'
+ self._check_config(self.cmdctl)
+ os.environ = old_env
+
+ def test_parse_command_result(self):
+ self.assertEqual({}, self.cmdctl._parse_command_result(1, {'error' : 1}))
+ self.assertEqual({'a': 1}, self.cmdctl._parse_command_result(0, {'a' : 1}))
+
+ def _check_answer(self, answer, rcode_, msg_):
+ rcode, msg = ccsession.parse_answer(answer)
+ self.assertEqual(rcode, rcode_)
+ self.assertEqual(msg, msg_)
+
+ def test_command_handler(self):
+ answer = self.cmdctl.command_handler('unknown-command', None)
+ self._check_answer(answer, 1, 'unknown command: unknown-command')
+
+ answer = self.cmdctl.command_handler('print_settings', None)
+ self._check_answer(answer, 0, None)
+
+ def test_check_config_handler(self):
+ answer = self.cmdctl.config_handler({'non-exist': 123})
+ self._check_answer(answer, 1, 'unknown config item: non-exist')
+
+ old_env = os.environ
+ os.environ['B10_FROM_SOURCE'] = '../'
+ self._check_config(self.cmdctl)
+ answer = self.cmdctl.config_handler({'key_file' : self.cmdctl._cmdctl_config_data['key_file']})
+ self._check_answer(answer, 0, None)
+
+ answer = self.cmdctl.config_handler({'cert_file' : self.cmdctl._cmdctl_config_data['cert_file']})
+ self._check_answer(answer, 0, None)
+
+ answer = self.cmdctl.config_handler({'accounts_file' : self.cmdctl._cmdctl_config_data['accounts_file']})
+ self._check_answer(answer, 0, None)
+ os.environ = old_env
+
+ answer = self.cmdctl.config_handler({'key_file': '/user/non-exist_folder'})
+ self._check_answer(answer, 1, "the file doesn't exist: /user/non-exist_folder")
+
+ answer = self.cmdctl.config_handler({'cert_file': '/user/non-exist_folder'})
+ self._check_answer(answer, 1, "the file doesn't exist: /user/non-exist_folder")
+
+ answer = self.cmdctl.config_handler({'accounts_file': '/user/non-exist_folder'})
+ self._check_answer(answer, 1,
+ "Invalid accounts file: [Errno 2] No such file or directory: '/user/non-exist_folder'")
+
+ # Test with invalid accounts file
+ file_name = 'tmp.account.file'
+ temp_file = open(file_name, 'w')
+ writer = csv.writer(temp_file)
+ writer.writerow(['a', 'b'])
+ temp_file.close()
+ answer = self.cmdctl.config_handler({'accounts_file': file_name})
+ self._check_answer(answer, 1, "Invalid accounts file: list index out of range")
+ os.remove(file_name)
+
+ def test_send_command(self):
+ rcode, value = self.cmdctl.send_command(MODULE_NAME, 'print_settings', None)
+ self.assertEqual(rcode, 0)
+
+class MySecureHTTPServer(SecureHTTPServer):
+ def server_bind(self):
+ pass
+
+class TestSecureHTTPServer(unittest.TestCase):
+ def setUp(self):
+ self.old_stdout = sys.stdout
+ sys.stdout = open(os.devnull, 'w')
+ self.server = MySecureHTTPServer(('localhost', 8080),
+ MySecureHTTPRequestHandler,
+ MyCommandControl, verbose=True)
+
+ def tearDown(self):
+ sys.stdout = self.old_stdout
+
+ def test_create_user_info(self):
+ self.server._create_user_info('/local/not-exist')
+ self.assertEqual(0, len(self.server._user_infos))
+
+ self.server._create_user_info('../cmdctl-accounts.csv')
+ self.assertEqual(1, len(self.server._user_infos))
+ self.assertTrue('root' in self.server._user_infos)
+
+ def test_wrap_sock_in_ssl_context(self):
+ sock = socket.socket()
+ self.server._wrap_socket_in_ssl_context(sock,
+ '../cmdctl-keyfile',
+ '../cmdctl-certfile')
+
+class TestFuncNotInClass(unittest.TestCase):
+ def test_check_port(self):
+ self.assertRaises(OptionValueError, check_port, None, 'port', -1, None)
+ self.assertRaises(OptionValueError, check_port, None, 'port', 65536, None)
+ self.assertRaises(OptionValueError, check_addr, None, 'ipstr', 'a.b.d', None)
+ self.assertRaises(OptionValueError, check_addr, None, 'ipstr', '1::0:a.b', None)
+
+
if __name__== "__main__":
unittest.main()
+
+
Modified: branches/trac127/src/lib/python/isc/config/cfgmgr.py
==============================================================================
--- branches/trac127/src/lib/python/isc/config/cfgmgr.py (original)
+++ branches/trac127/src/lib/python/isc/config/cfgmgr.py Thu Jun 24 05:29:05 2010
@@ -347,7 +347,7 @@
# passes both specification and commands at once
spec_update = ccsession.create_command(ccsession.COMMAND_MODULE_SPECIFICATION_UPDATE,
[ spec.get_module_name(), spec.get_full_spec() ])
- self.cc.group_sendmsg(spec_update, "Cmd-Ctrld")
+ self.cc.group_sendmsg(spec_update, "Cmdctl")
return ccsession.create_answer(0)
def handle_msg(self, msg):
Modified: branches/trac127/src/lib/python/isc/config/tests/cfgmgr_test.py
==============================================================================
--- branches/trac127/src/lib/python/isc/config/tests/cfgmgr_test.py (original)
+++ branches/trac127/src/lib/python/isc/config/tests/cfgmgr_test.py Thu Jun 24 05:29:05 2010
@@ -271,9 +271,9 @@
# the name here is actually wrong (and hardcoded), but needed in the current version
# TODO: fix that
#self.assertEqual({'specification_update': [ self.name, self.spec ] },
- # self.fake_session.get_message("Cmd-Ctrld", None))
+ # self.fake_session.get_message("Cmdctl", None))
#self.assertEqual({'commands_update': [ self.name, self.commands ] },
- # self.fake_session.get_message("Cmd-Ctrld", None))
+ # self.fake_session.get_message("Cmdctl", None))
self._handle_msg_helper({ "command":
["shutdown"]
More information about the bind10-changes
mailing list