[svn] commit: r961 - in /trunk: ./ src/bin/bindctl/ src/bin/bindctl/unittest/ src/bin/cmdctl/ src/bin/cmdctl/unittest/
BIND 10 source code commits
bind10-changes at lists.isc.org
Thu Feb 25 08:20:48 UTC 2010
Author: zhanglikun
Date: Thu Feb 25 08:20:48 2010
New Revision: 961
Log:
1. Add unittests and help information for cmdctl and bindctl.
2. Add login idle timeout for cmdctl, default idle time is 1200 seconds.
3. Refactor some code for cmdctl.
Added:
trunk/src/bin/cmdctl/cmdctl.py.in
- copied, changed from r960, trunk/src/bin/cmdctl/b10-cmdctl.py.in
trunk/src/bin/cmdctl/unittest/
trunk/src/bin/cmdctl/unittest/cmdctl_test.in
trunk/src/bin/cmdctl/unittest/cmdctl_test.py
Removed:
trunk/src/bin/cmdctl/b10-cmdctl.py.in
Modified:
trunk/configure.ac
trunk/src/bin/bindctl/TODO
trunk/src/bin/bindctl/bindcmd.py
trunk/src/bin/bindctl/bindctl.py
trunk/src/bin/bindctl/cmdparse.py
trunk/src/bin/bindctl/moduleinfo.py
trunk/src/bin/bindctl/unittest/bindctl_test.py
trunk/src/bin/cmdctl/Makefile.am
Modified: trunk/configure.ac
==============================================================================
--- trunk/configure.ac (original)
+++ trunk/configure.ac Thu Feb 25 08:20:48 2010
@@ -172,8 +172,9 @@
])
AC_OUTPUT([src/bin/cfgmgr/b10-cfgmgr.py
src/bin/cfgmgr/run_b10-cfgmgr.sh
- src/bin/cmdctl/b10-cmdctl.py
+ src/bin/cmdctl/cmdctl.py
src/bin/cmdctl/run_b10-cmdctl.sh
+ src/bin/cmdctl/unittest/cmdctl_test
src/bin/bind10/bind10.py
src/bin/bind10/bind10_test
src/bin/bind10/run_bind10.sh
@@ -190,6 +191,8 @@
chmod +x src/bin/cfgmgr/run_b10-cfgmgr.sh
chmod +x src/bin/cmdctl/run_b10-cmdctl.sh
chmod +x src/bin/bind10/run_bind10.sh
+ chmod +x src/bin/cmdctl/unittest/cmdctl_test
+ chmod +x src/bin/bindctl/unittest/bindctl_test
chmod +x src/bin/bindctl/bindctl
chmod +x src/bin/msgq/run_msgq.sh
chmod +x src/bin/msgq/msgq_test
Modified: trunk/src/bin/bindctl/TODO
==============================================================================
--- trunk/src/bin/bindctl/TODO (original)
+++ trunk/src/bin/bindctl/TODO Thu Feb 25 08:20:48 2010
@@ -1,3 +1,15 @@
1. Refactor the code for bindctl.
2. Update man page for bindctl provided by jreed.
3. Add more unit tests.
+4. Need Review:
+ bindcmd.py:
+ apply_config_cmd()
+ _validate_cmd()
+ complete()
+
+ cmdparse.py:
+ _parse_params
+
+ moduleinfo.py:
+ get_param_name_by_position
+
Modified: trunk/src/bin/bindctl/bindcmd.py
==============================================================================
--- trunk/src/bin/bindctl/bindcmd.py (original)
+++ trunk/src/bin/bindctl/bindcmd.py Thu Feb 25 08:20:48 2010
@@ -61,47 +61,52 @@
self.modules = OrderedDict()
self.add_module_info(ModuleInfo("help", desc = "Get help for bindctl"))
self.server_port = server_port
- self.connect_to_cmd_ctrld()
+ self._connect_to_cmd_ctrld()
self.session_id = self._get_session_id()
- def connect_to_cmd_ctrld(self):
+ def _connect_to_cmd_ctrld(self):
+ '''Connect to cmdctl in SSL context. '''
try:
self.conn = http.client.HTTPSConnection(self.server_port, cert_file='bindctl.pem')
except Exception as e:
- print(e)
- print("can't connect to %s, please make sure cmd-ctrld is running" % self.server_port)
+ print(e, "can't connect to %s, please make sure cmd-ctrld is running" %
+ self.server_port)
def _get_session_id(self):
+ '''Generate one session id for the connection. '''
rand = os.urandom(16)
now = time.time()
ip = socket.gethostbyname(socket.gethostname())
session_id = sha1(("%s%s%s" %(rand, now, ip)).encode())
- session_id = session_id.hexdigest()
- return session_id
+ digest = session_id.hexdigest()
+ return digest
def run(self):
+ '''Parse commands inputted from user and send them to cmdctl. '''
try:
- ret = self.login()
- if not ret:
+ if not self.login_to_cmdctl():
return False
# Get all module information from cmd-ctrld
self.config_data = isc.config.UIModuleCCSession(self)
- self.update_commands()
+ self._update_commands()
self.cmdloop()
except KeyboardInterrupt:
return True
- def login(self):
+ def login_to_cmdctl(self):
+ '''Login to cmdctl with the username and password inputted
+ from user. After login sucessfully, the username and password
+ will be saved in 'default_user.csv', when login next time,
+ username and password saved in 'default_user.csv' will be used
+ first.
+ '''
csvfile = None
bsuccess = False
try:
csvfile = open('default_user.csv')
users = csv.reader(csvfile)
for row in users:
- if (len(row) < 2):
- continue
-
param = {'username': row[0], 'password' : row[1]}
response = self.send_POST('/login', param)
data = response.read().decode()
@@ -120,10 +125,13 @@
return True
count = 0
- csvfile = None
print("[TEMP MESSAGE]: username :root password :bind10")
- while count < 3:
+ while True:
count = count + 1
+ if count > 3:
+ print("Too many authentication failures")
+ return False
+
username = input("Username:")
passwd = getpass.getpass()
param = {'username': username, 'password' : passwd}
@@ -135,26 +143,23 @@
csvfile = open('default_user.csv', 'w')
writer = csv.writer(csvfile)
writer.writerow([username, passwd])
- bsuccess = True
- break
-
- if count == 3:
- print("Too many authentication failures")
- break
-
- if csvfile:
- csvfile.close()
- return bsuccess
-
- def update_commands(self):
+ csvfile.close()
+ return True
+
+
+ def _update_commands(self):
+ '''Get all commands of modules. '''
cmd_spec = self.send_GET('/command_spec')
- if (len(cmd_spec) == 0):
- print('can\'t get any command specification')
+ if not cmd_spec:
+ return
+
for module_name in cmd_spec.keys():
- if cmd_spec[module_name]:
- self.prepare_module_commands(module_name, cmd_spec[module_name])
+ self._prepare_module_commands(module_name, cmd_spec[module_name])
def send_GET(self, url, body = None):
+ '''Send GET request to cmdctl, session id is send with the name
+ 'cookie' in header.
+ '''
headers = {"cookie" : self.session_id}
self.conn.request('GET', url, body, headers)
res = self.conn.getresponse()
@@ -162,11 +167,12 @@
if reply_msg:
return json.loads(reply_msg.decode())
else:
- return None
+ return {}
def send_POST(self, url, post_param = None):
- '''
+ '''Send GET request to cmdctl, session id is send with the name
+ 'cookie' in header.
Format: /module_name/command_name
parameters of command is encoded as a map
'''
@@ -183,13 +189,12 @@
self.prompt = self.location + self.prompt_end
return stop
- def prepare_module_commands(self, module_name, module_commands):
+ def _prepare_module_commands(self, module_name, module_commands):
module = ModuleInfo(name = module_name,
desc = "same here")
for command in module_commands:
cmd = CommandInfo(name = command["command_name"],
- desc = command["command_description"],
- need_inst_param = False)
+ desc = command["command_description"])
for arg in command["command_args"]:
param = ParamInfo(name = arg["item_name"],
type = arg["item_type"],
@@ -200,7 +205,7 @@
module.add_command(cmd)
self.add_module_info(module)
- def validate_cmd(self, cmd):
+ def _validate_cmd(self, cmd):
if not cmd.module in self.modules:
raise CmdUnknownModuleSyntaxError(cmd.module)
@@ -225,7 +230,6 @@
list(params.keys())[0])
elif params:
param_name = None
- index = 0
param_count = len(params)
for name in params:
# either the name of the parameter must be known, or
@@ -250,18 +254,17 @@
raise CmdUnknownParamSyntaxError(cmd.module, cmd.command, cmd.params[name])
else:
# replace the numbered items by named items
- param_name = command_info.get_param_name_by_position(name+1, index, param_count)
+ param_name = command_info.get_param_name_by_position(name+1, param_count)
cmd.params[param_name] = cmd.params[name]
del cmd.params[name]
elif not name in all_params:
raise CmdUnknownParamSyntaxError(cmd.module, cmd.command, name)
+
param_nr = 0
for name in manda_params:
if not name in params and not param_nr in params:
raise CmdMissParamSyntaxError(cmd.module, cmd.command, name)
-
- param_nr += 1
param_nr += 1
def _handle_cmd(self, cmd):
@@ -385,7 +388,7 @@
def _parse_cmd(self, line):
try:
cmd = BindCmdParse(line)
- self.validate_cmd(cmd)
+ self._validate_cmd(cmd)
self._handle_cmd(cmd)
except BindCtlException as e:
print("Error! ", e)
@@ -497,5 +500,3 @@
print("received reply:", data)
-
-
Modified: trunk/src/bin/bindctl/bindctl.py
==============================================================================
--- trunk/src/bin/bindctl/bindctl.py (original)
+++ trunk/src/bin/bindctl/bindctl.py Thu Feb 25 08:20:48 2010
@@ -18,69 +18,97 @@
from bindcmd import *
import isc
import pprint
+from optparse import OptionParser, OptionValueError
+__version__ = 'Bindctl'
def prepare_config_commands(tool):
module = ModuleInfo(name = "config", desc = "Configuration commands")
- cmd = CommandInfo(name = "show", desc = "Show configuration", need_inst_param = False)
+ cmd = CommandInfo(name = "show", desc = "Show configuration")
param = ParamInfo(name = "identifier", type = "string", optional=True)
cmd.add_param(param)
module.add_command(cmd)
- cmd = CommandInfo(name = "add", desc = "Add entry to configuration list", need_inst_param = False)
+ cmd = CommandInfo(name = "add", desc = "Add entry to configuration list")
param = ParamInfo(name = "identifier", type = "string", optional=True)
cmd.add_param(param)
param = ParamInfo(name = "value", type = "string", optional=False)
cmd.add_param(param)
module.add_command(cmd)
- cmd = CommandInfo(name = "remove", desc = "Remove entry from configuration list", need_inst_param = False)
+ cmd = CommandInfo(name = "remove", desc = "Remove entry from configuration list")
param = ParamInfo(name = "identifier", type = "string", optional=True)
cmd.add_param(param)
param = ParamInfo(name = "value", type = "string", optional=False)
cmd.add_param(param)
module.add_command(cmd)
- cmd = CommandInfo(name = "set", desc = "Set a configuration value", need_inst_param = False)
+ cmd = CommandInfo(name = "set", desc = "Set a configuration value")
param = ParamInfo(name = "identifier", type = "string", optional=True)
cmd.add_param(param)
param = ParamInfo(name = "value", type = "string", optional=False)
cmd.add_param(param)
module.add_command(cmd)
- cmd = CommandInfo(name = "unset", desc = "Unset a configuration value", need_inst_param = False)
+ cmd = CommandInfo(name = "unset", desc = "Unset a configuration value")
param = ParamInfo(name = "identifier", type = "string", optional=False)
cmd.add_param(param)
module.add_command(cmd)
- cmd = CommandInfo(name = "diff", desc = "Show all local changes", need_inst_param = False)
+ cmd = CommandInfo(name = "diff", desc = "Show all local changes")
module.add_command(cmd)
- cmd = CommandInfo(name = "revert", desc = "Revert all local changes", need_inst_param = False)
+ cmd = CommandInfo(name = "revert", desc = "Revert all local changes")
module.add_command(cmd)
- cmd = CommandInfo(name = "commit", desc = "Commit all local changes", need_inst_param = False)
+ cmd = CommandInfo(name = "commit", desc = "Commit all local changes")
module.add_command(cmd)
- cmd = CommandInfo(name = "go", desc = "Go to a specific configuration part", need_inst_param = False)
+ cmd = CommandInfo(name = "go", desc = "Go to a specific configuration part")
param = ParamInfo(name = "identifier", type="string", optional=False)
cmd.add_param(param)
module.add_command(cmd)
tool.add_module_info(module)
-if __name__ == '__main__':
- tool = BindCmdInterpreter("localhost:8080")
- prepare_config_commands(tool)
- tool.run()
-# TODO: put below back, was removed to see errors
-#if __name__ == '__main__':
- #try:
- #tool = BindCmdInterpreter("localhost:8080")
- #prepare_config_commands(tool)
- #tool.run()
- #except Exception as e:
- #print(e)
- #print("Failed to connect with b10-cmdctl module, is it running?")
+def check_port(option, opt_str, value, parser):
+ if (value < 0) or (value > 65535):
+ raise OptionValueError('%s requires a port number (0-65535)' % opt_str)
+ parser.values.port = value
+
+def check_addr(option, opt_str, value, parser):
+ ipstr = value
+ ip_family = socket.AF_INET
+ if (ipstr.find(':') != -1):
+ ip_family = socket.AF_INET6
+
+ try:
+ socket.inet_pton(ip_family, ipstr)
+ except:
+ raise OptionValueError("%s invalid ip address" % ipstr)
+
+ parser.values.addr = value
+
+def set_bindctl_options(parser):
+ parser.add_option('-p', '--port', dest = 'port', type = 'int',
+ action = 'callback', callback=check_port,
+ default = '8080', help = 'port for cmdctl of bind10')
+
+ parser.add_option('-a', '--address', dest = 'addr', type = 'string',
+ action = 'callback', callback=check_addr,
+ default = '127.0.0.1', help = 'IP address for cmdctl of bind10')
+if __name__ == '__main__':
+ try:
+ parser = OptionParser(version = __version__)
+ set_bindctl_options(parser)
+ (options, args) = parser.parse_args()
+ server_addr = options.addr + ':' + str(options.port)
+ tool = BindCmdInterpreter(server_addr)
+ prepare_config_commands(tool)
+ tool.run()
+ except Exception as e:
+ print(e, "\nFailed to connect with b10-cmdctl module, is it running?")
+
+
Modified: trunk/src/bin/bindctl/cmdparse.py
==============================================================================
--- trunk/src/bin/bindctl/cmdparse.py (original)
+++ trunk/src/bin/bindctl/cmdparse.py Thu Feb 25 08:20:48 2010
@@ -34,10 +34,10 @@
NAME_PATTERN = re.compile("^\s*(?P<name>[\w]+)(?P<blank>\s*)(?P<others>.*)$")
class BindCmdParse:
- """ This class will parse the command line user input into three parts:
- module name, command, parameters.
- The first two parts are strings and parameter is one hash.
- The parameter part is optional.
+ """ This class will parse the command line usr input into three part
+ module name, command, parameters
+ the first two parts are strings and parameter is one hash,
+ parameters part is optional
Example: zone reload, zone_name=example.com
module == zone
@@ -52,6 +52,7 @@
self._parse_cmd(cmd)
def _parse_cmd(self, text_str):
+ '''Parse command line. '''
# Get module name
groups = NAME_PATTERN.match(text_str)
if not groups:
Modified: trunk/src/bin/bindctl/moduleinfo.py
==============================================================================
--- trunk/src/bin/bindctl/moduleinfo.py (original)
+++ trunk/src/bin/bindctl/moduleinfo.py Thu Feb 25 08:20:48 2010
@@ -51,10 +51,8 @@
more parameters
"""
- def __init__(self, name, desc = "", need_inst_param = True):
+ def __init__(self, name, desc = ""):
self.name = name
- # Wether command needs parameter "instance_name"
- self.need_inst_param = need_inst_param
self.desc = desc
self.params = OrderedDict()
# Set default parameter "help"
@@ -91,7 +89,7 @@
return [name for name in all_names
if not self.params[name].is_optional]
- def get_param_name_by_position(self, pos, index, param_count):
+ def get_param_name_by_position(self, pos, param_count):
# count mandatories back from the last
# from the last mandatory; see the number of mandatories before it
# and compare that to the number of positional arguments left to do
@@ -101,7 +99,9 @@
# (can this be done in all cases? this is certainly not the most efficient method;
# one way to make the whole of this more consistent is to always set mandatories first, but
# that would make some commands less nice to use ("config set value location" instead of "config set location value")
- if type(pos) == int:
+ if type(pos) != int:
+ raise KeyError(str(pos) + " is not an integer")
+ else:
if param_count == len(self.params) - 1:
i = 0
for k in self.params.keys():
@@ -131,14 +131,9 @@
raise KeyError(str(pos) + " out of range")
else:
raise KeyError("Too many parameters")
- else:
- raise KeyError(str(pos) + " is not an integer")
-
- def need_instance_param(self):
- return self.need_inst_param
- def command_help(self, inst_name, inst_type, inst_desc):
+ def command_help(self):
print("Command ", self)
print("\t\thelp (Get help for command)")
@@ -166,65 +161,39 @@
class ModuleInfo:
"""Define the information of one module, include module name,
- module supporting commands, instance name and the value type of instance name
+ module supporting commands.
"""
- def __init__(self, name, inst_name = "", inst_type = STRING_TYPE,
- inst_desc = "", desc = ""):
+ def __init__(self, name, desc = ""):
self.name = name
- self.inst_name = inst_name
- self.inst_type = inst_type
- self.inst_desc = inst_desc
self.desc = desc
self.commands = OrderedDict()
self.add_command(CommandInfo(name = "help",
- desc = "Get help for module",
- need_inst_param = False))
+ desc = "Get help for module"))
def __str__(self):
return str("%s \t%s" % (self.name, self.desc))
def add_command(self, command_info):
self.commands[command_info.name] = command_info
- if command_info.need_instance_param():
- command_info.add_param(ParamInfo(name = self.inst_name,
- type = self.inst_type,
- desc = self.inst_desc))
-
def has_command_with_name(self, command_name):
return command_name in self.commands
-
def get_command_with_name(self, command_name):
return self.commands[command_name]
-
def get_commands(self):
return list(self.commands.values())
-
def get_command_names(self):
return list(self.commands.keys())
-
-
- def get_instance_param_name(self):
- return self.inst_name
-
-
- def get_instance_param_type(self):
- return self.inst_type
-
def module_help(self):
print("Module ", self, "\nAvailable commands:")
for k in self.commands.keys():
print("\t", self.commands[k])
-
def command_help(self, command):
- self.commands[command].command_help(self.inst_name,
- self.inst_type,
- self.inst_desc)
-
+ self.commands[command].command_help()
Modified: trunk/src/bin/bindctl/unittest/bindctl_test.py
==============================================================================
--- trunk/src/bin/bindctl/unittest/bindctl_test.py (original)
+++ trunk/src/bin/bindctl/unittest/bindctl_test.py Thu Feb 25 08:20:48 2010
@@ -85,16 +85,6 @@
self.my_assert_raise(CmdCommandNameFormatError, "zone z-d ")
self.my_assert_raise(CmdCommandNameFormatError, "zone zdd/")
self.my_assert_raise(CmdCommandNameFormatError, "zone zdd/ \"")
-
-
- def testCmdParamFormatError(self):
- self.my_assert_raise(CmdParamFormatError, "zone load load")
- self.my_assert_raise(CmdParamFormatError, "zone load load=")
- self.my_assert_raise(CmdParamFormatError, "zone load load==dd")
- self.my_assert_raise(CmdParamFormatError, "zone load , zone_name=dd zone_file=d" )
- self.my_assert_raise(CmdParamFormatError, "zone load zone_name=dd zone_file" )
- self.my_assert_raise(CmdParamFormatError, "zone zdd \"")
-
class TestCmdSyntax(unittest.TestCase):
@@ -103,18 +93,21 @@
tool = bindcmd.BindCmdInterpreter()
zone_file_param = ParamInfo(name = "zone_file")
+ zone_name = ParamInfo(name = 'zone_name')
load_cmd = CommandInfo(name = "load")
load_cmd.add_param(zone_file_param)
+ load_cmd.add_param(zone_name)
param_master = ParamInfo(name = "master", optional = True)
param_allow_update = ParamInfo(name = "allow_update", optional = True)
set_cmd = CommandInfo(name = "set")
set_cmd.add_param(param_master)
set_cmd.add_param(param_allow_update)
+ set_cmd.add_param(zone_name)
- reload_all_cmd = CommandInfo(name = "reload_all", need_inst_param = False)
+ reload_all_cmd = CommandInfo(name = "reload_all")
- zone_module = ModuleInfo(name = "zone", inst_name = "zone_name")
+ zone_module = ModuleInfo(name = "zone")
zone_module.add_command(load_cmd)
zone_module.add_command(set_cmd)
zone_module.add_command(reload_all_cmd)
@@ -129,12 +122,12 @@
def no_assert_raise(self, cmd_line):
cmd = cmdparse.BindCmdParse(cmd_line)
- self.bindcmd.validate_cmd(cmd)
+ self.bindcmd._validate_cmd(cmd)
def my_assert_raise(self, exception_type, cmd_line):
cmd = cmdparse.BindCmdParse(cmd_line)
- self.assertRaises(exception_type, self.bindcmd.validate_cmd, cmd)
+ self.assertRaises(exception_type, self.bindcmd._validate_cmd, cmd)
def testValidateSuccess(self):
Modified: trunk/src/bin/cmdctl/Makefile.am
==============================================================================
--- trunk/src/bin/cmdctl/Makefile.am (original)
+++ trunk/src/bin/cmdctl/Makefile.am Thu Feb 25 08:20:48 2010
@@ -5,10 +5,10 @@
b10_cmdctldir = $(DESTDIR)$(pkgdatadir)
b10_cmdctl_DATA = passwd.csv b10-cmdctl.pem
-CLEANFILES= b10-cmdctl
+CLEANFILES= cmdctl.py
# TODO: does this need $$(DESTDIR) also?
# this is done here since configure.ac AC_OUTPUT doesn't expand exec_prefix
-b10-cmdctl: b10-cmdctl.py
- $(SED) "s|@@PYTHONPATH@@|@pyexecdir@|" b10-cmdctl.py >$@
+b10-cmdctl: cmdctl.py
+ $(SED) "s|@@PYTHONPATH@@|@pyexecdir@|" cmdctl.py >$@
chmod a+x $@
More information about the bind10-changes
mailing list