Commit 633e231b authored by Jelte Jansen's avatar Jelte Jansen

merge back branches/jelte-configuration (branched at rev. 745, up to HEAD)


git-svn-id: svn://bind10.isc.org/svn/bind10/trunk@882 e5f2f494-b856-4b98-b285-d166d9295462
parents da9c7b09 33f2f0f5
{ {
"data_specification": { "module_spec": {
"module_name": "Auth" "module_name": "Auth",
"config_data": [
{ "item_name": "default_name",
"item_type": "string",
"item_optional": False,
"item_default": "Hello, world!"
},
{ "item_name": "zone_list",
"item_type": "list",
"item_optional": False,
"item_default": [],
"list_item_spec":
{ "item_name": "zone_name",
"item_type": "string",
"item_optional": True,
"item_default": ""
}
}
],
"commands": [
{
"command_name": "print_message",
"command_description": "Print the given message to stdout",
"command_args": [ {
"item_name": "message",
"item_type": "string",
"item_optional": False,
"item_default": ""
} ]
},
{
"command_name": "shutdown",
"command_description": "Shut down BIND 10",
"command_args": []
}
]
} }
} }
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <dns/rrset.h> #include <dns/rrset.h>
#include <dns/rrttl.h> #include <dns/rrttl.h>
#include <dns/message.h> #include <dns/message.h>
#include <config/ccsession.h>
#include <cc/data.h> #include <cc/data.h>
...@@ -46,6 +47,7 @@ using namespace std; ...@@ -46,6 +47,7 @@ using namespace std;
using namespace isc::dns; using namespace isc::dns;
using namespace isc::dns::rdata; using namespace isc::dns::rdata;
using namespace isc::data; using namespace isc::data;
using namespace isc::config;
AuthSrv::AuthSrv(int port) { AuthSrv::AuthSrv(int port) {
int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
...@@ -120,5 +122,7 @@ AuthSrv::updateConfig(isc::data::ElementPtr config) { ...@@ -120,5 +122,7 @@ AuthSrv::updateConfig(isc::data::ElementPtr config) {
// todo: what to do with port change. restart automatically? // todo: what to do with port change. restart automatically?
// ignore atm // ignore atm
//} //}
return isc::data::Element::createFromString("{ \"result\": [0] }"); std::cout << "[XX] auth: new config " << config << std::endl;
return isc::config::createAnswer(0);
} }
...@@ -64,18 +64,15 @@ my_config_handler(isc::data::ElementPtr config) ...@@ -64,18 +64,15 @@ my_config_handler(isc::data::ElementPtr config)
isc::data::ElementPtr isc::data::ElementPtr
my_command_handler(isc::data::ElementPtr command) { my_command_handler(isc::data::ElementPtr command) {
isc::data::ElementPtr answer = isc::data::Element::createFromString("{ \"result\": [0] }"); isc::data::ElementPtr answer = isc::config::createAnswer(0);
cout << "[XX] Handle command: " << endl << command->str() << endl; cout << "[XX] Handle command: " << endl << command->str() << endl;
if (command->get(0)->stringValue() == "print_message") if (command->get(0)->stringValue() == "print_message")
{ {
cout << command->get(1)->get("message") << endl; cout << command->get(1)->get("message") << endl;
/* let's add that message to our answer as well */ /* let's add that message to our answer as well */
cout << "[XX] answer was: " << answer->str() << endl;
answer->get("result")->add(command->get(1)); answer->get("result")->add(command->get(1));
cout << "[XX] answer now: " << answer->str() << endl;
} }
return answer; return answer;
} }
...@@ -106,9 +103,9 @@ main(int argc, char* argv[]) { ...@@ -106,9 +103,9 @@ main(int argc, char* argv[]) {
} else { } else {
specfile = std::string(AUTH_SPECFILE_LOCATION); specfile = std::string(AUTH_SPECFILE_LOCATION);
} }
CommandSession cs = CommandSession(specfile, isc::config::ModuleCCSession cs = isc::config::ModuleCCSession(specfile,
my_config_handler, my_config_handler,
my_command_handler); my_command_handler);
// main server loop // main server loop
fd_set fds; fd_set fds;
......
...@@ -106,6 +106,7 @@ class BoB: ...@@ -106,6 +106,7 @@ class BoB:
self.verbose = verbose self.verbose = verbose
self.c_channel_port = c_channel_port self.c_channel_port = c_channel_port
self.cc_session = None self.cc_session = None
self.ccs = None
self.processes = {} self.processes = {}
self.dead_processes = {} self.dead_processes = {}
self.runnable = False self.runnable = False
...@@ -114,6 +115,8 @@ class BoB: ...@@ -114,6 +115,8 @@ class BoB:
if self.verbose: if self.verbose:
print("[XX] handling new config:") print("[XX] handling new config:")
print(new_config) print(new_config)
answer = isc.config.ccsession.create_answer(0)
return answer
# TODO # TODO
def command_handler(self, command): def command_handler(self, command):
...@@ -121,21 +124,27 @@ class BoB: ...@@ -121,21 +124,27 @@ class BoB:
if self.verbose: if self.verbose:
print("[XX] Boss got command:") print("[XX] Boss got command:")
print(command) print(command)
answer = None answer = [ 1, "Command not implemented" ]
if type(command) != list or len(command) == 0: if type(command) != list or len(command) == 0:
answer = { "result": [ 1, "bad command" ] } answer = isc.config.ccsession.create_answer(1, "bad command")
else: else:
cmd = command[0] cmd = command[0]
if cmd == "shutdown": if cmd == "shutdown":
print("[XX] got shutdown command") print("[XX] got shutdown command")
self.runnable = False self.runnable = False
answer = { "result": [ 0 ] } answer = isc.config.ccsession.create_answer(0)
elif cmd == "print_message": elif cmd == "print_message":
if len(command) > 1 and type(command[1]) == dict and "message" in command[1]: if len(command) > 1 and type(command[1]) == dict and "message" in command[1]:
print(command[1]["message"]) print(command[1]["message"])
answer = { "result": [ 0 ] } answer = isc.config.ccsession.create_answer(0)
elif cmd == "print_settings":
print("Full Config:")
full_config = self.ccs.get_full_config()
for item in full_config:
print(item + ": " + str(full_config[item]))
answer = isc.config.ccsession.create_answer(0)
else: else:
answer = { "result": [ 1, "Unknown command" ] } answer = isc.config.ccsession.create_answer(1, "Unknown command")
return answer return answer
def startup(self): def startup(self):
...@@ -190,7 +199,8 @@ class BoB: ...@@ -190,7 +199,8 @@ class BoB:
time.sleep(1) time.sleep(1)
if self.verbose: if self.verbose:
print("[XX] starting ccsession") print("[XX] starting ccsession")
self.ccs = isc.config.CCSession(SPECFILE_LOCATION, self.config_handler, self.command_handler) self.ccs = isc.config.ModuleCCSession(SPECFILE_LOCATION, self.config_handler, self.command_handler)
self.ccs.start()
if self.verbose: if self.verbose:
print("[XX] ccsession started") print("[XX] ccsession started")
...@@ -478,7 +488,7 @@ def main(): ...@@ -478,7 +488,7 @@ def main():
for fd in rlist + xlist: for fd in rlist + xlist:
if fd == ccs_fd: if fd == ccs_fd:
boss_of_bind.ccs.checkCommand() boss_of_bind.ccs.check_command()
elif fd == wakeup_fd: elif fd == wakeup_fd:
os.read(wakeup_fd, 32) os.read(wakeup_fd, 32)
......
{ {
"data_specification": { "module_spec": {
"module_name": "Boss", "module_name": "Boss",
"config_data": [ "config_data": [
{ {
...@@ -7,6 +7,12 @@ ...@@ -7,6 +7,12 @@
"item_type": "string", "item_type": "string",
"item_optional": False, "item_optional": False,
"item_default": "Hi, shane!" "item_default": "Hi, shane!"
},
{
"item_name": "some_int",
"item_type": "integer",
"item_optional": False,
"item_default": 1
} }
], ],
"commands": [ "commands": [
...@@ -20,6 +26,11 @@ ...@@ -20,6 +26,11 @@
"item_default": "" "item_default": ""
} ] } ]
}, },
{
"command_name": "print_settings",
"command_description": "Print some_string and some_int to stdout",
"command_args": []
},
{ {
"command_name": "shutdown", "command_name": "shutdown",
"command_description": "Shut down BIND 10", "command_description": "Shut down BIND 10",
......
...@@ -31,6 +31,7 @@ import os, time, random, re ...@@ -31,6 +31,7 @@ import os, time, random, re
import getpass import getpass
from hashlib import sha1 from hashlib import sha1
import csv import csv
import ast
try: try:
from collections import OrderedDict from collections import OrderedDict
...@@ -85,7 +86,7 @@ class BindCmdInterpreter(Cmd): ...@@ -85,7 +86,7 @@ class BindCmdInterpreter(Cmd):
return False return False
# Get all module information from cmd-ctrld # Get all module information from cmd-ctrld
self.config_data = isc.cc.data.UIConfigData(self) self.config_data = isc.config.UIModuleCCSession(self)
self.update_commands() self.update_commands()
self.cmdloop() self.cmdloop()
except KeyboardInterrupt: except KeyboardInterrupt:
...@@ -150,7 +151,8 @@ class BindCmdInterpreter(Cmd): ...@@ -150,7 +151,8 @@ class BindCmdInterpreter(Cmd):
if (len(cmd_spec) == 0): if (len(cmd_spec) == 0):
print('can\'t get any command specification') print('can\'t get any command specification')
for module_name in cmd_spec.keys(): for module_name in cmd_spec.keys():
self.prepare_module_commands(module_name, cmd_spec[module_name]) if cmd_spec[module_name]:
self.prepare_module_commands(module_name, cmd_spec[module_name])
def send_GET(self, url, body = None): def send_GET(self, url, body = None):
headers = {"cookie" : self.session_id} headers = {"cookie" : self.session_id}
...@@ -315,7 +317,7 @@ class BindCmdInterpreter(Cmd): ...@@ -315,7 +317,7 @@ class BindCmdInterpreter(Cmd):
if cmd.module == "config": if cmd.module == "config":
# grm text has been stripped of slashes... # grm text has been stripped of slashes...
my_text = self.location + "/" + cur_line.rpartition(" ")[2] my_text = self.location + "/" + cur_line.rpartition(" ")[2]
list = self.config_data.config.get_item_list(my_text.rpartition("/")[0]) list = self.config_data.get_config_item_list(my_text.rpartition("/")[0])
hints.extend([val for val in list if val.startswith(text)]) hints.extend([val for val in list if val.startswith(text)])
except CmdModuleNameFormatError: except CmdModuleNameFormatError:
if not text: if not text:
...@@ -440,17 +442,28 @@ class BindCmdInterpreter(Cmd): ...@@ -440,17 +442,28 @@ class BindCmdInterpreter(Cmd):
line += "(modified)" line += "(modified)"
print(line) print(line)
elif cmd.command == "add": elif cmd.command == "add":
self.config_data.add(identifier, cmd.params['value']) self.config_data.add_value(identifier, cmd.params['value'])
elif cmd.command == "remove": elif cmd.command == "remove":
self.config_data.remove(identifier, cmd.params['value']) self.config_data.remove_value(identifier, cmd.params['value'])
elif cmd.command == "set": elif cmd.command == "set":
self.config_data.set(identifier, cmd.params['value']) 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)
elif cmd.command == "unset": elif cmd.command == "unset":
self.config_data.unset(identifier) self.config_data.unset(identifier)
elif cmd.command == "revert": elif cmd.command == "revert":
self.config_data.revert() self.config_data.revert()
elif cmd.command == "commit": elif cmd.command == "commit":
self.config_data.commit(self) self.config_data.commit()
elif cmd.command == "diff":
print(self.config_data.get_local_changes());
elif cmd.command == "go": elif cmd.command == "go":
self.go(identifier) self.go(identifier)
except isc.cc.data.DataTypeError as dte: except isc.cc.data.DataTypeError as dte:
......
...@@ -5,7 +5,7 @@ export PYTHON_EXEC ...@@ -5,7 +5,7 @@ export PYTHON_EXEC
BINDCTL_PATH=@abs_top_srcdir@/src/bin/bindctl BINDCTL_PATH=@abs_top_srcdir@/src/bin/bindctl
PYTHONPATH=@abs_top_srcdir@/src/lib/cc/python PYTHONPATH=@abs_top_builddir@/pyshared
export PYTHONPATH export PYTHONPATH
cd ${BINDCTL_PATH} cd ${BINDCTL_PATH}
......
...@@ -53,6 +53,9 @@ def prepare_config_commands(tool): ...@@ -53,6 +53,9 @@ def prepare_config_commands(tool):
cmd.add_param(param) cmd.add_param(param)
module.add_command(cmd) module.add_command(cmd)
cmd = CommandInfo(name = "diff", desc = "Show all local changes", need_inst_param = False)
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", need_inst_param = False)
module.add_command(cmd) module.add_command(cmd)
...@@ -67,12 +70,17 @@ def prepare_config_commands(tool): ...@@ -67,12 +70,17 @@ def prepare_config_commands(tool):
tool.add_module_info(module) tool.add_module_info(module)
if __name__ == '__main__': if __name__ == '__main__':
try: tool = BindCmdInterpreter("localhost:8080")
tool = BindCmdInterpreter("localhost:8080") prepare_config_commands(tool)
prepare_config_commands(tool) tool.run()
tool.run() # TODO: put below back, was removed to see errors
except Exception as e: #if __name__ == '__main__':
print(e) #try:
print("Failed to connect with b10-cmdctl module, is it running?") #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?")
...@@ -169,8 +169,8 @@ class SecureHTTPRequestHandler(http.server.BaseHTTPRequestHandler): ...@@ -169,8 +169,8 @@ class SecureHTTPRequestHandler(http.server.BaseHTTPRequestHandler):
param = json.loads(post_str) param = json.loads(post_str)
# TODO, need return some proper return code. # TODO, need return some proper return code.
# currently always OK. # currently always OK.
reply = self.server.send_command_to_module(mod, cmd, param) reply = self.server.send_command_to_module(mod, cmd, param)
print('b10-cmdctl finish send message \'%s\' to module %s' % (cmd, mod)) print('b10-cmdctl finish send message \'%s\' to module %s' % (cmd, mod))
return rcode, reply return rcode, reply
...@@ -189,7 +189,7 @@ class CommandControl(): ...@@ -189,7 +189,7 @@ class CommandControl():
self.config_data = self.get_config_data() self.config_data = self.get_config_data()
def get_cmd_specification(self): def get_cmd_specification(self):
return self.send_command('ConfigManager', 'get_commands') return self.send_command('ConfigManager', 'get_commands_spec')
def get_config_data(self): def get_config_data(self):
return self.send_command('ConfigManager', 'get_config') return self.send_command('ConfigManager', 'get_config')
...@@ -199,7 +199,7 @@ class CommandControl(): ...@@ -199,7 +199,7 @@ class CommandControl():
self.config_data = self.get_config_data() self.config_data = self.get_config_data()
def get_data_specification(self): def get_data_specification(self):
return self.send_command('ConfigManager', 'get_data_spec') return self.send_command('ConfigManager', 'get_module_spec')
def handle_recv_msg(self): def handle_recv_msg(self):
# Handle received message, if 'shutdown' is received, return False # Handle received message, if 'shutdown' is received, return False
......
...@@ -829,13 +829,19 @@ ListElement::toWire(std::stringstream& ss, int omit_length) ...@@ -829,13 +829,19 @@ ListElement::toWire(std::stringstream& ss, int omit_length)
(*it)->toWire(ss2, 0); (*it)->toWire(ss2, 0);
} }
if (omit_length) { if (omit_length) {
ss << ss2.rdbuf(); stringbuf *ss2_buf = ss2.rdbuf();
if (ss2_buf->in_avail() > 0) {
ss << ss2_buf;
}
} else { } else {
stringbuf *ss2_buf = ss2.rdbuf(); stringbuf *ss2_buf = ss2.rdbuf();
ss2_buf->pubseekpos(0); ss2_buf->pubseekpos(0);
ss << encode_length(ss2_buf->in_avail(), ITEM_LIST); ss << encode_length(ss2_buf->in_avail(), ITEM_LIST);
ss << ss2_buf; if (ss2_buf->in_avail() > 0) {
ss << ss2_buf;
}
} }
} }
...@@ -873,13 +879,17 @@ MapElement::toWire(std::stringstream& ss, int omit_length) ...@@ -873,13 +879,17 @@ MapElement::toWire(std::stringstream& ss, int omit_length)
// add length if needed // add length if needed
// //
if (omit_length) { if (omit_length) {
ss << ss2.rdbuf(); stringbuf *ss2_buf = ss2.rdbuf();
if (ss2_buf->in_avail() > 0) {
ss << ss2_buf;
}
} else { } else {
stringbuf *ss2_buf = ss2.rdbuf(); stringbuf *ss2_buf = ss2.rdbuf();
ss2_buf->pubseekpos(0); ss2_buf->pubseekpos(0);
ss << encode_length(ss2_buf->in_avail(), ITEM_HASH); ss << encode_length(ss2_buf->in_avail(), ITEM_HASH);
ss << ss2_buf; if (ss2_buf->in_avail() > 0) {
ss << ss2_buf;
}
} }
} }
......
...@@ -35,7 +35,6 @@ typedef boost::shared_ptr<Element> ElementPtr; ...@@ -35,7 +35,6 @@ typedef boost::shared_ptr<Element> ElementPtr;
/// is called for an Element that has a wrong type (e.g. int_value on a /// is called for an Element that has a wrong type (e.g. int_value on a
/// ListElement) /// ListElement)
/// ///
// todo: include types and called function in the exception
class TypeError : public isc::Exception { class TypeError : public isc::Exception {
public: public:
TypeError(const char* file, size_t line, const char* what) : TypeError(const char* file, size_t line, const char* what) :
......
...@@ -266,5 +266,13 @@ TEST(Element, to_and_from_wire) { ...@@ -266,5 +266,13 @@ TEST(Element, to_and_from_wire) {
//EXPECT_EQ("\047\0031.2", Element::create(1.2)->toWire(0)); //EXPECT_EQ("\047\0031.2", Element::create(1.2)->toWire(0));
EXPECT_EQ("\046\0011", Element::createFromString("[ 1 ]")->toWire(1)); EXPECT_EQ("\046\0011", Element::createFromString("[ 1 ]")->toWire(1));
std::string ddef = "{\"data_specification\": {\"config_data\": [ {\"item_default\": \"Hello, world!\", \"item_name\": \"default_name\", \"item_optional\": False, \"item_type\": \"string\"}, {\"item_default\": [ ], \"item_name\": \"zone_list\", \"item_optional\": False, \"item_type\": \"list\", \"list_item_spec\": {\"item_name\": \"zone_name\", \"item_optional\": True, \"item_type\": \"string\"}} ], \"module_name\": \"Auth\"}}";
//std::string ddef = "{\"aaa\": 123, \"test\": [ ], \"zzz\": 123}";
ElementPtr ddef_el = Element::createFromString(ddef);
std::string ddef_wire = ddef_el->toWire();
ElementPtr ddef_el2 = Element::fromWire(ddef_wire);
std::string ddef2 = ddef_el2->str();
EXPECT_EQ(ddef, ddef2);
} }
# data, data_definition, config_data, module_config_data and ui_config_data classes # Copyright (C) 2010 Internet Systems Consortium.
# we might want to split these up :) #
# 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.
#
# Helper functions for data elements as used in cc-channel and
# configuration. There is no python equivalent for the cpp Element
# class, since data elements are represented by native python types
# (int, real, bool, string, list and dict respectively)
#
import ast import ast
class DataNotFoundError(Exception): pass class DataNotFoundError(Exception): pass
...@@ -9,6 +29,8 @@ def merge(orig, new): ...@@ -9,6 +29,8 @@ def merge(orig, new):
"""Merges the contents of new into orig, think recursive update() """Merges the contents of new into orig, think recursive update()
orig and new must both be dicts. If an element value is None in orig and new must both be dicts. If an element value is None in
new it will be removed in orig.""" new it will be removed in orig."""
if type(orig) != dict or type(new) != dict:
raise DataTypeError("Not a dict in merge()")
for kn in new.keys(): for kn in new.keys():
if kn in orig: if kn in orig:
if new[kn]: if new[kn]:
...@@ -23,6 +45,10 @@ def merge(orig, new): ...@@ -23,6 +45,10 @@ def merge(orig, new):
def find(element, identifier): def find(element, identifier):
"""Returns the subelement in the given data element, raises DataNotFoundError if not found""" """Returns the subelement in the given data element, raises DataNotFoundError if not found"""
if type(identifier) != str or (type(element) != dict and identifier != ""):
raise DataTypeError("identifier in merge() is not a string")
if type(identifier) != str or (type(element) != dict and identifier != ""):
raise DataTypeError("element in merge() is not a dict")
id_parts = identifier.split("/") id_parts = identifier.split("/")
id_parts[:] = (value for value in id_parts if value != "") id_parts[:] = (value for value in id_parts if value != "")
cur_el = element cur_el = element
...@@ -34,6 +60,17 @@ def find(element, identifier): ...@@ -34,6 +60,17 @@ def find(element, identifier):
return cur_el return cur_el
def set(element, identifier, value): def set(element, identifier, value):
"""Sets the value at the element specified by identifier to value.