Commit 4b1e0bab authored by Jelte Jansen's avatar Jelte Jansen
Browse files

made config-specific commands also of the form of 'normal' commands, so they...

made config-specific commands also of the form of 'normal' commands, so they can be made with the same functions
updated cfgmgr to use these functions


git-svn-id: svn://bind10.isc.org/svn/bind10/trunk@963 e5f2f494-b856-4b98-b285-d166d9295462
parent 896f1b7a
......@@ -103,6 +103,42 @@ parseAnswer(int &rcode, const ElementPtr msg)
}
}
ElementPtr
createCommand(const std::string& command, ElementPtr arg)
{
ElementPtr cmd = Element::createFromString("{}");
ElementPtr cmd_parts = Element::createFromString("[]");
cmd_parts->add(Element::create(command));
if (arg) {
cmd_parts->add(arg);
}
cmd->set("command", cmd_parts);
return cmd;
}
/// Returns "" and empty ElementPtr() if this does not
/// look like a command
const std::string
parseCommand(ElementPtr& arg, const ElementPtr command)
{
if (command->getType() == Element::map &&
command->contains("command")) {
ElementPtr cmd = command->get("command");
if (cmd->getType() == Element::list &&
cmd->size() > 0 &&
cmd->get(0)->getType() == Element::string) {
if (cmd->size() > 1) {
arg = cmd->get(1);
} else {
arg = ElementPtr();
}
return cmd->get(0)->stringValue();
}
}
arg = ElementPtr();
return "";
}
void
ModuleCCSession::read_module_specification(const std::string& filename) {
std::ifstream file;
......@@ -150,8 +186,7 @@ ModuleCCSession::ModuleCCSession(std::string spec_file_name,
//session_.subscribe("Boss", "*");
//session_.subscribe("statistics", "*");
// send the data specification
ElementPtr spec_msg = Element::createFromString("{}");
spec_msg->set("module_spec", module_specification_.getFullSpec());
ElementPtr spec_msg = createCommand("module_spec", module_specification_.getFullSpec());
session_.group_sendmsg(spec_msg, "ConfigManager");
session_.group_recvmsg(env, answer, false);
......@@ -160,7 +195,6 @@ ModuleCCSession::ModuleCCSession(std::string spec_file_name,
ElementPtr cmd = Element::createFromString("{ \"command\": [\"get_config\", {\"module_name\":\"" + module_name_ + "\"} ] }");
session_.group_sendmsg(cmd, "ConfigManager");
session_.group_recvmsg(env, answer, false);
cout << "[XX] got config: " << endl << answer->str() << endl;
int rcode;
ElementPtr new_config = parseAnswer(rcode, answer);
handleConfigUpdate(new_config);
......@@ -208,7 +242,6 @@ ModuleCCSession::getSocket()
int
ModuleCCSession::check_command()
{
cout << "[XX] check for command" << endl;
ElementPtr cmd, routing, data;
if (session_.group_recvmsg(routing, data, true)) {
/* ignore result messages (in case we're out of sync, to prevent
......@@ -216,7 +249,6 @@ ModuleCCSession::check_command()
if (!data->getType() == Element::map || data->contains("result")) {
return 0;
}
cout << "[XX] got something!" << endl << data->str() << endl;
ElementPtr answer;
if (data->contains("config_update")) {
ElementPtr new_config = data->get("config_update");
......
......@@ -83,6 +83,7 @@ COMMAND_GET_COMMANDS_SPEC = "get_commands_spec"
COMMAND_GET_CONFIG = "get_config"
COMMAND_SET_CONFIG = "set_config"
COMMAND_GET_MODULE_SPEC = "get_module_spec"
COMMAND_MODULE_SPEC = "module_spec"
def parse_command(msg):
"""Parses what may be a command message. If it looks like one,
......@@ -90,8 +91,11 @@ def parse_command(msg):
string. If it is not, this function returns None, None"""
if type(msg) == dict and len(msg.items()) == 1:
cmd, value = msg.popitem()
if type(cmd) == str:
return cmd, value
if cmd == "command" and type(value) == list:
if len(value) == 1:
return value[0], None
elif len(value) > 1:
return value[0], value[1]
return None, None
def create_command(command_name, params = None):
......@@ -197,7 +201,8 @@ class ModuleCCSession(ConfigData):
def __send_spec(self):
"""Sends the data specification to the configuration manager"""
self._session.group_sendmsg({ "module_spec": self.get_module_spec().get_full_spec() }, "ConfigManager")
msg = create_command(COMMAND_MODULE_SPEC, self.get_module_spec().get_full_spec())
self._session.group_sendmsg(msg, "ConfigManager")
answer, env = self._session.group_recvmsg(False)
def __request_config(self):
......@@ -289,7 +294,7 @@ class UIModuleCCSession(MultiConfigData):
"""Commit all local changes, send them through b10-cmdctl to
the configuration manager"""
if self.get_local_changes():
self._conn.send_POST('/ConfigManager/set_config', self.get_local_changes())
self._conn.send_POST('/ConfigManager/set_config', [ self.get_local_changes() ])
# todo: check result
self.request_current_config()
self.clear_local_changes()
......@@ -189,10 +189,10 @@ class ConfigManager:
def _handle_get_module_spec(self, cmd):
"""Private function that handles the 'get_module_spec' command"""
answer = {}
if len(cmd) > 1:
if type(cmd[1]) == dict:
if 'module_name' in cmd[1] and cmd[1]['module_name'] != '':
module_name = cmd[1]['module_name']
if cmd != None:
if type(cmd) == dict:
if 'module_name' in cmd and cmd['module_name'] != '':
module_name = cmd['module_name']
answer = isc.config.ccsession.create_answer(0, self.get_config_spec(module_name))
else:
answer = isc.config.ccsession.create_answer(1, "Bad module_name in get_module_spec command")
......@@ -205,10 +205,10 @@ class ConfigManager:
def _handle_get_config(self, cmd):
"""Private function that handles the 'get_config' command"""
answer = {}
if len(cmd) > 1:
if type(cmd[1]) == dict:
if 'module_name' in cmd[1] and cmd[1]['module_name'] != '':
module_name = cmd[1]['module_name']
if cmd != None:
if type(cmd) == dict:
if 'module_name' in cmd and cmd['module_name'] != '':
module_name = cmd['module_name']
try:
answer = isc.config.ccsession.create_answer(0, data.find(self.config.data, module_name))
except data.DataNotFoundError as dnfe:
......@@ -226,19 +226,19 @@ class ConfigManager:
def _handle_set_config(self, cmd):
"""Private function that handles the 'set_config' command"""
answer = None
if len(cmd) == 3:
if cmd == None:
return isc.config.ccsession.create_answer(1, "Wrong number of arguments")
if len(cmd) == 2:
# todo: use api (and check the data against the definition?)
module_name = cmd[1]
module_name = cmd[0]
conf_part = data.find_no_exc(self.config.data, module_name)
print("[XX] cfgmgr conf part:")
print(conf_part)
if conf_part:
data.merge(conf_part, cmd[2])
data.merge(conf_part, cmd[1])
self.cc.group_sendmsg({ "config_update": conf_part }, module_name)
answer, env = self.cc.group_recvmsg(False)
else:
conf_part = data.set(self.config.data, module_name, {})
data.merge(conf_part[module_name], cmd[2])
data.merge(conf_part[module_name], cmd[1])
# send out changed info
self.cc.group_sendmsg({ "config_update": conf_part[module_name] }, module_name)
# replace 'our' answer with that of the module
......@@ -246,10 +246,10 @@ class ConfigManager:
rcode, val = isc.config.ccsession.parse_answer(answer)
if rcode == 0:
self.write_config()
elif len(cmd) == 2:
elif len(cmd) == 1:
# todo: use api (and check the data against the definition?)
old_data = self.config.data.copy()
data.merge(self.config.data, cmd[1])
data.merge(self.config.data, cmd[0])
# send out changed info
got_error = False
err_list = []
......@@ -269,6 +269,7 @@ class ConfigManager:
self.config.data = old_data
answer = isc.config.ccsession.create_answer(1, " ".join(err_list))
else:
print(cmd)
answer = isc.config.ccsession.create_answer(1, "Wrong number of arguments")
if not answer:
answer = isc.config.ccsession.create_answer(1, "Error handling set_config command")
......@@ -285,42 +286,42 @@ class ConfigManager:
# We should make one general 'spec update for module' that
# passes both specification and commands at once
self.cc.group_sendmsg({ "specification_update": [ spec.get_module_name(), spec.get_config_spec() ] }, "Cmd-Ctrld")
self.cc.group_sendmsg({ "commands_update": [ spec.get_module_name(), spec.get_commands_spec() ] }, "Cmd-Ctrld")
spec_update = isc.config.ccsession.create_command(isc.config.ccsession.COMMAND_SPECIFICATION_UPDATE,
[ spec.get_module_name(), spec.get_config_spec() ])
self.cc.group_sendmsg(spec_update, "Cmd-Ctrld")
cmds_update = isc.config.ccsession.create_command(isc.config.ccsession.COMMAND_COMMANDS_UPDATE,
[ spec.get_module_name(), spec.get_commands_spec() ])
self.cc.group_sendmsg(cmds_update, "Cmd-Ctrld")
answer = isc.config.ccsession.create_answer(0)
return answer
def handle_msg(self, msg):
"""Handle a command from the cc channel to the configuration manager"""
answer = {}
if "command" in msg:
cmd = msg["command"]
try:
if cmd[0] == "get_commands_spec":
answer = isc.config.ccsession.create_answer(0, self.get_commands_spec())
elif cmd[0] == "get_module_spec":
answer = self._handle_get_module_spec(cmd)
elif cmd[0] == "get_config":
answer = self._handle_get_config(cmd)
elif cmd[0] == "set_config":
answer = self._handle_set_config(cmd)
elif cmd[0] == "shutdown":
print("[bind-cfgd] Received shutdown command")
self.running = False
answer = isc.config.ccsession.create_answer(0)
else:
answer = isc.config.ccsession.create_answer(1, "Unknown command: " + str(cmd))
except IndexError as ie:
answer = isc.config.ccsession.create_answer(1, "Missing argument in command: " + str(ie))
raise ie
elif "module_spec" in msg:
try:
answer = self._handle_module_spec(isc.config.ModuleSpec(msg["module_spec"]))
except isc.config.ModuleSpecError as dde:
answer = isc.config.ccsession.create_answer(1, "Error in data definition: " + str(dde))
elif 'result' in msg:
# this seems wrong, might start pingpong
answer = isc.config.ccsession.create_answer(0)
#print("[XX] got msg:")
#print(msg)
cmd, arg = isc.config.ccsession.parse_command(msg)
if cmd:
#print("[XX] cmd: " + cmd)
if cmd == isc.config.ccsession.COMMAND_GET_COMMANDS_SPEC:
answer = isc.config.ccsession.create_answer(0, self.get_commands_spec())
elif cmd == isc.config.ccsession.COMMAND_GET_MODULE_SPEC:
answer = self._handle_get_module_spec(arg)
elif cmd == isc.config.ccsession.COMMAND_GET_CONFIG:
answer = self._handle_get_config(arg)
elif cmd == isc.config.ccsession.COMMAND_SET_CONFIG:
answer = self._handle_set_config(arg)
elif cmd == "shutdown":
print("[b10-cfgmgr] Received shutdown command")
self.running = False
answer = isc.config.ccsession.create_answer(0)
elif cmd == isc.config.ccsession.COMMAND_MODULE_SPEC:
try:
answer = self._handle_module_spec(isc.config.ModuleSpec(arg))
except isc.config.ModuleSpecError as dde:
answer = isc.config.ccsession.create_answer(1, "Error in data definition: " + str(dde))
else:
answer = isc.config.ccsession.create_answer(1, "Unknown command: " + str(cmd))
else:
answer = isc.config.ccsession.create_answer(1, "Unknown message format: " + str(msg))
return answer
......
......@@ -210,7 +210,7 @@ class TestConfigManager(unittest.TestCase):
def test_handle_msg(self):
self._handle_msg_helper({}, { 'result': [ 1, 'Unknown message format: {}']})
self._handle_msg_helper("", { 'result': [ 1, 'Unknown message format: ']})
self._handle_msg_helper({ "command": [ "badcommand" ] }, { 'result': [ 1, "Unknown command: ['badcommand']"]})
self._handle_msg_helper({ "command": [ "badcommand" ] }, { 'result': [ 1, "Unknown command: badcommand"]})
self._handle_msg_helper({ "command": [ "get_commands_spec" ] }, { 'result': [ 0, {} ]})
self._handle_msg_helper({ "command": [ "get_module_spec" ] }, { 'result': [ 0, {} ]})
#self._handle_msg_helper({ "command": [ "get_module_spec", { "module_name": "nosuchmodule" } ] },
......@@ -228,7 +228,7 @@ class TestConfigManager(unittest.TestCase):
{'result': [1, 'Bad module_name in get_config command']})
self._handle_msg_helper({ "command": [ "set_config" ] },
{'result': [1, 'Wrong number of arguments']})
self._handle_msg_helper({ "command": [ "set_config", {} ] },
self._handle_msg_helper({ "command": [ "set_config", [{}]] },
{'result': [0]})
self.assertEqual(len(self.fake_session.message_queue), 0)
......@@ -237,13 +237,13 @@ class TestConfigManager(unittest.TestCase):
my_ok_answer = { 'result': [ 0 ] }
self.fake_session.group_sendmsg(my_ok_answer, "ConfigManager")
self._handle_msg_helper({ "command": [ "set_config", self.name, { "test": 123 } ] },
self._handle_msg_helper({ "command": [ "set_config", [self.name, { "test": 123 }] ] },
my_ok_answer)
self.assertEqual(len(self.fake_session.message_queue), 1)
self.fake_session.group_sendmsg(my_ok_answer, "ConfigManager")
self.assertEqual({'config_update': {'test': 123}},
self.fake_session.get_message(self.name, None))
self._handle_msg_helper({ "command": [ "set_config", self.name, { "test": 124 } ] },
self._handle_msg_helper({ "command": [ "set_config", [self.name, { "test": 124 }] ] },
{'result': [0]})
#print(self.fake_session.message_queue)
......@@ -251,13 +251,11 @@ class TestConfigManager(unittest.TestCase):
self.assertEqual({'config_update': {'test': 124}},
self.fake_session.get_message(self.name, None))
self.assertEqual({'version': 1, 'TestModule': {'test': 124}}, self.cm.config.data)
self._handle_msg_helper({ "module_spec":
self.spec.get_full_spec()
self._handle_msg_helper({ "command":
["module_spec", self.spec.get_full_spec()]
},
{'result': [0]})
self._handle_msg_helper({ "module_spec":
{ 'foo': 1 }
},
self._handle_msg_helper({ "command": [ "module_spec", { 'foo': 1 } ] },
{'result': [1, 'Error in data definition: no module_name in module_spec']})
self._handle_msg_helper({ "command": [ "get_module_spec" ] }, { 'result': [ 0, { self.spec.get_module_name(): self.spec.get_config_spec() } ]})
self._handle_msg_helper({ "command": [ "get_commands_spec" ] }, { 'result': [ 0, { self.spec.get_module_name(): self.spec.get_commands_spec() } ]})
......
......@@ -103,7 +103,6 @@ def spec_name_list(spec, prefix="", recurse=False):
for name in spec:
result.append(prefix + name + "/")
if recurse:
print("[XX] recurse1")
result.extend(spec_name_list(spec[name],name, recurse))
elif type(spec) == list:
for list_el in spec:
......
......@@ -29,7 +29,6 @@ class TestConfigData(unittest.TestCase):
else:
self.data_path = "../../../testdata"
spec = isc.config.module_spec_from_file(self.data_path + os.sep + "spec2.spec")
print("SPEC: " + str(type(spec)))
self.cd = ConfigData(spec)
#def test_module_spec_from_file(self):
......
......@@ -51,7 +51,6 @@ def module_spec_from_file(spec_file, check = True):
raise ModuleSpecError("Data definition has no module_spec element")
result = ModuleSpec(module_spec['module_spec'], check)
print("RETURNING: " + str(type(result)))
return result
class ModuleSpec:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment