2010-01-28 23:47:18 +00:00
|
|
|
# Copyright (C) 2009 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
|
|
|
|
# copyright notice and this permission notice appear in all copies.
|
|
|
|
#
|
|
|
|
# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
|
|
|
|
# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
|
|
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
|
|
|
|
# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
|
|
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
|
|
|
|
# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
|
|
|
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
|
|
|
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
|
2010-03-16 12:39:09 +00:00
|
|
|
"""This module holds the BindCmdInterpreter class. This provides the
|
|
|
|
core functionality for bindctl. It maintains a session with
|
|
|
|
b10-cmdctl, holds local configuration and module information, and
|
|
|
|
handles command line interface commands"""
|
|
|
|
|
2010-01-28 23:47:18 +00:00
|
|
|
import sys
|
|
|
|
from cmd import Cmd
|
2010-03-15 14:24:33 +00:00
|
|
|
from bindctl.exception import *
|
|
|
|
from bindctl.moduleinfo import *
|
|
|
|
from bindctl.cmdparse import BindCmdParse
|
2010-01-28 23:47:18 +00:00
|
|
|
from xml.dom import minidom
|
2010-02-01 10:48:19 +00:00
|
|
|
import isc
|
|
|
|
import isc.cc.data
|
2010-01-28 23:47:18 +00:00
|
|
|
import http.client
|
|
|
|
import json
|
|
|
|
import inspect
|
|
|
|
import pprint
|
|
|
|
import ssl, socket
|
|
|
|
import os, time, random, re
|
|
|
|
import getpass
|
|
|
|
from hashlib import sha1
|
|
|
|
import csv
|
2010-02-15 13:30:39 +00:00
|
|
|
import ast
|
2010-01-28 23:47:18 +00:00
|
|
|
|
|
|
|
try:
|
|
|
|
from collections import OrderedDict
|
|
|
|
except ImportError:
|
2010-03-15 14:24:33 +00:00
|
|
|
from bindctl.mycollections import OrderedDict
|
2010-01-28 23:47:18 +00:00
|
|
|
|
2010-03-16 10:32:51 +00:00
|
|
|
# if we have readline support, use that, otherwise use normal stdio
|
|
|
|
try:
|
|
|
|
import readline
|
|
|
|
my_readline = readline.get_line_buffer
|
|
|
|
except ImportError:
|
|
|
|
my_readline = sys.stding.readline
|
|
|
|
|
2010-01-28 23:47:18 +00:00
|
|
|
|
2010-03-17 03:26:04 +00:00
|
|
|
CONST_BINDCTL_HELP = """
|
2010-01-28 23:47:18 +00:00
|
|
|
usage: <module name> <command name> [param1 = value1 [, param2 = value2]]
|
2010-03-16 14:04:16 +00:00
|
|
|
Type Tab character to get the hint of module/command/parameters.
|
2010-01-28 23:47:18 +00:00
|
|
|
Type \"help(? h)\" for help on bindctl.
|
|
|
|
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 BindCmdInterpreter(Cmd):
|
|
|
|
"""simple bindctl example."""
|
|
|
|
|
2010-03-16 00:21:30 +00:00
|
|
|
def __init__(self, server_port = 'localhost:8080', pem_file = "bindctl.pem"):
|
2010-01-28 23:47:18 +00:00
|
|
|
Cmd.__init__(self)
|
|
|
|
self.location = ""
|
|
|
|
self.prompt_end = '> '
|
|
|
|
self.prompt = self.prompt_end
|
|
|
|
self.ruler = '-'
|
|
|
|
self.modules = OrderedDict()
|
|
|
|
self.add_module_info(ModuleInfo("help", desc = "Get help for bindctl"))
|
|
|
|
self.server_port = server_port
|
2010-03-16 00:21:30 +00:00
|
|
|
self.pem_file = pem_file
|
2010-02-25 08:20:48 +00:00
|
|
|
self._connect_to_cmd_ctrld()
|
2010-01-28 23:47:18 +00:00
|
|
|
self.session_id = self._get_session_id()
|
|
|
|
|
2010-02-25 08:20:48 +00:00
|
|
|
def _connect_to_cmd_ctrld(self):
|
|
|
|
'''Connect to cmdctl in SSL context. '''
|
2010-01-28 23:47:18 +00:00
|
|
|
try:
|
2010-03-16 00:21:30 +00:00
|
|
|
self.conn = http.client.HTTPSConnection(self.server_port,
|
|
|
|
cert_file=self.pem_file)
|
2010-01-28 23:47:18 +00:00
|
|
|
except Exception as e:
|
2010-02-25 08:20:48 +00:00
|
|
|
print(e, "can't connect to %s, please make sure cmd-ctrld is running" %
|
|
|
|
self.server_port)
|
2010-01-28 23:47:18 +00:00
|
|
|
|
|
|
|
def _get_session_id(self):
|
2010-02-25 08:20:48 +00:00
|
|
|
'''Generate one session id for the connection. '''
|
2010-01-28 23:47:18 +00:00
|
|
|
rand = os.urandom(16)
|
|
|
|
now = time.time()
|
|
|
|
ip = socket.gethostbyname(socket.gethostname())
|
|
|
|
session_id = sha1(("%s%s%s" %(rand, now, ip)).encode())
|
2010-02-25 08:20:48 +00:00
|
|
|
digest = session_id.hexdigest()
|
|
|
|
return digest
|
2010-01-28 23:47:18 +00:00
|
|
|
|
|
|
|
def run(self):
|
2010-02-25 08:20:48 +00:00
|
|
|
'''Parse commands inputted from user and send them to cmdctl. '''
|
2010-01-28 23:47:18 +00:00
|
|
|
try:
|
2010-02-25 08:20:48 +00:00
|
|
|
if not self.login_to_cmdctl():
|
2010-01-28 23:47:18 +00:00
|
|
|
return False
|
|
|
|
|
|
|
|
# Get all module information from cmd-ctrld
|
2010-02-16 20:12:52 +00:00
|
|
|
self.config_data = isc.config.UIModuleCCSession(self)
|
2010-02-25 08:20:48 +00:00
|
|
|
self._update_commands()
|
2010-01-28 23:47:18 +00:00
|
|
|
self.cmdloop()
|
|
|
|
except KeyboardInterrupt:
|
|
|
|
return True
|
|
|
|
|
2010-02-25 08:20:48 +00:00
|
|
|
def login_to_cmdctl(self):
|
|
|
|
'''Login to cmdctl with the username and password inputted
|
2010-03-16 10:06:27 +00:00
|
|
|
from user. After the login is sucessful, the username and
|
|
|
|
password will be saved in 'default_user.csv', when run the next
|
|
|
|
time, username and password saved in 'default_user.csv' will be
|
|
|
|
used first.
|
2010-02-25 08:20:48 +00:00
|
|
|
'''
|
2010-01-28 23:47:18 +00:00
|
|
|
csvfile = None
|
|
|
|
bsuccess = False
|
|
|
|
try:
|
2010-03-19 00:10:27 +00:00
|
|
|
cvsfilepath = ""
|
|
|
|
if ('HOME' in os.environ):
|
|
|
|
cvsfilepath = os.environ['HOME']
|
|
|
|
cvsfilepath += os.sep + '.bind10' + os.sep
|
|
|
|
cvsfilepath += 'default_user.csv'
|
|
|
|
csvfile = open(cvsfilepath)
|
2010-01-28 23:47:18 +00:00
|
|
|
users = csv.reader(csvfile)
|
|
|
|
for row in users:
|
|
|
|
param = {'username': row[0], 'password' : row[1]}
|
|
|
|
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
|
2010-01-30 01:37:43 +00:00
|
|
|
except IOError as e:
|
|
|
|
pass
|
2010-01-28 23:47:18 +00:00
|
|
|
except Exception as e:
|
|
|
|
print(e)
|
|
|
|
finally:
|
|
|
|
if csvfile:
|
|
|
|
csvfile.close()
|
|
|
|
if bsuccess:
|
|
|
|
return True
|
|
|
|
|
|
|
|
count = 0
|
|
|
|
print("[TEMP MESSAGE]: username :root password :bind10")
|
2010-02-25 08:20:48 +00:00
|
|
|
while True:
|
2010-01-28 23:47:18 +00:00
|
|
|
count = count + 1
|
2010-02-25 08:20:48 +00:00
|
|
|
if count > 3:
|
|
|
|
print("Too many authentication failures")
|
|
|
|
return False
|
|
|
|
|
2010-01-28 23:47:18 +00:00
|
|
|
username = input("Username:")
|
|
|
|
passwd = getpass.getpass()
|
|
|
|
param = {'username': username, 'password' : passwd}
|
|
|
|
response = self.send_POST('/login', param)
|
|
|
|
data = response.read().decode()
|
|
|
|
print(data)
|
|
|
|
|
|
|
|
if response.status == http.client.OK:
|
2010-03-19 00:10:27 +00:00
|
|
|
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)
|
2010-03-19 00:16:44 +00:00
|
|
|
else:
|
|
|
|
print("Cannot determine location of $HOME. Not storing default user")
|
|
|
|
return True
|
2010-03-19 00:10:27 +00:00
|
|
|
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)
|
2010-02-25 08:20:48 +00:00
|
|
|
return True
|
2010-01-28 23:47:18 +00:00
|
|
|
|
|
|
|
|
2010-02-25 08:20:48 +00:00
|
|
|
def _update_commands(self):
|
2010-03-16 10:06:27 +00:00
|
|
|
'''Get the commands of all modules. '''
|
2010-01-28 23:47:18 +00:00
|
|
|
cmd_spec = self.send_GET('/command_spec')
|
2010-02-25 08:20:48 +00:00
|
|
|
if not cmd_spec:
|
|
|
|
return
|
|
|
|
|
2010-01-28 23:47:18 +00:00
|
|
|
for module_name in cmd_spec.keys():
|
2010-02-25 08:20:48 +00:00
|
|
|
self._prepare_module_commands(module_name, cmd_spec[module_name])
|
2010-01-28 23:47:18 +00:00
|
|
|
|
|
|
|
def send_GET(self, url, body = None):
|
2010-02-25 08:20:48 +00:00
|
|
|
'''Send GET request to cmdctl, session id is send with the name
|
|
|
|
'cookie' in header.
|
|
|
|
'''
|
2010-01-28 23:47:18 +00:00
|
|
|
headers = {"cookie" : self.session_id}
|
|
|
|
self.conn.request('GET', url, body, headers)
|
|
|
|
res = self.conn.getresponse()
|
|
|
|
reply_msg = res.read()
|
|
|
|
if reply_msg:
|
|
|
|
return json.loads(reply_msg.decode())
|
|
|
|
else:
|
2010-02-25 08:20:48 +00:00
|
|
|
return {}
|
2010-01-28 23:47:18 +00:00
|
|
|
|
|
|
|
|
|
|
|
def send_POST(self, url, post_param = None):
|
2010-03-16 10:06:27 +00:00
|
|
|
'''Send POST request to cmdctl, session id is send with the name
|
2010-02-25 08:20:48 +00:00
|
|
|
'cookie' in header.
|
2010-01-28 23:47:18 +00:00
|
|
|
Format: /module_name/command_name
|
|
|
|
parameters of command is encoded as a map
|
|
|
|
'''
|
|
|
|
param = None
|
|
|
|
if (len(post_param) != 0):
|
|
|
|
param = json.dumps(post_param)
|
|
|
|
|
|
|
|
headers = {"cookie" : self.session_id}
|
|
|
|
self.conn.request('POST', url, param, headers)
|
|
|
|
return self.conn.getresponse()
|
|
|
|
|
|
|
|
|
|
|
|
def postcmd(self, stop, line):
|
2010-03-16 10:06:27 +00:00
|
|
|
'''Update the prompt after every command'''
|
2010-01-28 23:47:18 +00:00
|
|
|
self.prompt = self.location + self.prompt_end
|
|
|
|
return stop
|
|
|
|
|
2010-02-25 08:20:48 +00:00
|
|
|
def _prepare_module_commands(self, module_name, module_commands):
|
2010-03-16 10:06:27 +00:00
|
|
|
'''Prepare the module commands'''
|
2010-01-28 23:47:18 +00:00
|
|
|
module = ModuleInfo(name = module_name,
|
|
|
|
desc = "same here")
|
|
|
|
for command in module_commands:
|
|
|
|
cmd = CommandInfo(name = command["command_name"],
|
2010-02-25 08:20:48 +00:00
|
|
|
desc = command["command_description"])
|
2010-01-28 23:47:18 +00:00
|
|
|
for arg in command["command_args"]:
|
|
|
|
param = ParamInfo(name = arg["item_name"],
|
|
|
|
type = arg["item_type"],
|
|
|
|
optional = bool(arg["item_optional"]))
|
|
|
|
if ("item_default" in arg):
|
|
|
|
param.default = arg["item_default"]
|
|
|
|
cmd.add_param(param)
|
|
|
|
module.add_command(cmd)
|
|
|
|
self.add_module_info(module)
|
|
|
|
|
2010-02-25 08:20:48 +00:00
|
|
|
def _validate_cmd(self, cmd):
|
2010-02-26 08:52:21 +00:00
|
|
|
'''validate the parameters and merge some parameters together,
|
|
|
|
merge algorithm is based on the command line syntax, later, if
|
|
|
|
a better command line syntax come out, this function should be
|
|
|
|
updated first.
|
|
|
|
'''
|
2010-01-28 23:47:18 +00:00
|
|
|
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()
|
|
|
|
|
2010-03-16 10:06:27 +00:00
|
|
|
# If help is entered, don't do further parameter validation.
|
2010-01-28 23:47:18 +00:00
|
|
|
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:
|
|
|
|
param_name = None
|
|
|
|
param_count = len(params)
|
|
|
|
for name in params:
|
|
|
|
# either the name of the parameter must be known, or
|
|
|
|
# the 'name' must be an integer (ie. the position of
|
|
|
|
# an unnamed argument
|
|
|
|
if type(name) == int:
|
|
|
|
# lump all extraneous arguments together as one big final one
|
|
|
|
# todo: check if last param type is a string?
|
|
|
|
if (param_count > 2):
|
|
|
|
while (param_count > len(command_info.params) - 1):
|
|
|
|
params[param_count - 2] += params[param_count - 1]
|
|
|
|
del(params[param_count - 1])
|
|
|
|
param_count = len(params)
|
|
|
|
cmd.params = params.copy()
|
|
|
|
|
|
|
|
# (-1, help is always in the all_params list)
|
|
|
|
if name >= len(all_params) - 1:
|
|
|
|
# add to last known param
|
|
|
|
if param_name:
|
|
|
|
cmd.params[param_name] += cmd.params[name]
|
|
|
|
else:
|
|
|
|
raise CmdUnknownParamSyntaxError(cmd.module, cmd.command, cmd.params[name])
|
|
|
|
else:
|
|
|
|
# replace the numbered items by named items
|
2010-02-26 08:52:21 +00:00
|
|
|
param_name = command_info.get_param_name_by_position(name, param_count)
|
2010-01-28 23:47:18 +00:00
|
|
|
cmd.params[param_name] = cmd.params[name]
|
|
|
|
del cmd.params[name]
|
|
|
|
|
|
|
|
elif not name in all_params:
|
|
|
|
raise CmdUnknownParamSyntaxError(cmd.module, cmd.command, name)
|
2010-02-25 08:20:48 +00:00
|
|
|
|
2010-01-28 23:47:18 +00:00
|
|
|
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
|
|
|
|
|
|
|
|
def _handle_cmd(self, cmd):
|
2010-03-16 10:06:27 +00:00
|
|
|
'''Handle a command entered by the user'''
|
2010-01-28 23:47:18 +00:00
|
|
|
if cmd.command == "help" or ("help" in cmd.params.keys()):
|
|
|
|
self._handle_help(cmd)
|
|
|
|
elif cmd.module == "config":
|
|
|
|
self.apply_config_cmd(cmd)
|
|
|
|
else:
|
|
|
|
self.apply_cmd(cmd)
|
|
|
|
|
2010-03-16 10:06:27 +00:00
|
|
|
def add_module_info(self, module_info):
|
|
|
|
'''Add the information about one module'''
|
2010-01-28 23:47:18 +00:00
|
|
|
self.modules[module_info.name] = module_info
|
|
|
|
|
|
|
|
def get_module_names(self):
|
2010-03-16 10:06:27 +00:00
|
|
|
'''Return the names of all known modules'''
|
2010-01-28 23:47:18 +00:00
|
|
|
return list(self.modules.keys())
|
|
|
|
|
|
|
|
#override methods in cmd
|
|
|
|
def default(self, line):
|
|
|
|
self._parse_cmd(line)
|
|
|
|
|
|
|
|
def emptyline(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def do_help(self, name):
|
|
|
|
print(CONST_BINDCTL_HELP)
|
|
|
|
for k in self.modules.keys():
|
|
|
|
print("\t", self.modules[k])
|
|
|
|
|
|
|
|
|
|
|
|
def onecmd(self, line):
|
|
|
|
if line == 'EOF' or line.lower() == "quit":
|
|
|
|
self.conn.close()
|
|
|
|
return True
|
|
|
|
|
|
|
|
if line == 'h':
|
|
|
|
line = 'help'
|
|
|
|
|
|
|
|
Cmd.onecmd(self, line)
|
2010-03-16 13:30:23 +00:00
|
|
|
|
|
|
|
def remove_prefix(self, list, prefix):
|
|
|
|
return [(val[len(prefix):]) for val in list]
|
|
|
|
|
2010-01-28 23:47:18 +00:00
|
|
|
def complete(self, text, state):
|
|
|
|
if 0 == state:
|
|
|
|
text = text.strip()
|
|
|
|
hints = []
|
2010-03-16 10:32:51 +00:00
|
|
|
cur_line = my_readline()
|
2010-01-28 23:47:18 +00:00
|
|
|
try:
|
|
|
|
cmd = BindCmdParse(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)
|
|
|
|
if cmd.module == "config":
|
|
|
|
# grm text has been stripped of slashes...
|
|
|
|
my_text = self.location + "/" + cur_line.rpartition(" ")[2]
|
2010-03-16 13:30:23 +00:00
|
|
|
list = self.config_data.get_config_item_list(my_text.rpartition("/")[0], True)
|
|
|
|
hints.extend([val for val in list if val.startswith(my_text[1:])])
|
|
|
|
# remove the common prefix from the hints so we don't get it twice
|
|
|
|
hints = self.remove_prefix(hints, my_text.rpartition("/")[0])
|
2010-01-28 23:47:18 +00:00
|
|
|
except CmdModuleNameFormatError:
|
|
|
|
if not text:
|
|
|
|
hints = self.get_module_names()
|
|
|
|
|
|
|
|
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 BindCtlException:
|
|
|
|
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 = BindCmdParse(line)
|
2010-02-25 08:20:48 +00:00
|
|
|
self._validate_cmd(cmd)
|
2010-01-28 23:47:18 +00:00
|
|
|
self._handle_cmd(cmd)
|
|
|
|
except BindCtlException 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_config_cmd(self, cmd):
|
2010-03-16 10:06:27 +00:00
|
|
|
'''Handles a configuration command.
|
|
|
|
Raises a DataTypeError if a wrong value is set.
|
|
|
|
Raises a DataNotFoundError if a wrong identifier is used.
|
|
|
|
Raises a KeyError if the command was not complete
|
|
|
|
'''
|
2010-01-28 23:47:18 +00:00
|
|
|
identifier = self.location
|
|
|
|
try:
|
|
|
|
if 'identifier' in cmd.params:
|
|
|
|
if not identifier.endswith("/"):
|
|
|
|
identifier += "/"
|
|
|
|
if cmd.params['identifier'].startswith("/"):
|
|
|
|
identifier = cmd.params['identifier']
|
|
|
|
else:
|
|
|
|
identifier += cmd.params['identifier']
|
|
|
|
if cmd.command == "show":
|
|
|
|
values = self.config_data.get_value_maps(identifier)
|
|
|
|
for value_map in values:
|
|
|
|
line = value_map['name']
|
|
|
|
if value_map['type'] in [ 'module', 'map', 'list' ]:
|
|
|
|
line += "/"
|
|
|
|
else:
|
|
|
|
line += ":\t" + str(value_map['value'])
|
|
|
|
line += "\t" + value_map['type']
|
|
|
|
line += "\t"
|
|
|
|
if value_map['default']:
|
|
|
|
line += "(default)"
|
|
|
|
if value_map['modified']:
|
|
|
|
line += "(modified)"
|
|
|
|
print(line)
|
|
|
|
elif cmd.command == "add":
|
2010-02-13 22:07:58 +00:00
|
|
|
self.config_data.add_value(identifier, cmd.params['value'])
|
2010-01-28 23:47:18 +00:00
|
|
|
elif cmd.command == "remove":
|
2010-02-13 22:07:58 +00:00
|
|
|
self.config_data.remove_value(identifier, cmd.params['value'])
|
2010-01-28 23:47:18 +00:00
|
|
|
elif cmd.command == "set":
|
2010-02-16 09:50:03 +00:00
|
|
|
if 'identifier' not in cmd.params:
|
|
|
|
print("Error: missing identifier or value")
|
|
|
|
else:
|
|
|
|
parsed_value = None
|
|
|
|
try:
|
|
|
|
parsed_value = ast.literal_eval(cmd.params['value'])
|
|
|
|
except Exception as exc:
|
|
|
|
# ok could be an unquoted string, interpret as such
|
|
|
|
parsed_value = cmd.params['value']
|
|
|
|
self.config_data.set_value(identifier, parsed_value)
|
2010-01-28 23:47:18 +00:00
|
|
|
elif cmd.command == "unset":
|
|
|
|
self.config_data.unset(identifier)
|
|
|
|
elif cmd.command == "revert":
|
2010-03-12 13:50:47 +00:00
|
|
|
self.config_data.clear_local_changes()
|
2010-01-28 23:47:18 +00:00
|
|
|
elif cmd.command == "commit":
|
2010-02-13 22:07:58 +00:00
|
|
|
self.config_data.commit()
|
2010-02-15 13:30:39 +00:00
|
|
|
elif cmd.command == "diff":
|
|
|
|
print(self.config_data.get_local_changes());
|
2010-01-28 23:47:18 +00:00
|
|
|
elif cmd.command == "go":
|
|
|
|
self.go(identifier)
|
2010-02-01 10:48:19 +00:00
|
|
|
except isc.cc.data.DataTypeError as dte:
|
2010-01-28 23:47:18 +00:00
|
|
|
print("Error: " + str(dte))
|
2010-02-01 10:48:19 +00:00
|
|
|
except isc.cc.data.DataNotFoundError as dnfe:
|
2010-01-28 23:47:18 +00:00
|
|
|
print("Error: " + identifier + " not found")
|
|
|
|
except KeyError as ke:
|
|
|
|
print("Error: missing " + str(ke))
|
|
|
|
raise ke
|
|
|
|
|
|
|
|
def go(self, identifier):
|
2010-03-16 10:06:27 +00:00
|
|
|
'''Handles the config go command, change the 'current' location
|
|
|
|
within the configuration tree'''
|
|
|
|
# this is just to see if it exists
|
2010-01-28 23:47:18 +00:00
|
|
|
self.config_data.get_value(identifier)
|
|
|
|
# some sanitizing
|
|
|
|
identifier = identifier.replace("//", "/")
|
|
|
|
if not identifier.startswith("/"):
|
|
|
|
identifier = "/" + identifier
|
|
|
|
if identifier.endswith("/"):
|
|
|
|
identifier = identifier[:-1]
|
|
|
|
self.location = identifier
|
|
|
|
|
|
|
|
def apply_cmd(self, cmd):
|
2010-03-16 10:06:27 +00:00
|
|
|
'''Handles a general module command'''
|
2010-01-28 23:47:18 +00:00
|
|
|
url = '/' + cmd.module + '/' + cmd.command
|
|
|
|
cmd_params = None
|
|
|
|
if (len(cmd.params) != 0):
|
|
|
|
cmd_params = json.dumps(cmd.params)
|
|
|
|
|
|
|
|
print("send the message to cmd-ctrld")
|
|
|
|
reply = self.send_POST(url, cmd.params)
|
|
|
|
data = reply.read().decode()
|
|
|
|
print("received reply:", data)
|
|
|
|
|
|
|
|
|