Commit 13a3a9aa authored by Jelte Jansen's avatar Jelte Jansen
Browse files

added a feature (yes i know, but this is a serious problem) to cc/session.py;

if you pass recvmsg() or group_recvmsg() the sequence number you got back from send(), it will only give back the answer to your message (which should be sent back with group_reply()); other messages are queued and returned on subsequent calls of recvmsg()

this should fix at least the Bad config version some people have been having (which were caused by other messages getting in before the answer to certain requests made by cmdctl)

it's only in the python version, and i would like someone to take a good look at this change (perhaps the api of this part can be better, and possibly a limit on how many messages are queued). If people are ok with this solution we'll add it to the cpp version too


git-svn-id: svn://bind10.isc.org/svn/bind10/trunk@1418 e5f2f494-b856-4b98-b285-d166d9295462
parent ea40d6dd
#!@PYTHON@
# 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.
import sys; sys.path.append ('@@PYTHONPATH@@')
from bindctl.moduleinfo import *
from bindctl.bindcmd import *
import pprint
from optparse import OptionParser, OptionValueError
__version__ = 'Bindctl'
def prepare_config_commands(tool):
module = ModuleInfo(name = "config", desc = "Configuration commands")
cmd = CommandInfo(name = "show", desc = "Show configuration")
param = ParamInfo(name = "identifier", type = "string", optional=True)
cmd.add_param(param)
module.add_command(cmd)
cmd = CommandInfo(name = "add", desc = "Add entry to configuration list")
param = ParamInfo(name = "identifier", type = "string", optional=True)
cmd.add_param(param)
param = ParamInfo(name = "value", type = "string", optional=False)
cmd.add_param(param)
module.add_command(cmd)
cmd = CommandInfo(name = "remove", desc = "Remove entry from configuration list")
param = ParamInfo(name = "identifier", type = "string", optional=True)
cmd.add_param(param)
param = ParamInfo(name = "value", type = "string", optional=False)
cmd.add_param(param)
module.add_command(cmd)
cmd = CommandInfo(name = "set", desc = "Set a configuration value")
param = ParamInfo(name = "identifier", type = "string", optional=True)
cmd.add_param(param)
param = ParamInfo(name = "value", type = "string", optional=False)
cmd.add_param(param)
module.add_command(cmd)
cmd = CommandInfo(name = "unset", desc = "Unset a configuration value")
param = ParamInfo(name = "identifier", type = "string", optional=False)
cmd.add_param(param)
module.add_command(cmd)
cmd = CommandInfo(name = "diff", desc = "Show all local changes")
module.add_command(cmd)
cmd = CommandInfo(name = "revert", desc = "Revert all local changes")
module.add_command(cmd)
cmd = CommandInfo(name = "commit", desc = "Commit all local changes")
module.add_command(cmd)
cmd = CommandInfo(name = "go", desc = "Go to a specific configuration part")
param = ParamInfo(name = "identifier", type="string", optional=False)
cmd.add_param(param)
module.add_command(cmd)
tool.add_module_info(module)
def check_port(option, opt_str, value, parser):
if (value < 0) or (value > 65535):
raise OptionValueError('%s requires a port number (0-65535)' % opt_str)
parser.values.port = value
def check_addr(option, opt_str, value, parser):
ipstr = value
ip_family = socket.AF_INET
if (ipstr.find(':') != -1):
ip_family = socket.AF_INET6
try:
socket.inet_pton(ip_family, ipstr)
except:
raise OptionValueError("%s invalid ip address" % ipstr)
parser.values.addr = value
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')
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')
if __name__ == '__main__':
try:
parser = OptionParser(version = __version__)
set_bindctl_options(parser)
(options, args) = parser.parse_args()
server_addr = options.addr + ':' + str(options.port)
tool = BindCmdInterpreter(server_addr)
prepare_config_commands(tool)
tool.run()
except Exception as e:
print(e, "\nFailed to connect with b10-cmdctl module, is it running?")
......@@ -296,9 +296,9 @@ class CommandControl():
print('b10-cmdctl send command \'%s\' to %s' %(command_name, module_name))
try:
msg = isc.config.ccsession.create_command(command_name, params)
self.cc.group_sendmsg(msg, module_name)
seq = self.cc.group_sendmsg(msg, module_name)
#TODO, it may be blocked, msqg need to add a new interface waiting in timeout.
answer, env = self.cc.group_recvmsg(False)
answer, env = self.cc.group_recvmsg(False, seq)
if answer:
try:
rcode, arg = isc.config.ccsession.parse_answer(answer)
......
......@@ -32,6 +32,7 @@ class Session:
self._recvlength = 0
self._sequence = 1
self._closed = False
self._queue = []
try:
self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
......@@ -75,7 +76,18 @@ class Session:
if msg:
self._socket.send(msg)
def recvmsg(self, nonblock = True):
def recvmsg(self, nonblock = True, seq = None):
if len(self._queue) > 0:
if seq == None:
msg, env = self._queue.pop(0)
else:
i = 0;
for msg, env in self._queue:
if "reply" in env and seq == env["reply"]:
self._queue.remove(i)
return env, msg
else:
i = i + 1
if self._closed:
raise SessionError("Session has been closed.")
data = self._receive_full_buffer(nonblock)
......@@ -83,7 +95,13 @@ class Session:
header_length = struct.unpack('>H', data[0:2])[0]
data_length = len(data) - 2 - header_length
if data_length > 0:
return isc.cc.message.from_wire(data[2:header_length+2]), isc.cc.message.from_wire(data[header_length + 2:])
env = isc.cc.message.from_wire(data[2:header_length+2])
msg = isc.cc.message.from_wire(data[header_length + 2:])
if seq == None or "reply" in env and seq == env["reply"]:
return env, msg
else:
self._queue.append((env,msg))
self.recvmsg(nonblock, seq)
else:
return isc.cc.message.from_wire(data[2:header_length+2]), None
return None, None
......@@ -155,8 +173,8 @@ class Session:
}, isc.cc.message.to_wire(msg))
return seq
def group_recvmsg(self, nonblock = True):
env, msg = self.recvmsg(nonblock)
def group_recvmsg(self, nonblock = True, seq = None):
env, msg = self.recvmsg(nonblock, seq)
if env == None:
# return none twice to match normal return value
# (so caller won't get a type error on no data)
......
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