Commit 25ccb97a authored by Likun Zhang's avatar Likun Zhang
Browse files

Add code for BigTool

git-svn-id: svn://bind10.isc.org/svn/bind10/branches/f2f200910@186 e5f2f494-b856-4b98-b285-d166d9295462
parent 296add2d
#! /bin/sh
PYTHON_EXEC=/usr/bin/python3
BIGTOOL_PATH=.
PYTHONPATH=../../lib/cc/python:../../lib/cc/python/ISC:../../lib/cc/python/ISC/CC:../../lib/cc/python/ISC/Util:../../lib/bigtool/
export PYTHONPATH
cd ${BIGTOOL_PATH}
exec ${PYTHON_EXEC} -O run_bigtool.py $*
from moduleinfo import *
from bigtool import *
def _prepare_fake_data(bigtool):
add_cmd = CommandInfo(name = "add", desc = "add one zone")
remove_cmd = CommandInfo(name = 'remove', desc = 'remove one zone')
list_cmd = CommandInfo(name = 'list', desc = 'list all zones', need_inst_param = False)
zone_module = ModuleInfo(name = "zone",
inst_name = "zone_name",
inst_type = STRING_TYPE,
inst_desc = "the name of one zone",
desc = "manage all the zones")
zone_module.add_command(add_cmd)
zone_module.add_command(remove_cmd)
zone_module.add_command(list_cmd)
bigtool.add_module_info(zone_module)
if __name__ == '__main__':
tool = BigTool()
_prepare_fake_data(tool)
tool.cmdloop()
__all__ = ['mycollections', 'exception', 'moduleinfo', 'command', 'bigtool']
import sys
import readline
from cmd import Cmd
from exception import *
from moduleinfo import ModuleInfo
from moduleinfo import ParamInfo
from command import BigToolCmd
from xml.dom import minidom
import ISC
try:
from collections import OrderedDict
except ImportError:
from mycollections import OrderedDict
CONST_BIGTOOL_HELP = """Bigtool, verstion 0.1
usage: <module name> <command name> [param1 = value1 [, param2 = value2]]
Type Tab character to get the hint of module/command/paramters.
Type \"help(? h)\" for help on bigtool.
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: """
CONST_COMMAND_NODE = "command"
class BigTool(Cmd):
"""simple bigtool example."""
def __init__(self):
Cmd.__init__(self)
self.prompt = '> '
self.ruler = '-'
self.modules = OrderedDict()
self.add_module_info(ModuleInfo("help", desc = "Get help for bigtool"))
try:
self.cc = ISC.CC.Session()
self.cc.group_subscribe("BigTool")
self.cc.group_subscribe("ConfigManager")
except ISC.CC.SessionError:
print("Failed to create cchannel session")
return
def validate_cmd(self, cmd):
if not cmd.module in self.modules:
raise CmdUnknownModuleSyntaxError(cmd.module)
module_info = self.modules[cmd.module]
if not module_info.has_command_with_name(cmd.command):
raise CmdUnknownCmdSyntaxError(cmd.module, cmd.command)
command_info = module_info.get_command_with_name(cmd.command)
manda_params = command_info.get_mandatory_param_names()
all_params = command_info.get_param_names()
# If help is inputed, don't do further paramters validation.
for val in cmd.params.keys():
if val == "help":
return
params = cmd.params.copy()
if not params and manda_params:
raise CmdMissParamSyntaxError(cmd.module, cmd.command, manda_params[0])
elif params and not all_params:
raise CmdUnknownParamSyntaxError(cmd.module, cmd.command,
list(params.keys())[0])
elif params:
for name in params:
if not name in all_params:
raise CmdUnknownParamSyntaxError(cmd.module, cmd.command, name)
for name in manda_params:
if not name in params:
raise CmdMissParamSyntaxError(cmd.module, cmd.command, name)
def _handle_cmd(self, cmd):
#to do, consist xml package and send to bind10
if cmd.command == "help" or ("help" in cmd.params.keys()):
self._handle_help(cmd)
else:
self.apply_cmd(cmd)
def add_module_info(self, module_info):
self.modules[module_info.name] = module_info
def get_module_names(self):
return list(self.modules.keys())
#override methods in cmd
def default(self, line):
self._parse_cmd(line)
def emptyline(self):
pass
def cmdloop(self):
try:
Cmd.cmdloop(self)
except KeyboardInterrupt:
return True
def do_help(self, name):
print(CONST_BIGTOOL_HELP)
for k in self.modules.keys():
print("\t", self.modules[k])
def onecmd(self, line):
if line == 'EOF'or line.lower() == "quit":
return True
if line == 'h':
line = 'help'
Cmd.onecmd(self, line)
def complete(self, text, state):
if 0 == state:
text = text.strip()
hints = []
cur_line = readline.get_line_buffer()
try:
cmd = BigToolCmd(cur_line)
if not cmd.params and text:
hints = self._get_command_startswith(cmd.module, text)
else:
hints = self._get_param_startswith(cmd.module, cmd.command,
text)
except CmdModuleNameFormatError:
if not text:
hints = list(self.modules.keys())
except CmdMissCommandNameFormatError as e:
if not text.strip(): # command name is empty
hints = self.modules[e.module].get_command_names()
else:
hints = self._get_module_startswith(text)
except CmdCommandNameFormatError as e:
if e.module in self.modules:
hints = self._get_command_startswith(e.module, text)
except CmdParamFormatError as e:
hints = self._get_param_startswith(e.module, e.command, text)
except BigToolException:
hints = []
self.hint = hints
self._append_space_to_hint()
if state < len(self.hint):
return self.hint[state]
else:
return None
def _get_module_startswith(self, text):
return [module
for module in self.modules
if module.startswith(text)]
def _get_command_startswith(self, module, text):
if module in self.modules:
return [command
for command in self.modules[module].get_command_names()
if command.startswith(text)]
return []
def _get_param_startswith(self, module, command, text):
if module in self.modules:
module_info = self.modules[module]
if command in module_info.get_command_names():
cmd_info = module_info.get_command_with_name(command)
params = cmd_info.get_param_names()
hint = []
if text:
hint = [val for val in params if val.startswith(text)]
else:
hint = list(params)
if len(hint) == 1 and hint[0] != "help":
hint[0] = hint[0] + " ="
return hint
return []
def _parse_cmd(self, line):
try:
cmd = BigToolCmd(line)
self.validate_cmd(cmd)
self._handle_cmd(cmd)
except BigToolException as e:
print("Error! ", e)
self._print_correct_usage(e)
def _print_correct_usage(self, ept):
if isinstance(ept, CmdUnknownModuleSyntaxError):
self.do_help(None)
elif isinstance(ept, CmdUnknownCmdSyntaxError):
self.modules[ept.module].module_help()
elif isinstance(ept, CmdMissParamSyntaxError) or \
isinstance(ept, CmdUnknownParamSyntaxError):
self.modules[ept.module].command_help(ept.command)
def _append_space_to_hint(self):
"""Append one space at the end of complete hint."""
self.hint = [(val + " ") for val in self.hint]
def _handle_help(self, cmd):
if cmd.command == "help":
self.modules[cmd.module].module_help()
else:
self.modules[cmd.module].command_help(cmd.command)
def apply_cmd(self, cmd):
try:
msg ={"command": [cmd.module, cmd.command, list(cmd.params.values())[0]]}
print("begin to send the message...")
self.cc.group_sendmsg(msg, "ConfigManager")
print("waiting for configure manager reply...")
reply, env = self.cc.group_recvmsg(False)
print("received reply:", reply)
except ISC.CC.SessionError:
print("Error commucation with configure manager")
import re
from exception import *
try:
from collections import OrderedDict
except ImportError:
from 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\., ]+)[\"\']"
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 +
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>.*)$")
class BigToolCmd:
""" This class will parse the command line usr input into three part
module name, cmmand, parameters
the first two parts are strings and parameter is one hash,
parameter part is optional
Example: zone reload, zone_name=example.com
module == zone
command == reload
params == [zone_name = 'example.com']
"""
def __init__(self, cmd):
self.params = OrderedDict()
self.module = ''
self.command = ''
self._parse_cmd(cmd)
def _parse_cmd(self, text_str):
# Get module name
groups = NAME_PATTERN.match(text_str)
if not groups:
raise CmdModuleNameFormatError
self.module = groups.group('name')
cmd_str = groups.group('others')
if cmd_str:
if not groups.group('blank'):
raise CmdModuleNameFormatError
else:
raise CmdMissCommandNameFormatError(self.module)
# Get command name
groups = NAME_PATTERN.match(cmd_str)
if (not groups):
raise CmdCommandNameFormatError(self.module)
self.command = groups.group('name')
param_str = groups.group('others')
if param_str:
if not groups.group('blank'):
raise CmdCommandNameFormatError(self.module)
self._parse_params(param_str)
def _parse_params(self, param_text):
"""convert a=b,c=d into one hash """
# Check parameter name "help"
param = NAME_PATTERN.match(param_text)
if param and param.group('name') == "help":
self.params["help"] = "help"
return
while True:
if not param_text.strip():
break
groups = PARAM_PATTERN.match(param_text) or \
PARAM_WITH_QUOTA_PATTERN.match(param_text)
if not groups:
raise CmdParamFormatError(self.module, self.command)
else:
self.params[groups.group('param_name')] = groups.group('param_value')
param_text = groups.group('next_params')
if not param_text or (not param_text.strip()):
break
if not groups.group('blank') and \
not groups.group('comma'):
raise CmdParamFormatError(self.module, self.command)
class BigToolException(Exception):
"""Abstract base class shared by all bigtool exceptions"""
def __str__(self):
return "Big tool has problem"
# Begin define Format exception
class CmdFormatError(BigToolException):
"""Command is malformed"""
def __str__(self):
return "Command is malformed"
class CmdModuleNameFormatError(CmdFormatError):
"""module name format error"""
def __str__(self):
return "Module name format error: the charater of name can only be '0-9a-zA-Z_'"
class CmdCommandNameFormatError(CmdFormatError):
"""command name format error"""
def __init__(self, module):
self.module = module
def __str__(self):
return "Command name format error: the charater of name can only be '0-9a-zA-Z_'"
class CmdMissCommandNameFormatError(CmdFormatError):
"""Module name isn't finished"""
def __init__(self, module):
self.module = module
def __str__(self):
return "command name is missed"
class CmdParamFormatError(CmdFormatError):
"""Command is malformed which parameter isn't key value pair"""
def __init__(self, module, command):
self.module = module
self.command = command
def __str__(self):
return "Parameter format error, it should like 'key = value'"
# Begin define the exception for syntax
class CmdSyntaxError(BigToolException):
"""Command line has syntax error"""
def __str__(self):
return "Command line has syntax error"
class CmdUnknownModuleSyntaxError(CmdSyntaxError):
"""Command is unknown"""
def __init__(self, module):
self.module = module
def __str__(self):
return str("Unknown module '%s'" % self.module)
class CmdUnknownCmdSyntaxError(CmdSyntaxError):
"""Command is unknown"""
def __init__(self, module, command):
self.module = module
self.command = command
def __str__(self):
return str("Unknown command '%s' to module '%s'" %
(self.command, self.module))
class CmdUnknownParamSyntaxError(CmdSyntaxError):
"""The parameter of command is unknown"""
def __init__(self, module, command, param):
self.module = module
self.command = command
self.param = param
def __str__(self):
return str("Unknown parameter '%s' to command '%s' of module '%s'" %
(self.param, self.command, self.module))
class CmdMissParamSyntaxError(CmdSyntaxError):
"""The parameter of one command is missed"""
def __init__(self, module, command, param):
self.module = module
self.command = command
self.param = param
def __str__(self):
return str("Parameter '%s' is missed for command '%s' of moudule '%s'" %
(self.param, self.command, self.module))
try:
from collections import OrderedDict
except ImportError:
from mycollections import OrderedDict
# Define value type
STRING_TYPE = "string"
LIST_TYPE = "list"
INT_TYPE = "int"
MODULE_NODE_NAME = 'module'
COMMAND_NODE_NAME = 'command'
PARAM_NODE_NAME = 'param'
class ParamInfo:
"""The parameter of one command
each command parameter have four attributes,
parameter name, parameter type, parameter value, and parameter description
"""
def __init__(self, name, desc = '', type = STRING_TYPE,
optional = False, value = '', default_value = ''):
self.name = name
self.type = type
self.value = value
self.default_value = default_value
self.desc = desc
self.is_optional = optional
def __str__(self):
return str("\t%s <type: %s> \t(%s)" % (self.name, self.type, self.desc))
def write_xml(xmldoc, name, value):
node = xmldoc.createElement(PARAM_NODE_NAME)
node.setAttribute('name', name)
node.setAttribute('value', value)
return node
class CommandInfo:
"""One command which provide by one bind10 module, it has zero or
more parameters
"""
def __init__(self, name, desc = "", need_inst_param = True):
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"
self.add_param(ParamInfo("help",
desc = "Get help for command",
optional = True))
def __str__(self):
return str("%s \t(%s)" % (self.name, self.desc))
def add_param(self, paraminfo):
self.params[paraminfo.name] = paraminfo
def has_param_with_name(self, param_name):
return param_name in self.params
def get_param_with_name(self, param_name):
return self.params[param_name]
def get_params(self):
return list(self.params.values())
def get_param_names(self):
return list(self.params.keys())
def get_mandatory_param_names(self):
all_names = self.params.keys()
return [name for name in all_names
if not self.params[name].is_optional]
def need_instance_param(self):
return self.need_inst_param
def write_xml(self, xmldoc, command_name):
node = xmldoc.createElement(COMMAND_NODE_NAME)
node.setAttribute('name', command_name)
return node
def command_help(self, inst_name, inst_type, inst_desc):
print("Command ", self)
print("\t\thelp (Get help for command)")
params = self.params.copy()
del params["help"]
if len(params) == 0:
print("\tNo parameters for the command")
return
print("\n\tMandatory parameters:")
mandatory_infos = []
for info in params.values():
if not info.is_optional:
print("\t", info)
mandatory_infos.append(info)
optional_infos = [info for info in params.values()
if info not in mandatory_infos]
if len(optional_infos) > 0:
print("\n\tOptional parameters:")
for info in optional_infos:
print("\t", info)
class ModuleInfo:
"""Define the information of one module, include module name,
module supporting commands, instance name and the value type of instance name
"""