update to get coresendmsg working again

This commit is contained in:
Blake J. Harnden 2018-03-14 13:14:14 -07:00
parent 46e057d1ed
commit 138b2fcc4a

View file

@ -6,187 +6,207 @@
# #
# authors: Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com> # authors: Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
# #
''' """
coresendmsg: utility for generating CORE messages coresendmsg: utility for generating CORE messages
''' """
import sys
import socket
import optparse import optparse
import os import os
import socket
import sys
try:
from core.constants import *
except ImportError:
# hack for Fedora autoconf that uses the following pythondir:
if "/usr/lib/python2.6/site-packages" in sys.path:
sys.path.append("/usr/local/lib/python2.6/site-packages")
if "/usr/lib64/python2.6/site-packages" in sys.path:
sys.path.append("/usr/local/lib64/python2.6/site-packages")
if "/usr/lib/python2.7/site-packages" in sys.path:
sys.path.append("/usr/local/lib/python2.7/site-packages")
if "/usr/lib64/python2.7/site-packages" in sys.path:
sys.path.append("/usr/local/lib64/python2.7/site-packages")
from core.constants import *
from core.api import coreapi from core.api import coreapi
from core.enumerations import CORE_API_PORT
from core.enumerations import MessageFlags
from core.enumerations import MessageTypes
from core.enumerations import SessionTlvs
def msgtypenum_to_str(num): # def msgtypenum_to_str(num):
''' Convert the message type number into a string, such as # """
1 = 'CORE_API_NODE_MSG' = 'node' # Convert the message type number into a string, such as
''' # 1 = "CORE_API_NODE_MSG" = "node"
fulltypestr = coreapi.message_types[num] # """
r = fulltypestr.split('_')[2] # fulltypestr = str(MessageTypes(num))
return r.lower() # r = fulltypestr.split("_")[2]
# return r.lower()
def str_to_msgtypenum(s):
''' Convert a shorthand string into a message type number.
'''
fulltypestr = str_to_msgtypename(s)
for k, v in coreapi.message_types.iteritems():
if v == fulltypestr:
return k
return None
def str_to_msgtypename(s): # def str_to_msgtypenum(message_string):
''' Convert a shorthand string into a message type name. # """
''' # Convert a shorthand string into a message type number.
return "CORE_API_%s_MSG" % s.upper() # """
# fulltypestr = str_to_msgtypename(message_string)
# for k, v in coreapi.message_types.iteritems():
# if v == fulltypestr:
# return k
# return None
def msgflagnum_to_str(num):
''' Convert the message flag number into a string, such as
1 = 'CORE_API_ADD_FLAG' = add
'''
fullflagstr = coreapi.message_flags[num]
r = fullflagstr.split('_')[2]
return r.lower()
def str_to_msgflagname(s): # def str_to_msgtypename(s):
''' Convert a shorthand string into a message flag name. # """
''' # Convert a shorthand string into a message type name.
return "CORE_API_%s_FLAG" % s.upper() # """
# return "CORE_API_%s_MSG" % s.upper()
def str_to_msgflagnum(s):
flagname = str_to_msgflagname(s)
for (k, v) in coreapi.message_flags.iteritems():
if v == flagname:
return k
return None
def tlvname_to_str(name): # def msgflagnum_to_str(num):
''' Convert a TLV name such as CORE_TLV_CONF_NODE to a short sring 'node'. # """
''' # Convert the message flag number into a string, such as
items = name.split('_')[3:] # 1 = "CORE_API_ADD_FLAG" = add
return '_'.join(items).lower() # """
# fullflagstr = coreapi.message_flags[num]
# r = fullflagstr.split("_")[2]
# return r.lower()
def tlvname_to_num(tlv_cls, name):
''' Convert the given TLV Type class and TLV name to the TLV number.
'''
for (k, v) in tlv_cls.tlvtypemap.iteritems():
if v == name:
return k
return None
def str_to_tlvname(t, s): # def str_to_msgflagname(s):
''' Convert the given TLV type t and string s to a TLV name. # """
''' # Convert a shorthand string into a message flag name.
return "CORE_TLV_%s_%s" % (t.upper(), s.upper()) # """
# return "CORE_API_%s_FLAG" % s.upper()
# def str_to_msgflagnum(s):
# flagname = str_to_msgflagname(s)
# for (k, v) in coreapi.message_flags.iteritems():
# if v == flagname:
# return k
# return None
# def tlvname_to_str(name):
# """
# Convert a TLV name such as CORE_TLV_CONF_NODE to a short sring "node".
# """
# items = name.split("_")[3:]
# return "_".join(items).lower()
# def tlvname_to_num(tlv_cls, name):
# """
# Convert the given TLV Type class and TLV name to the TLV number.
# """
# for k, v in tlv_cls.tlv_type_map.iteritems():
# if v == name:
# return k
# return None
# def str_to_tlvname(t, s):
# """
# Convert the given TLV type t and string s to a TLV name.
# """
# return "CORE_TLV_%s_%s" % (t.upper(), s.upper())
def print_available_tlvs(t, tlv_cls): def print_available_tlvs(t, tlv_cls):
''' Print a TLV list. """
''' Print a TLV list.
"""
print "TLVs available for %s message:" % t print "TLVs available for %s message:" % t
for k in sorted(tlv_cls.tlvtypemap.keys()): for tlv in sorted([tlv for tlv in tlv_cls], key=lambda x: x.name):
print "%d:%s" % (k, tlvname_to_str(tlv_cls.tlvtypemap[k])), print "%s:%s" % (tlv.value, tlv.name)
def print_examples(name): def print_examples(name):
''' Print example usage of this script. """
''' Print example usage of this script.
"""
examples = [ examples = [
('link n1number=2 n2number=3 delay=15000', ("link n1number=2 n2number=3 delay=15000",
'set a 15ms delay on the link between n2 and n3'), "set a 15ms delay on the link between n2 and n3"),
('link n1number=2 n2number=3 guiattr=\'color=blue\'', ("link n1number=2 n2number=3 guiattr=\"color=blue\"",
'change the color of the link between n2 and n3'), "change the color of the link between n2 and n3"),
('node number=3 xpos=125 ypos=525', ("node number=3 xpos=125 ypos=525",
'move node number 3 to x,y=(125,525)'), "move node number 3 to x,y=(125,525)"),
('node number=4 icon=/usr/local/share/core/icons/normal/router_red.gif', ("node number=4 icon=/usr/local/share/core/icons/normal/router_red.gif",
'change node number 4\'s icon to red'), "change node number 4\"s icon to red"),
('node flags=add number=5 type=0 name=\'n5\' xpos=500 ypos=500', ("node flags=add number=5 type=0 name=\"n5\" xpos=500 ypos=500",
'add a new router node n5'), "add a new router node n5"),
('link flags=add n1number=4 n2number=5 if1ip4=\'10.0.3.2\' ' \ ("link flags=add n1number=4 n2number=5 if1ip4=\"10.0.3.2\" " \
'if1ip4mask=24 if2ip4=\'10.0.3.1\' if2ip4mask=24', "if1ip4mask=24 if2ip4=\"10.0.3.1\" if2ip4mask=24",
'link node n5 with n4 using the given interface addresses'), "link node n5 with n4 using the given interface addresses"),
('exec flags=str,txt node=1 num=1000 cmd=\'uname -a\' -l', ("exec flags=str,txt node=1 num=1000 cmd=\"uname -a\" -l",
'run a command on node 1 and wait for the result'), "run a command on node 1 and wait for the result"),
('exec node=2 num=1001 cmd=\'killall ospfd\'', ("exec node=2 num=1001 cmd=\"killall ospfd\"",
'run a command on node 2 and ignore the result'), "run a command on node 2 and ignore the result"),
('file flags=add node=1 name=\'/var/log/test.log\' data=\'Hello World.\'', ("file flags=add node=1 name=\"/var/log/test.log\" data=\"Hello World.\"",
'write a test.log file on node 1 with the given contents'), "write a test.log file on node 1 with the given contents"),
('file flags=add node=2 name=\'test.log\' ' \ ("file flags=add node=2 name=\"test.log\" " \
'srcname=\'./test.log\'', "srcname=\"./test.log\"",
'move a test.log file from host to node 2'), "move a test.log file from host to node 2"),
] ]
print "Example %s invocations:" % name print "Example %s invocations:" % name
for cmd, descr in examples: for cmd, descr in examples:
print " %s %s\n\t\t%s" % (name, cmd, descr) print " %s %s\n\t\t%s" % (name, cmd, descr)
def receive_message(sock): def receive_message(sock):
''' Retrieve a message from a socket and return the CoreMessage object or """
Retrieve a message from a socket and return the CoreMessage object or
None upon disconnect. Socket data beyond the first message is dropped. None upon disconnect. Socket data beyond the first message is dropped.
''' """
try: try:
# large receive buffer used for UDP sockets, instead of just receiving # large receive buffer used for UDP sockets, instead of just receiving
# the 4-byte header # the 4-byte header
data = sock.recv(4096) data = sock.recv(4096)
msghdr = data[:coreapi.CoreMessage.hdrsiz] msghdr = data[:coreapi.CoreMessage.header_len]
except KeyboardInterrupt: except KeyboardInterrupt:
print "CTRL+C pressed" print "CTRL+C pressed"
sys.exit(1) sys.exit(1)
if len(msghdr) == 0: if len(msghdr) == 0:
return None return None
msgdata = None msgdata = None
msgtype, msgflags, msglen = coreapi.CoreMessage.unpackhdr(msghdr) msgtype, msgflags, msglen = coreapi.CoreMessage.unpack_header(msghdr)
if msglen: if msglen:
msgdata = data[coreapi.CoreMessage.hdrsiz:] msgdata = data[coreapi.CoreMessage.header_len:]
try: try:
msgcls = coreapi.msg_class(msgtype) msgcls = coreapi.CLASS_MAP[msgtype]
except KeyError: except KeyError:
msg = coreapi.CoreMessage(msgflags, msghdr, msgdata) msg = coreapi.CoreMessage(msgflags, msghdr, msgdata)
msg.msgtype = msgtype msg.message_type = msgtype
print "unimplemented CORE message type: %s" % msg.typestr() print "unimplemented CORE message type: %s" % msg.type_str()
return msg return msg
if len(data) > msglen + coreapi.CoreMessage.hdrsiz: if len(data) > msglen + coreapi.CoreMessage.header_len:
print "received a message of type %d, dropping %d bytes of extra data" \ print "received a message of type %d, dropping %d bytes of extra data" \
% (msgtype, len(data) - (msglen + coreapi.CoreMessage.hdrsiz)) % (msgtype, len(data) - (msglen + coreapi.CoreMessage.header_len))
return msgcls(msgflags, msghdr, msgdata) return msgcls(msgflags, msghdr, msgdata)
def connect_to_session(sock, requested): def connect_to_session(sock, requested):
''' Use Session Messages to retrieve the current list of sessions and """
Use Session Messages to retrieve the current list of sessions and
connect to the first one. connect to the first one.
''' """
# request the session list # request the session list
tlvdata = coreapi.CoreSessionTlv.pack(coreapi.CORE_TLV_SESS_NUMBER, "0") tlvdata = coreapi.CoreSessionTlv.pack(SessionTlvs.NUMBER.value, "0")
flags = coreapi.CORE_API_STR_FLAG flags = MessageFlags.STRING.value
smsg = coreapi.CoreSessionMessage.pack(flags, tlvdata) smsg = coreapi.CoreSessionMessage.pack(flags, tlvdata)
sock.sendall(smsg) sock.sendall(smsg)
print "waiting for session list..." print "waiting for session list..."
smsgreply = receive_message(sock) smsgreply = receive_message(sock)
if smsgreply is None: if smsgreply is None:
print "disconnected" print "disconnected"
return False return False
sessstr = smsgreply.gettlv(coreapi.CORE_TLV_SESS_NUMBER)
sessstr = smsgreply.gettlv(SessionTlvs.NUMBER.value)
if sessstr is None: if sessstr is None:
print "missing session numbers" print "missing session numbers"
return False return False
# join the first session (that is not our own connection) # join the first session (that is not our own connection)
(tmp, localport) = sock.getsockname() tmp, localport = sock.getsockname()
sessions = sessstr.split('|') sessions = sessstr.split("|")
sessions.remove(str(localport)) sessions.remove(str(localport))
if len(sessions) == 0: if len(sessions) == 0:
print "no sessions to join" print "no sessions to join"
return False return False
if not requested: if not requested:
session = sessions[0] session = sessions[0]
elif requested in sessions: elif requested in sessions:
@ -194,17 +214,19 @@ def connect_to_session(sock, requested):
else: else:
print "requested session not found!" print "requested session not found!"
return False return False
print "joining session %s..." % session print "joining session %s..." % session
tlvdata = coreapi.CoreSessionTlv.pack(coreapi.CORE_TLV_SESS_NUMBER, session) tlvdata = coreapi.CoreSessionTlv.pack(SessionTlvs.NUMBER, session)
flags = coreapi.CORE_API_ADD_FLAG flags = MessageFlags.ADD
smsg = coreapi.CoreSessionMessage.pack(flags, tlvdata) smsg = coreapi.CoreSessionMessage.pack(flags, tlvdata)
sock.sendall(smsg) sock.sendall(smsg)
return True return True
def receive_response(sock, opt): def receive_response(sock, opt):
''' Receive and print a CORE message from the given socket. """
''' Receive and print a CORE message from the given socket.
"""
print "waiting for response..." print "waiting for response..."
msg = receive_message(sock) msg = receive_message(sock)
if msg is None: if msg is None:
@ -214,42 +236,44 @@ def receive_response(sock, opt):
def main(): def main():
''' Parse command-line arguments to build and send a CORE message. """
''' Parse command-line arguments to build and send a CORE message.
types = map(msgtypenum_to_str, coreapi.message_types.keys()[:-1]) """
flags = map(msgflagnum_to_str, sorted(coreapi.message_flags.keys())) types = [message_type.name for message_type in MessageTypes]
flags = [flag.name for flag in MessageFlags]
usagestr = "usage: %prog [-h|-H] [options] [message-type] [flags=flags] " usagestr = "usage: %prog [-h|-H] [options] [message-type] [flags=flags] "
usagestr += "[message-TLVs]\n\n" usagestr += "[message-TLVs]\n\n"
usagestr += "Supported message types:\n %s\n" % types usagestr += "Supported message types:\n %s\n" % types
usagestr += "Supported message flags (flags=f1,f2,...):\n %s" % flags usagestr += "Supported message flags (flags=f1,f2,...):\n %s" % flags
parser = optparse.OptionParser(usage=usagestr) parser = optparse.OptionParser(usage=usagestr)
parser.set_defaults(port = coreapi.CORE_API_PORT, parser.set_defaults(
port=CORE_API_PORT,
address="localhost", address="localhost",
session=None, session=None,
listen=False, listen=False,
examples=False, examples=False,
tlvs=False, tlvs=False,
tcp = False) tcp=False
)
parser.add_option("-H", dest="examples", action="store_true", parser.add_option("-H", dest="examples", action="store_true",
help="show example usage help message and exit") help="show example usage help message and exit")
parser.add_option("-p", "--port", dest="port", type=int, parser.add_option("-p", "--port", dest="port", type=int,
help="TCP port to connect to, default: %d" % \ help="TCP port to connect to, default: %d" % \
parser.defaults['port']) parser.defaults["port"])
parser.add_option("-a", "--address", dest="address", type=str, parser.add_option("-a", "--address", dest="address", type=str,
help="Address to connect to, default: %s" % \ help="Address to connect to, default: %s" % \
parser.defaults['address']) parser.defaults["address"])
parser.add_option("-s", "--session", dest="session", type=str, parser.add_option("-s", "--session", dest="session", type=str,
help="Session to join, default: %s" % \ help="Session to join, default: %s" % \
parser.defaults['session']) parser.defaults["session"])
parser.add_option("-l", "--listen", dest="listen", action="store_true", parser.add_option("-l", "--listen", dest="listen", action="store_true",
help="Listen for a response message and print it.") help="Listen for a response message and print it.")
parser.add_option("-t", "--list-tlvs", dest="tlvs", action="store_true", parser.add_option("-t", "--list-tlvs", dest="tlvs", action="store_true",
help="List TLVs for the specified message type.") help="List TLVs for the specified message type.")
parser.add_option("-T", "--tcp", dest="tcp", action="store_true", parser.add_option("-T", "--tcp", dest="tcp", action="store_true",
help="Use TCP instead of UDP and connect to a session" \ help="Use TCP instead of UDP and connect to a session" \
", default: %s" % parser.defaults['tcp']) ", default: %s" % parser.defaults["tcp"])
def usage(msg=None, err=0): def usage(msg=None, err=0):
sys.stdout.write("\n") sys.stdout.write("\n")
@ -259,8 +283,8 @@ def main():
sys.exit(err) sys.exit(err)
# parse command line opt # parse command line opt
(opt, args) = parser.parse_args() opt, args = parser.parse_args()
if (opt.examples): if opt.examples:
print_examples(os.path.basename(sys.argv[0])) print_examples(os.path.basename(sys.argv[0]))
sys.exit(0) sys.exit(0)
if len(args) == 0: if len(args) == 0:
@ -270,40 +294,47 @@ def main():
t = args.pop(0) t = args.pop(0)
if t not in types: if t not in types:
usage("Unknown message type requested: %s" % t) usage("Unknown message type requested: %s" % t)
msg_cls = coreapi.msgclsmap[str_to_msgtypenum(t)] message_type = MessageTypes[t]
tlv_cls = msg_cls.tlvcls msg_cls = coreapi.CLASS_MAP[message_type.value]
tlv_cls = msg_cls.tlv_cls
# list TLV types for this message type # list TLV types for this message type
if opt.tlvs: if opt.tlvs:
print_available_tlvs(t, tlv_cls) print_available_tlvs(t, tlv_cls)
sys.exit(0) sys.exit(0)
# build a message consisting of TLVs from 'type=value' arguments # build a message consisting of TLVs from "type=value" arguments
flagstr = "" flagstr = ""
tlvdata = "" tlvdata = ""
for a in args: for a in args:
typevalue = a.split('=') typevalue = a.split("=")
if len(typevalue) < 2: if len(typevalue) < 2:
usage("Use 'type=value' syntax instead of '%s'." % a) usage("Use \"type=value\" syntax instead of \"%s\"." % a)
tlv_typestr = typevalue[0] tlv_typestr = typevalue[0]
tlv_valstr = '='.join(typevalue[1:]) tlv_valstr = "=".join(typevalue[1:])
if tlv_typestr == "flags": if tlv_typestr == "flags":
flagstr = tlv_valstr flagstr = tlv_valstr
continue continue
tlv_name = str_to_tlvname(t, tlv_typestr)
tlv_type = tlvname_to_num(tlv_cls, tlv_name) tlv_name = tlv_typestr
if tlv_name not in tlv_cls.tlvtypemap.values(): tlv_type = tlv_cls[tlv_name].value
usage("Unknown TLV: '%s' / %s" % (tlv_typestr, tlv_name)) try:
tlvdata += tlv_cls.packstring(tlv_type, tlv_valstr) tlv_cls.tlv_type_map[tlv_name]
except KeyError:
usage("Unknown TLV: \"%s\"" % tlv_name)
tlvdata += tlv_cls.pack_string(tlv_type, tlv_valstr)
flags = 0 flags = 0
for f in flagstr.split(","): for f in flagstr.split(","):
if f == '': if f == "":
continue continue
n = str_to_msgflagnum(f)
if n is None: try:
usage("Invalid flag '%s'." % f) flag_enum = MessageFlags[f]
n = flag_enum.value
flags |= n flags |= n
except KeyError:
usage("Invalid flag \"%s\"." % f)
msg = msg_cls.pack(flags, tlvdata) msg = msg_cls.pack(flags, tlvdata)
@ -312,11 +343,13 @@ def main():
protocol = socket.SOCK_STREAM protocol = socket.SOCK_STREAM
else: else:
protocol = socket.SOCK_DGRAM protocol = socket.SOCK_DGRAM
sock = socket.socket(socket.AF_INET, protocol) sock = socket.socket(socket.AF_INET, protocol)
sock.setblocking(True) sock.setblocking(True)
try: try:
sock.connect((opt.address, opt.port)) sock.connect((opt.address, opt.port))
except Exception, e: except Exception as e:
print "Error connecting to %s:%s:\n\t%s" % (opt.address, opt.port, e) print "Error connecting to %s:%s:\n\t%s" % (opt.address, opt.port, e)
sys.exit(1) sys.exit(1)