Commit 26266087 authored by Jelte Jansen's avatar Jelte Jansen
Browse files

finaly sync for merge


git-svn-id: svn://bind10.isc.org/svn/bind10/experiments/python-binding@2360 e5f2f494-b856-4b98-b285-d166d9295462
parents 6220232c 0c4bbcba
68. [func] zhanglikun
Add options -c(--certificate-chain) to bindctl. Override class
HTTPSConnection to support server certificate validation.
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.
(Trac #127, svn r2357)
67. [func] zhanglikun
Make bindctl's command parser only do minimal check. Parameter
value can be a sequence of non-space characters, or a string
surrounded by quotation marks(these marks can be a part of the
value string in escaped form). Make error message be more
friendly.(if there is some error in parameter's value, the
parameter name will be provided). Refactor function login_to_cmdctl()
in class BindCmdInterpreter: avoid using Exception to catch all
exceptions.
(Trac #220, svn r2356)
66. [bug] each
Check for duplicate RRsets before inserting data into a message
section; this, among other things, will prevent multiple copies
......
......@@ -413,6 +413,7 @@ AC_OUTPUT([src/bin/cfgmgr/b10-cfgmgr.py
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
......
......@@ -387,7 +387,7 @@ class BoB:
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")
......
......@@ -9,8 +9,6 @@ python_PYTHON = __init__.py bindcmd.py cmdparse.py exception.py moduleinfo.py my
pythondir = $(pyexecdir)/bindctl
bindctldir = $(DESTDIR)$(pkgdatadir)
bindctl_DATA = bindctl.pem
EXTRA_DIST += bindctl.pem
CLEANFILES = bindctl
......@@ -26,14 +24,3 @@ bindctl: bindctl-source.py
-e "s|@@SYSCONFDIR@@|@sysconfdir@|" \
-e "s|@@LIBEXECDIR@@|$(pkglibexecdir)|" bindctl-source.py >$@
chmod a+x $@
if INSTALL_CONFIGURATIONS
# TODO: permissions handled later
install-data-local:
$(mkinstalldirs) $(DESTDIR)/@sysconfdir@/@PACKAGE@
if test ! -f $(DESTDIR)$(sysconfdir)/@PACKAGE@/bindctl.pem; then \
$(INSTALL_DATA) $(srcdir)/bindctl.pem $(DESTDIR)$(sysconfdir)/@PACKAGE@/ ; \
fi
endif
......@@ -18,3 +18,4 @@ functions should be updated first.):
If the default user is saved in file, its password shouldn't be saved in plaintext.
7. Need to think of what exactly to do with responses received to commands
(currently it simply print the map)
8. Remove bindctl-source.py.in(replace with bindctl-source.py) when merging to trunk.
......@@ -36,6 +36,9 @@ import getpass
from hashlib import sha1
import csv
import ast
import pwd
import getpass
import traceback
try:
from collections import OrderedDict
......@@ -49,6 +52,8 @@ try:
except ImportError:
my_readline = sys.stdin.readline
CSV_FILE_NAME = 'default_user.csv'
FAIL_TO_CONNECT_WITH_CMDCTL = "Fail to connect with b10-cmdctl module, is it running?"
CONFIG_MODULE_NAME = 'config'
CONST_BINDCTL_HELP = """
usage: <module name> <command name> [param1 = value1 [, param2 = value2]]
......@@ -58,10 +63,34 @@ Type \"<module_name> help\" for help on the specific module.
Type \"<module_name> <command_name> help\" for help on the specific command.
\nAvailable module names: """
class ValidatedHTTPSConnection(http.client.HTTPSConnection):
'''Overrides HTTPSConnection to support certification
validation. '''
def __init__(self, host, ca_certs):
http.client.HTTPSConnection.__init__(self, host)
self.ca_certs = ca_certs
def connect(self):
''' Overrides the connect() so that we do
certificate validation. '''
sock = socket.create_connection((self.host, self.port),
self.timeout)
if self._tunnel_host:
self.sock = sock
self._tunnel()
req_cert = ssl.CERT_NONE
if self.ca_certs:
req_cert = ssl.CERT_REQUIRED
self.sock = ssl.wrap_socket(sock, self.key_file,
self.cert_file,
cert_reqs=req_cert,
ca_certs=self.ca_certs)
class BindCmdInterpreter(Cmd):
"""simple bindctl example."""
def __init__(self, server_port = 'localhost:8080', pem_file = "bindctl.pem"):
def __init__(self, server_port = 'localhost:8080', pem_file = None):
Cmd.__init__(self)
self.location = ""
self.prompt_end = '> '
......@@ -70,19 +99,10 @@ class BindCmdInterpreter(Cmd):
self.modules = OrderedDict()
self.add_module_info(ModuleInfo("help", desc = "Get help for bindctl"))
self.server_port = server_port
self.pem_file = pem_file
self._connect_to_cmd_ctrld()
self.conn = ValidatedHTTPSConnection(self.server_port,
ca_certs=pem_file)
self.session_id = self._get_session_id()
def _connect_to_cmd_ctrld(self):
'''Connect to cmdctl in SSL context. '''
try:
self.conn = http.client.HTTPSConnection(self.server_port,
cert_file=self.pem_file)
except Exception as e:
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)
......@@ -93,17 +113,59 @@ class BindCmdInterpreter(Cmd):
return digest
def run(self):
'''Parse commands inputted from user and send them to cmdctl. '''
'''Parse commands from user and send them to cmdctl. '''
try:
if not self.login_to_cmdctl():
return False
return
# Get all module information from cmd-ctrld
self.config_data = isc.config.UIModuleCCSession(self)
self._update_commands()
self.cmdloop()
except FailToLogin as err:
print(err)
print(FAIL_TO_CONNECT_WITH_CMDCTL)
traceback.print_exc()
except KeyboardInterrupt:
return True
print('\nExit from bindctl')
def _get_saved_user_info(self, dir, file_name):
''' Read all the available username and password pairs saved in
file(path is "dir + file_name"), Return value is one list of elements
['name', 'password'], If get information failed, empty list will be
returned.'''
if (not dir) or (not os.path.exists(dir)):
return []
try:
csvfile = None
users = []
csvfile = open(dir + file_name)
users_info = csv.reader(csvfile)
for row in users_info:
users.append([row[0], row[1]])
except (IOError, IndexError) as e:
pass
finally:
if csvfile:
csvfile.close()
return users
def _save_user_info(self, username, passwd, dir, file_name):
''' Save username and password in file "dir + file_name"
If it's saved properly, return True, or else return False. '''
try:
if not os.path.exists(dir):
os.mkdir(dir, 0o700)
csvfilepath = dir + file_name
csvfile = open(csvfilepath, 'w')
os.chmod(csvfilepath, 0o600)
writer = csv.writer(csvfile)
writer.writerow([username, passwd])
csvfile.close()
except Exception as e:
print(e, "\nCannot write %s%s; default user is not stored" % (dir, file_name))
return False
return True
def login_to_cmdctl(self):
'''Login to cmdctl with the username and password inputted
......@@ -112,33 +174,21 @@ class BindCmdInterpreter(Cmd):
time, username and password saved in 'default_user.csv' will be
used first.
'''
csvfile = None
bsuccess = False
try:
cvsfilepath = ""
if ('HOME' in os.environ):
cvsfilepath = os.environ['HOME']
cvsfilepath += os.sep + '.bind10' + os.sep
cvsfilepath += 'default_user.csv'
csvfile = open(cvsfilepath)
users = csv.reader(csvfile)
for row in users:
param = {'username': row[0], 'password' : row[1]}
csv_file_dir = pwd.getpwnam(getpass.getuser()).pw_dir
csv_file_dir += os.sep + '.bind10' + os.sep
users = self._get_saved_user_info(csv_file_dir, CSV_FILE_NAME)
for row in users:
param = {'username': row[0], 'password' : row[1]}
try:
response = self.send_POST('/login', param)
data = response.read().decode()
if response.status == http.client.OK:
print(data + ' login as ' + row[0] )
bsuccess = True
break
except IOError as e:
pass
except Exception as e:
print(e)
finally:
if csvfile:
csvfile.close()
if bsuccess:
return True
except socket.error:
traceback.print_exc()
raise FailToLogin()
if response.status == http.client.OK:
print(data + ' login as ' + row[0] )
return True
count = 0
print("[TEMP MESSAGE]: username :root password :bind10")
......@@ -151,34 +201,18 @@ class BindCmdInterpreter(Cmd):
username = input("Username:")
passwd = getpass.getpass()
param = {'username': username, 'password' : passwd}
response = self.send_POST('/login', param)
data = response.read().decode()
print(data)
try:
response = self.send_POST('/login', param)
data = response.read().decode()
print(data)
except socket.error as e:
traceback.print_exc()
raise FailToLogin()
if response.status == http.client.OK:
cvsfilepath = ""
try:
if ('HOME' in os.environ):
cvsfilepath = os.environ['HOME']
cvsfilepath += os.sep + '.bind10' + os.sep
if not os.path.exists(cvsfilepath):
os.mkdir(cvsfilepath, 0o700)
else:
print("Cannot determine location of $HOME. Not storing default user")
return True
cvsfilepath += 'default_user.csv'
csvfile = open(cvsfilepath, 'w')
os.chmod(cvsfilepath, 0o600)
writer = csv.writer(csvfile)
writer.writerow([username, passwd])
csvfile.close()
except Exception as e:
# just not store it
print("Cannot write ~/.bind10/default_user.csv; default user is not stored")
print(e)
self._save_user_info(username, passwd, csv_file_dir, CSV_FILE_NAME)
return True
def _update_commands(self):
'''Update the commands of all modules. '''
for module_name in self.config_data.get_config_item_list():
......@@ -211,7 +245,19 @@ class BindCmdInterpreter(Cmd):
headers = {"cookie" : self.session_id}
self.conn.request('POST', url, param, headers)
return self.conn.getresponse()
def _update_all_modules_info(self):
''' Get all modules' information from cmdctl, including
specification file and configuration data. This function
should be called before interpreting command line or complete-key
is entered. This may not be the best way to keep bindctl
and cmdctl share same modules information, but it works.'''
self.config_data = isc.config.UIModuleCCSession(self)
self._update_commands()
def precmd(self, line):
self._update_all_modules_info()
return line
def postcmd(self, stop, line):
'''Update the prompt after every command'''
......@@ -308,8 +354,11 @@ class BindCmdInterpreter(Cmd):
if cmd.module != CONFIG_MODULE_NAME:
for param_name in cmd.params:
param_spec = command_info.get_param_with_name(param_name).param_spec
cmd.params[param_name] = isc.config.config_data.convert_type(param_spec, cmd.params[param_name])
try:
cmd.params[param_name] = isc.config.config_data.convert_type(param_spec, cmd.params[param_name])
except isc.cc.data.DataTypeError as e:
raise isc.cc.data.DataTypeError('Invalid parameter value for \"%s\", the type should be \"%s\" \n'
% (param_name, param_spec['item_type']) + str(e))
def _handle_cmd(self, cmd):
'''Handle a command entered by the user'''
......@@ -356,6 +405,7 @@ class BindCmdInterpreter(Cmd):
def complete(self, text, state):
if 0 == state:
self._update_all_modules_info()
text = text.strip()
hints = []
cur_line = my_readline()
......@@ -441,13 +491,14 @@ class BindCmdInterpreter(Cmd):
cmd = BindCmdParse(line)
self._validate_cmd(cmd)
self._handle_cmd(cmd)
except BindCtlException as e:
print("Error! ", e)
self._print_correct_usage(e)
except isc.cc.data.DataTypeError as e:
print("Error! ", e)
self._print_correct_usage(e)
except (IOError, http.client.HTTPException) as err:
print('Error!', err)
print(FAIL_TO_CONNECT_WITH_CMDCTL)
except BindCtlException as err:
print("Error! ", err)
self._print_correct_usage(err)
except isc.cc.data.DataTypeError as err:
print("Error! ", err)
def _print_correct_usage(self, ept):
if isinstance(ept, CmdUnknownModuleSyntaxError):
......@@ -556,7 +607,7 @@ class BindCmdInterpreter(Cmd):
if (len(cmd.params) != 0):
cmd_params = json.dumps(cmd.params)
print("send the message to cmd-ctrld")
print("send the command to cmd-ctrld")
reply = self.send_POST(url, cmd.params)
data = reply.read().decode()
print("received reply:", data)
......
......@@ -97,13 +97,16 @@ def check_addr(option, opt_str, value, parser):
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')
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')
action = 'callback', callback=check_addr,
default = '127.0.0.1', help = 'IP address for cmdctl of bind10')
parser.add_option('-c', '--certificate-chain', dest = 'cert_chain',
type = 'string', action = 'store',
help = 'PEM formatted server certificate validation chain file')
if __name__ == '__main__':
try:
......@@ -111,14 +114,7 @@ if __name__ == '__main__':
set_bindctl_options(parser)
(options, args) = parser.parse_args()
server_addr = options.addr + ':' + str(options.port)
# If B10_FROM_SOURCE is set in the environment, we use PEM file
# from a directory relative to that, otherwise we use the one
# installed on the system
if "B10_FROM_SOURCE" in os.environ:
SYSCONF_PATH = os.environ["B10_FROM_SOURCE"] + "/src/bin/bindctl"
else:
SYSCONF_PATH = "@@SYSCONFDIR@@/@PACKAGE@"
tool = BindCmdInterpreter(server_addr, pem_file = SYSCONF_PATH + "/bindctl.pem")
tool = BindCmdInterpreter(server_addr, pem_file=options.cert_chain)
prepare_config_commands(tool)
tool.run()
except Exception as e:
......
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQDpICWxJGKMvUhLFPbf5n8ZWogqjYcQqqoHqHVRHYjyiey6FZdt
ZkY2s1gYh0G0NXtimlIgic+vEcFe7vdmyKntW7DYDaqAj0KrED7RKAj8324jNbSJ
HtLP4evvJep3vsoNtTvNuceQJ46vukxyxgg3DuC9kVqPuD8CZ1Rq4ATyiwIDAQAB
AoGBAOJlOtV+DUq6Y2Ou91VXRiU8GzKgAQP5iWgoe84Ljbxkn4XThBxVD2j94Fbp
u7AjpDCMx6cbzpoo9w6XqaGizAmAehIfTE3eFYs74N/FM09Wg2OSDyxMY0jgyECU
A4ukjlPwcGDbmgbmlY3i+FVHp+zCgtZEsMC1IAosMac1BoX5AkEA/lrXWaVtH8bo
mut3GBaXvubZMdaUr0BUd5a9q+tt4dQcKG1kFqgCNKhNhBIcpiMVcz+jGmOuopNA
8dnUGqv3FQJBAOqiJ54ZvOTWNDpJIe02wIXRxRmc1xhHFCqYP23KxBVrAcTYB19J
lesov/hEbnGLCbKS/naZJ1zrTImUPNRLqx8CQCzDtA7U7GWhTiKluioFH+O7IRKC
X1yQh80cPHlbT9VkzSfYSLssCmdWD35k6aHbntTPqFbmoD+AhveJjKi9BxkCQDwX
1c+/RcrSNcQr0N2hZUOgyztZGRnlsnuKTMyA3yGhK23P6mt0PEpjQG+Ej0jTVGOB
FF0pspQwy4R9C+tPif8CQH36NNlXBfVNmT7kDtyLmaE6pID0vY9duX56BJbU1R0x
SQ8/LcfJagk6gvp08OyYCPA+WZ7u/bas9R/nMTCLivc=
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIDhzCCAvCgAwIBAgIJALwngNFik7ONMA0GCSqGSIb3DQEBBQUAMIGKMQswCQYD
VQQGEwJjbjEQMA4GA1UECBMHYmVpamluZzEQMA4GA1UEBxMHYmVpamluZzEOMAwG
A1UEChMFY25uaWMxDjAMBgNVBAsTBWNubmljMRMwEQYDVQQDEwp6aGFuZ2xpa3Vu
MSIwIAYJKoZIhvcNAQkBFhN6aGFuZ2xpa3VuQGNubmljLmNuMB4XDTEwMDEwNzEy
NDcxOFoXDTExMDEwNzEyNDcxOFowgYoxCzAJBgNVBAYTAmNuMRAwDgYDVQQIEwdi
ZWlqaW5nMRAwDgYDVQQHEwdiZWlqaW5nMQ4wDAYDVQQKEwVjbm5pYzEOMAwGA1UE
CxMFY25uaWMxEzARBgNVBAMTCnpoYW5nbGlrdW4xIjAgBgkqhkiG9w0BCQEWE3po
YW5nbGlrdW5AY25uaWMuY24wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOkg
JbEkYoy9SEsU9t/mfxlaiCqNhxCqqgeodVEdiPKJ7LoVl21mRjazWBiHQbQ1e2Ka
UiCJz68RwV7u92bIqe1bsNgNqoCPQqsQPtEoCPzfbiM1tIke0s/h6+8l6ne+yg21
O825x5Anjq+6THLGCDcO4L2RWo+4PwJnVGrgBPKLAgMBAAGjgfIwge8wHQYDVR0O
BBYEFJKM/O0ViGlwtb3JEci/DLTO/7DaMIG/BgNVHSMEgbcwgbSAFJKM/O0ViGlw
tb3JEci/DLTO/7DaoYGQpIGNMIGKMQswCQYDVQQGEwJjbjEQMA4GA1UECBMHYmVp
amluZzEQMA4GA1UEBxMHYmVpamluZzEOMAwGA1UEChMFY25uaWMxDjAMBgNVBAsT
BWNubmljMRMwEQYDVQQDEwp6aGFuZ2xpa3VuMSIwIAYJKoZIhvcNAQkBFhN6aGFu
Z2xpa3VuQGNubmljLmNuggkAvCeA0WKTs40wDAYDVR0TBAUwAwEB/zANBgkqhkiG
9w0BAQUFAAOBgQBh5N6isMAQAFFD+pbfpppjQlO4vUNcEdzPdeuBFaf9CsX5ZdxV
jmn1ZuGm6kRzqUPwPSxvCIAY0wuSu1g7YREPAZ3XBVwcg6262iGOA6n7E+nv5PLz
EuZ1oUg+IfykUIoflKH6xZB4MyPL+EgkMT+i9BrngaXHXF8tEO30YppMiA==
-----END CERTIFICATE-----
......@@ -24,15 +24,19 @@ except ImportError:
from bindctl.mycollections import OrderedDict
param_name_str = "^\s*(?P<param_name>[\w]+)\s*=\s*"
param_value_str = "(?P<param_value>[\w\.:/-]+)"
param_value_with_quota_str = "[\"\'](?P<param_value>[\w\.:, /-]+)[\"\']"
# The value string can be a sequence without space or comma
# characters, or a string surroundedby quotation marks(such marks
# can be part of string in an escaped form)
#param_value_str = "(?P<param_value>[\"\'].+?(?<!\\\)[\"\']|[^\'\"][^, ]+)"
param_value_str = "(?P<param_value>[^\'\" ][^, ]+)"
param_value_with_quota_str = "[\"\'](?P<param_value>.+?)(?<!\\\)[\"\']"
next_params_str = "(?P<blank>\s*)(?P<comma>,?)(?P<next_params>.*)$"
PARAM_WITH_QUOTA_PATTERN = re.compile(param_name_str +
param_value_with_quota_str +
param_value_with_quota_str +
next_params_str)
PARAM_PATTERN = re.compile(param_name_str + param_value_str + next_params_str)
# Used for module and command name
NAME_PATTERN = re.compile("^\s*(?P<name>[\w]+)(?P<blank>\s*)(?P<others>.*)$")
......@@ -98,7 +102,6 @@ class BindCmdParse:
groups = PARAM_PATTERN.match(param_text) or \
PARAM_WITH_QUOTA_PATTERN.match(param_text)
if not groups:
# ok, fill in the params in the order entered
params = re.findall("([^\" ]+|\".*\")", param_text)
......
......@@ -115,3 +115,10 @@ class CmdMissParamSyntaxError(CmdSyntaxError):
def __str__(self):
return str("Parameter '%s' is missed for command '%s' of module '%s'" %
(self.param, self.command, self.module))
class FailToLogin(BindCtlException):
def __str__(self):
return "Fail to login to cmdctl"
......@@ -16,6 +16,7 @@
import unittest
import isc.cc.data
import os
from bindctl import cmdparse
from bindctl import bindcmd
from bindctl.moduleinfo import *
......@@ -50,12 +51,31 @@ class TestCmdLex(unittest.TestCase):
assert cmd.params["zone_name"] == "cnnic.cn"
assert cmd.params["file"] == "cnnic.cn.file"
assert cmd.params["master"] == '1.1.1.1'
def testCommandWithParamters_2(self):
'''Test whether the parameters in key=value can be parsed properly.'''
cmd = cmdparse.BindCmdParse('zone cmd name = 1:34::2')
self.assertEqual(cmd.params['name'], '1:34::2')
cmd = cmdparse.BindCmdParse('zone cmd name = 1\"\'34**&2 value=44\"\'\"')
self.assertEqual(cmd.params['name'], '1\"\'34**&2')
self.assertEqual(cmd.params['value'], '44\"\'\"')
cmd = cmdparse.BindCmdParse('zone cmd name = 1\"\'34**&2 ,value= 44\"\'\"')
self.assertEqual(cmd.params['name'], '1\"\'34**&2')
self.assertEqual(cmd.params['value'], '44\"\'\"')
cmd = cmdparse.BindCmdParse('zone cmd name = 1\'34**&2value=44\"\'\" value = \"==============\'')
self.assertEqual(cmd.params['name'], '1\'34**&2value=44\"\'\"')
self.assertEqual(cmd.params['value'], '==============')
cmd = cmdparse.BindCmdParse('zone cmd name = \"1234, 567890 \" value ==&*/')
self.assertEqual(cmd.params['name'], '1234, 567890 ')
self.assertEqual(cmd.params['value'], '=&*/')
def testCommandWithListParam(self):
cmd = cmdparse.BindCmdParse("zone set zone_name='cnnic.cn', master='1.1.1.1, 2.2.2.2'")
assert cmd.params["master"] == '1.1.1.1, 2.2.2.2'
cmd = cmdparse.BindCmdParse("zone set zone_name='cnnic.cn', master='1.1.1.1, 2.2.2.2'")
assert cmd.params["master"] == '1.1.1.1, 2.2.2.2'
def testCommandWithHelpParam(self):
cmd = cmdparse.BindCmdParse("zone add help")
......@@ -217,8 +237,32 @@ class TestNameSequence(unittest.TestCase):
assert self.random_names[i] == cmd_names[i+1]
assert self.random_names[i] == module_names[i+1]
i = i + 1
class FakeBindCmdInterpreter(bindcmd.BindCmdInterpreter):
def __init__(self):
pass
class TestBindCmdInterpreter(unittest.TestCase):
def _create_invalid_csv_file(self, csvfilename):
import csv
csvfile = open(csvfilename, 'w')
writer = csv.writer(csvfile)
writer.writerow(['name1'])
writer.writerow(['name2'])
csvfile.close()
def test_get_saved_user_info(self):
cmd = FakeBindCmdInterpreter()
users = cmd._get_saved_user_info('/notexist', 'cvs_file.cvs')
self.assertEqual([], users)
csvfilename = 'csv_file.csv'
self._create_invalid_csv_file(csvfilename)
users = cmd._get_saved_user_info('./', csvfilename)
self.assertEqual([], users)
os.remove(csvfilename)
if __name__== "__main__":
unittest.main()
......@@ -17,9 +17,8 @@ b10_cmdctl_DATA = $(CMDCTL_CONFIGURATIONS)
b10_cmdctl_DATA += cmdctl.spec
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
......@@ -31,6 +30,9 @@ b10-cmdctl.8: 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
b10-cmdctl: cmdctl.py
......
. 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).
. Use only one msgq/session to communicate with other modules?
. 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)
This diff is collapsed.
{
"module_spec": {
"module_name": "Cmdctl",
"module_description": "Interface for command and control",
"config_data": [
{
"item_name": "key_file",