moved daemon/sbin to daemon/scripts
This commit is contained in:
parent
ac81c049ee
commit
09cf406187
7 changed files with 4 additions and 11 deletions
|
@ -1,64 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
if [ "z$1" = "z-h" -o "z$1" = "z--help" ]; then
|
||||
echo "usage: $0 [-d [-l]]"
|
||||
echo -n " Clean up all CORE namespaces processes, bridges, interfaces, "
|
||||
echo "and session\n directories. Options:"
|
||||
echo " -h show this help message and exit"
|
||||
echo " -d also kill the Python daemon"
|
||||
echo " -l remove the core-daemon.log file"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ `id -u` != 0 ]; then
|
||||
echo "Permission denied. Re-run this script as root."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PATH="/sbin:/bin:/usr/sbin:/usr/bin"
|
||||
export PATH
|
||||
|
||||
if [ "z$1" = "z-d" ]; then
|
||||
pypids=`pidof python python2`
|
||||
for p in $pypids; do
|
||||
grep -q core-daemon /proc/$p/cmdline
|
||||
if [ $? = 0 ]; then
|
||||
echo "cleaning up core-daemon process: $p"
|
||||
kill -9 $p
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [ "z$2" = "z-l" ]; then
|
||||
rm -f /var/log/core-daemon.log
|
||||
fi
|
||||
|
||||
vnodedpids=`pidof vnoded`
|
||||
if [ "z$vnodedpids" != "z" ]; then
|
||||
echo "cleaning up old vnoded processes: $vnodedpids"
|
||||
killall -v -KILL vnoded
|
||||
# pause for 1 second for interfaces to disappear
|
||||
sleep 1
|
||||
fi
|
||||
killall -q emane
|
||||
killall -q emanetransportd
|
||||
killall -q emaneeventservice
|
||||
|
||||
if [ -d /sys/class/net ]; then
|
||||
ifcommand="ls -1 /sys/class/net"
|
||||
else
|
||||
ifcommand="ip -o link show | sed -r -e 's/[0-9]+: ([^[:space:]]+): .*/\1/'"
|
||||
fi
|
||||
|
||||
eval "$ifcommand" | awk '
|
||||
/^veth[0-9]+\./ {print "removing interface " $1; system("ip link del " $1);}
|
||||
/tmp\./ {print "removing interface " $1; system("ip link del " $1);}
|
||||
/gt\./ {print "removing interface " $1; system("ip link del " $1);}
|
||||
/b\./ {print "removing bridge " $1; system("ip link set " $1 " down; brctl delbr " $1);}
|
||||
'
|
||||
|
||||
ebtables -L FORWARD | awk '
|
||||
/^-.*b\./ {print "removing ebtables " $0; system("ebtables -D FORWARD " $0); print "removing ebtables chain " $4; system("ebtables -X " $4);}
|
||||
'
|
||||
|
||||
rm -rf /tmp/pycore*
|
|
@ -1,316 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
"""
|
||||
core-daemon: the CORE daemon is a server process that receives CORE API
|
||||
messages and instantiates emulated nodes and networks within the kernel. Various
|
||||
message handlers are defined and some support for sending messages.
|
||||
"""
|
||||
|
||||
import ConfigParser
|
||||
import atexit
|
||||
import optparse
|
||||
import os
|
||||
import signal
|
||||
import socket
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
|
||||
from core import constants
|
||||
from core import corehandlers
|
||||
from core import coreserver
|
||||
from core import enumerations
|
||||
from core import logger
|
||||
from core import services
|
||||
from core.api import coreapi
|
||||
from core.corehandlers import CoreDatagramRequestHandler
|
||||
from core.enumerations import MessageFlags
|
||||
from core.enumerations import RegisterTlvs
|
||||
from core.misc import nodeutils
|
||||
from core.misc.utils import close_onexec
|
||||
from core.misc.utils import daemonize
|
||||
from core.service import ServiceManager
|
||||
|
||||
DEFAULT_MAXFD = 1024
|
||||
|
||||
|
||||
def startudp(core_server, server_address):
|
||||
"""
|
||||
Start a thread running a UDP server on the same host,port for connectionless requests.
|
||||
|
||||
:param core.coreserver.CoreServer core_server: core server instance
|
||||
:param tuple[str, int] server_address: server address
|
||||
:return: created core udp server
|
||||
:rtype: core.coreserver.CoreUdpServer
|
||||
"""
|
||||
core_server.udpserver = coreserver.CoreUdpServer(server_address, CoreDatagramRequestHandler, core_server)
|
||||
core_server.udpthread = threading.Thread(target=core_server.udpserver.start)
|
||||
core_server.udpthread.daemon = True
|
||||
core_server.udpthread.start()
|
||||
return core_server.udpserver
|
||||
|
||||
|
||||
def banner():
|
||||
"""
|
||||
Output the program banner printed to the terminal or log file.
|
||||
|
||||
:return: nothing
|
||||
"""
|
||||
logger.info("CORE daemon v.%s started %s\n" % (constants.COREDPY_VERSION, time.ctime()))
|
||||
|
||||
|
||||
def cored(cfg=None):
|
||||
"""
|
||||
Start the CoreServer object and enter the server loop.
|
||||
|
||||
:param dict cfg: core configuration
|
||||
:return: nothing
|
||||
"""
|
||||
host = cfg["listenaddr"]
|
||||
port = int(cfg["port"])
|
||||
if host == "" or host is None:
|
||||
host = "localhost"
|
||||
try:
|
||||
server = coreserver.CoreServer((host, port), corehandlers.CoreRequestHandler, cfg)
|
||||
except:
|
||||
logger.exception("error starting main server on: %s:%s", host, port)
|
||||
sys.exit(1)
|
||||
|
||||
close_onexec(server.fileno())
|
||||
logger.info("main server started, listening on: %s:%s\n" % (host, port))
|
||||
|
||||
udpserver = startudp(server, (host, port))
|
||||
close_onexec(udpserver.fileno())
|
||||
|
||||
server.serve_forever()
|
||||
|
||||
|
||||
# TODO: should sessions and the main core daemon both catch at exist to shutdown independently?
|
||||
def cleanup():
|
||||
"""
|
||||
Runs server shutdown and cleanup when catching an exit signal.
|
||||
|
||||
:return: nothing
|
||||
"""
|
||||
while coreserver.CoreServer.servers:
|
||||
server = coreserver.CoreServer.servers.pop()
|
||||
server.shutdown()
|
||||
|
||||
|
||||
atexit.register(cleanup)
|
||||
|
||||
|
||||
def sighandler(signum, stackframe):
|
||||
"""
|
||||
Signal handler when different signals are sent.
|
||||
|
||||
:param int signum: singal number sent
|
||||
:param stackframe: stack frame sent
|
||||
:return: nothing
|
||||
"""
|
||||
logger.error("terminated by signal: %s", signum)
|
||||
sys.exit(signum)
|
||||
|
||||
|
||||
signal.signal(signal.SIGHUP, sighandler)
|
||||
signal.signal(signal.SIGINT, sighandler)
|
||||
signal.signal(signal.SIGTERM, sighandler)
|
||||
signal.signal(signal.SIGUSR1, sighandler)
|
||||
signal.signal(signal.SIGUSR2, sighandler)
|
||||
|
||||
|
||||
def logrotate(stdout, stderr, stdoutmode=0644, stderrmode=0644):
|
||||
"""
|
||||
Log rotation method.
|
||||
|
||||
:param stdout: stdout
|
||||
:param stderr: stderr
|
||||
:param int stdoutmode: stdout mode
|
||||
:param int stderrmode: stderr mode
|
||||
:return:
|
||||
"""
|
||||
|
||||
def reopen(fileno, filename, mode):
|
||||
err = 0
|
||||
fd = -1
|
||||
try:
|
||||
fd = os.open(filename,
|
||||
os.O_WRONLY | os.O_CREAT | os.O_APPEND, mode)
|
||||
os.dup2(fd, fileno)
|
||||
except OSError as e:
|
||||
err = e.errno
|
||||
finally:
|
||||
if fd >= 0:
|
||||
os.close(fd)
|
||||
return err
|
||||
|
||||
if stdout:
|
||||
err = reopen(1, stdout, stdoutmode)
|
||||
if stderr:
|
||||
if stderr == stdout and not err:
|
||||
try:
|
||||
os.dup2(1, 2)
|
||||
except OSError as e:
|
||||
pass
|
||||
else:
|
||||
reopen(2, stderr, stderrmode)
|
||||
|
||||
|
||||
def get_merged_config(filename):
|
||||
"""
|
||||
Return a configuration after merging config file and command-line arguments.
|
||||
|
||||
:param str filename: file name to merge configuration settings with
|
||||
:return: merged configuration
|
||||
:rtype: dict
|
||||
"""
|
||||
# these are the defaults used in the config file
|
||||
defaults = {"port": "%d" % enumerations.CORE_API_PORT,
|
||||
"listenaddr": "localhost",
|
||||
"pidfile": "%s/run/core-daemon.pid" % constants.CORE_STATE_DIR,
|
||||
"logfile": "%s/log/core-daemon.log" % constants.CORE_STATE_DIR,
|
||||
"xmlfilever": "1.0",
|
||||
"numthreads": "1",
|
||||
"verbose": "False",
|
||||
"daemonize": "False",
|
||||
"debug": "False",
|
||||
"execfile": None,
|
||||
}
|
||||
|
||||
usagestr = "usage: %prog [-h] [options] [args]\n\n" + \
|
||||
"CORE daemon v.%s instantiates Linux network namespace " \
|
||||
"nodes." % constants.COREDPY_VERSION
|
||||
parser = optparse.OptionParser(usage=usagestr)
|
||||
parser.add_option("-f", "--configfile", dest="configfile",
|
||||
type="string",
|
||||
help="read config from specified file; default = %s" %
|
||||
filename)
|
||||
parser.add_option("-d", "--daemonize", dest="daemonize",
|
||||
action="store_true",
|
||||
help="run in background as daemon; default=%s" % \
|
||||
defaults["daemonize"])
|
||||
parser.add_option("-e", "--execute", dest="execfile", type="string",
|
||||
help="execute a Python/XML-based session")
|
||||
parser.add_option("-l", "--logfile", dest="logfile", type="string",
|
||||
help="log output to specified file; default = %s" %
|
||||
defaults["logfile"])
|
||||
parser.add_option("-p", "--port", dest="port", type=int,
|
||||
help="port number to listen on; default = %s" % \
|
||||
defaults["port"])
|
||||
parser.add_option("-i", "--pidfile", dest="pidfile",
|
||||
help="filename to write pid to; default = %s" % \
|
||||
defaults["pidfile"])
|
||||
parser.add_option("-t", "--numthreads", dest="numthreads", type=int,
|
||||
help="number of server threads; default = %s" % \
|
||||
defaults["numthreads"])
|
||||
parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
|
||||
help="enable verbose logging; default = %s" % \
|
||||
defaults["verbose"])
|
||||
parser.add_option("-g", "--debug", dest="debug", action="store_true",
|
||||
help="enable debug logging; default = %s" % \
|
||||
defaults["debug"])
|
||||
|
||||
# parse command line options
|
||||
options, args = parser.parse_args()
|
||||
|
||||
# read the config file
|
||||
if options.configfile is not None:
|
||||
filename = options.configfile
|
||||
del options.configfile
|
||||
cfg = ConfigParser.SafeConfigParser(defaults)
|
||||
cfg.read(filename)
|
||||
|
||||
section = "core-daemon"
|
||||
if not cfg.has_section(section):
|
||||
cfg.add_section(section)
|
||||
# gracefully support legacy configs (cored.py/cored now core-daemon)
|
||||
if cfg.has_section("cored.py"):
|
||||
for name, val in cfg.items("cored.py"):
|
||||
if name == "pidfile" or name == "logfile":
|
||||
bn = os.path.basename(val).replace("coredpy", "core-daemon")
|
||||
val = os.path.join(os.path.dirname(val), bn)
|
||||
cfg.set(section, name, val)
|
||||
if cfg.has_section("cored"):
|
||||
for name, val in cfg.items("cored"):
|
||||
if name == "pidfile" or name == "logfile":
|
||||
bn = os.path.basename(val).replace("cored", "core-daemon")
|
||||
val = os.path.join(os.path.dirname(val), bn)
|
||||
cfg.set(section, name, val)
|
||||
|
||||
# merge command line with config file
|
||||
for opt in options.__dict__:
|
||||
val = options.__dict__[opt]
|
||||
if val is not None:
|
||||
cfg.set(section, opt, val.__str__())
|
||||
|
||||
return dict(cfg.items(section)), args
|
||||
|
||||
|
||||
def exec_file(cfg):
|
||||
"""
|
||||
Send a Register Message to execute a new session based on XML or Python script file.
|
||||
|
||||
:param dict cfg: configuration settings
|
||||
:return: 0
|
||||
"""
|
||||
filename = cfg["execfile"]
|
||||
logger.info("Telling daemon to execute file: %s...", filename)
|
||||
tlvdata = coreapi.CoreRegisterTlv.pack(RegisterTlvs.EXECUTE_SERVER.value, filename)
|
||||
msg = coreapi.CoreRegMessage.pack(MessageFlags.ADD.value, tlvdata)
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
# TODO: connect address option
|
||||
sock.connect(("localhost", int(cfg["port"])))
|
||||
sock.sendall(msg)
|
||||
return 0
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
Main program startup.
|
||||
|
||||
:return: nothing
|
||||
"""
|
||||
# get a configuration merged from config file and command-line arguments
|
||||
cfg, args = get_merged_config("%s/core.conf" % constants.CORE_CONF_DIR)
|
||||
for a in args:
|
||||
logger.error("ignoring command line argument: %s", a)
|
||||
|
||||
# attempt load custom services
|
||||
service_paths = cfg.get("custom_services_dir")
|
||||
logger.debug("custom service paths: %s", service_paths)
|
||||
if service_paths:
|
||||
for service_path in service_paths.split(','):
|
||||
service_path = service_path.strip()
|
||||
ServiceManager.add_services(service_path)
|
||||
|
||||
if cfg["daemonize"] == "True":
|
||||
daemonize(rootdir=None, umask=0, close_fds=False,
|
||||
stdin=os.devnull,
|
||||
stdout=cfg["logfile"], stderr=cfg["logfile"],
|
||||
pidfilename=cfg["pidfile"],
|
||||
defaultmaxfd=DEFAULT_MAXFD)
|
||||
signal.signal(signal.SIGUSR1, lambda signum, stackframe:
|
||||
logrotate(stdout=cfg["logfile"], stderr=cfg["logfile"]))
|
||||
|
||||
banner()
|
||||
if cfg["execfile"]:
|
||||
cfg["execfile"] = os.path.abspath(cfg["execfile"])
|
||||
sys.exit(exec_file(cfg))
|
||||
try:
|
||||
cored(cfg)
|
||||
except KeyboardInterrupt:
|
||||
logger.info("keyboard interrupt, stopping core daemon")
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# configure nodes to use
|
||||
if len(sys.argv) == 2 and sys.argv[1] == "ovs":
|
||||
from core.netns.openvswitch import OVS_NODES
|
||||
|
||||
nodeutils.update_node_map(OVS_NODES)
|
||||
|
||||
# load default services
|
||||
services.load()
|
||||
|
||||
main()
|
|
@ -1,248 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
"""
|
||||
core-manage: Helper tool to add, remove, or check for services, models, and
|
||||
node types in a CORE installation.
|
||||
"""
|
||||
|
||||
import ast
|
||||
import optparse
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
from core import services
|
||||
from core.constants import CORE_CONF_DIR
|
||||
|
||||
|
||||
class FileUpdater(object):
|
||||
"""
|
||||
Helper class for changing configuration files.
|
||||
"""
|
||||
actions = ("add", "remove", "check")
|
||||
targets = ("service", "model", "nodetype")
|
||||
|
||||
def __init__(self, action, target, data, options):
|
||||
"""
|
||||
"""
|
||||
self.action = action
|
||||
self.target = target
|
||||
self.data = data
|
||||
self.options = options
|
||||
self.verbose = options.verbose
|
||||
self.search, self.filename = self.get_filename(target)
|
||||
|
||||
def process(self):
|
||||
""" Invoke update_file() using a helper method depending on target.
|
||||
"""
|
||||
if self.verbose:
|
||||
txt = "Updating"
|
||||
if self.action == "check":
|
||||
txt = "Checking"
|
||||
sys.stdout.write("%s file: %s\n" % (txt, self.filename))
|
||||
|
||||
if self.target == "service":
|
||||
r = self.update_file(fn=self.update_services)
|
||||
elif self.target == "model":
|
||||
r = self.update_file(fn=self.update_emane_models)
|
||||
elif self.target == "nodetype":
|
||||
r = self.update_nodes_conf()
|
||||
|
||||
if self.verbose:
|
||||
txt = ""
|
||||
if not r:
|
||||
txt = "NOT "
|
||||
if self.action == "check":
|
||||
sys.stdout.write("String %sfound.\n" % txt)
|
||||
else:
|
||||
sys.stdout.write("File %supdated.\n" % txt)
|
||||
|
||||
return r
|
||||
|
||||
def update_services(self, line):
|
||||
""" Modify the __init__.py file having this format:
|
||||
__all__ = ["quagga", "nrl", "xorp", "bird", ]
|
||||
Returns True or False when "check" is the action, a modified line
|
||||
otherwise.
|
||||
"""
|
||||
line = line.strip("\n")
|
||||
key, valstr = line.split("= ")
|
||||
vals = ast.literal_eval(valstr)
|
||||
r = self.update_keyvals(key, vals)
|
||||
if self.action == "check":
|
||||
return r
|
||||
valstr = "%s" % r
|
||||
return "= ".join([key, valstr]) + "\n"
|
||||
|
||||
def update_emane_models(self, line):
|
||||
""" Modify the core.conf file having this format:
|
||||
emane_models = RfPipe, Ieee80211abg, CommEffect, Bypass
|
||||
Returns True or False when "check" is the action, a modified line
|
||||
otherwise.
|
||||
"""
|
||||
line = line.strip("\n")
|
||||
key, valstr = line.split("= ")
|
||||
vals = valstr.split(", ")
|
||||
r = self.update_keyvals(key, vals)
|
||||
if self.action == "check":
|
||||
return r
|
||||
valstr = ", ".join(r)
|
||||
return "= ".join([key, valstr]) + "\n"
|
||||
|
||||
def update_keyvals(self, key, vals):
|
||||
""" Perform self.action on (key, vals).
|
||||
Returns True or False when "check" is the action, a modified line
|
||||
otherwise.
|
||||
"""
|
||||
if self.action == "check":
|
||||
if self.data in vals:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
elif self.action == "add":
|
||||
if self.data not in vals:
|
||||
vals.append(self.data)
|
||||
elif self.action == "remove":
|
||||
try:
|
||||
vals.remove(self.data)
|
||||
except ValueError:
|
||||
pass
|
||||
return vals
|
||||
|
||||
def get_filename(self, target):
|
||||
""" Return search string and filename based on target.
|
||||
"""
|
||||
if target == "service":
|
||||
filename = os.path.abspath(services.__file__)
|
||||
search = "__all__ ="
|
||||
elif target == "model":
|
||||
filename = os.path.join(CORE_CONF_DIR, "core.conf")
|
||||
search = "emane_models ="
|
||||
elif target == "nodetype":
|
||||
if self.options.userpath is None:
|
||||
raise ValueError, "missing user path"
|
||||
filename = os.path.join(self.options.userpath, "nodes.conf")
|
||||
search = self.data
|
||||
else:
|
||||
raise ValueError, "unknown target"
|
||||
if not os.path.exists(filename):
|
||||
raise ValueError, "file %s does not exist" % filename
|
||||
return search, filename
|
||||
|
||||
def update_file(self, fn=None):
|
||||
""" Open a file and search for self.search, invoking the supplied
|
||||
function on the matching line. Write file changes if necessary.
|
||||
Returns True if the file has changed (or action is "check" and the
|
||||
search string is found), False otherwise.
|
||||
"""
|
||||
changed = False
|
||||
output = "" # this accumulates output, assumes input is small
|
||||
with open(self.filename, "r") as f:
|
||||
for line in f:
|
||||
if line[:len(self.search)] == self.search:
|
||||
r = fn(line) # line may be modified by fn() here
|
||||
if self.action == "check":
|
||||
return r
|
||||
else:
|
||||
if line != r:
|
||||
changed = True
|
||||
line = r
|
||||
output += line
|
||||
if changed:
|
||||
with open(self.filename, "w") as f:
|
||||
f.write(output)
|
||||
|
||||
return changed
|
||||
|
||||
def update_nodes_conf(self):
|
||||
""" Add/remove/check entries from nodes.conf. This file
|
||||
contains a Tcl-formatted array of node types. The array index must be
|
||||
properly set for new entries. Uses self.{action, filename, search,
|
||||
data} variables as input and returns the same value as update_file().
|
||||
"""
|
||||
changed = False
|
||||
output = "" # this accumulates output, assumes input is small
|
||||
with open(self.filename, "r") as f:
|
||||
for line in f:
|
||||
# make sure data is not added twice
|
||||
if line.find(self.search) >= 0:
|
||||
if self.action == "check":
|
||||
return True
|
||||
elif self.action == "add":
|
||||
return False
|
||||
elif self.action == "remove":
|
||||
changed = True
|
||||
continue
|
||||
else:
|
||||
output += line
|
||||
|
||||
if self.action == "add":
|
||||
index = int(re.match("^\d+", line).group(0))
|
||||
output += str(index + 1) + " " + self.data + "\n"
|
||||
changed = True
|
||||
if changed:
|
||||
with open(self.filename, "w") as f:
|
||||
f.write(output)
|
||||
|
||||
return changed
|
||||
|
||||
|
||||
def main():
|
||||
usagestr = "usage: %prog [-h] [options] <action> <target> <string>\n"
|
||||
usagestr += "\nHelper tool to add, remove, or check for "
|
||||
usagestr += "services, models, and node types\nin a CORE installation.\n"
|
||||
usagestr += "\nExamples:\n %prog add service newrouting"
|
||||
usagestr += "\n %prog -v check model RfPipe"
|
||||
usagestr += "\n %prog --userpath=\"$HOME/.core\" add nodetype \"{ftp ftp.gif ftp.gif {DefaultRoute FTP} netns {FTP server} }\" \n"
|
||||
usagestr += "\nArguments:\n <action> should be one of: %s" % \
|
||||
", ".join(FileUpdater.actions)
|
||||
usagestr += "\n <target> should be one of: %s" % \
|
||||
", ".join(FileUpdater.targets)
|
||||
usagestr += "\n <string> is the text to %s" % \
|
||||
", ".join(FileUpdater.actions)
|
||||
parser = optparse.OptionParser(usage=usagestr)
|
||||
parser.set_defaults(userpath=None, verbose=False, )
|
||||
|
||||
parser.add_option("--userpath", dest="userpath", type="string",
|
||||
help="use the specified user path (e.g. \"$HOME/.core" \
|
||||
"\") to access nodes.conf")
|
||||
parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
|
||||
help="be verbose when performing action")
|
||||
|
||||
def usage(msg=None, err=0):
|
||||
sys.stdout.write("\n")
|
||||
if msg:
|
||||
sys.stdout.write(msg + "\n\n")
|
||||
parser.print_help()
|
||||
sys.exit(err)
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
if len(args) != 3:
|
||||
usage("Missing required arguments!", 1)
|
||||
|
||||
action = args[0]
|
||||
if action not in FileUpdater.actions:
|
||||
usage("invalid action %s" % action, 1)
|
||||
|
||||
target = args[1]
|
||||
if target not in FileUpdater.targets:
|
||||
usage("invalid target %s" % target, 1)
|
||||
|
||||
if target == "nodetype" and not options.userpath:
|
||||
usage("user path option required for this target (%s)" % target)
|
||||
|
||||
data = args[2]
|
||||
|
||||
try:
|
||||
up = FileUpdater(action, target, data, options)
|
||||
r = up.process()
|
||||
except Exception, e:
|
||||
sys.stderr.write("Exception: %s\n" % e)
|
||||
sys.exit(1)
|
||||
if not r:
|
||||
sys.exit(1)
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -1,275 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
"""
|
||||
coresendmsg: utility for generating CORE messages
|
||||
"""
|
||||
|
||||
import optparse
|
||||
import os
|
||||
import socket
|
||||
import sys
|
||||
|
||||
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 print_available_tlvs(t, tlv_class):
|
||||
"""
|
||||
Print a TLV list.
|
||||
"""
|
||||
print "TLVs available for %s message:" % t
|
||||
for tlv in sorted([tlv for tlv in tlv_class.tlv_type_map], key=lambda x: x.name):
|
||||
print "%s:%s" % (tlv.value, tlv.name)
|
||||
|
||||
|
||||
def print_examples(name):
|
||||
"""
|
||||
Print example usage of this script.
|
||||
"""
|
||||
examples = [
|
||||
("link n1number=2 n2number=3 delay=15000",
|
||||
"set a 15ms delay on the link between n2 and n3"),
|
||||
("link n1number=2 n2number=3 guiattr=\"color=blue\"",
|
||||
"change the color of the link between n2 and n3"),
|
||||
("node number=3 xpos=125 ypos=525",
|
||||
"move node number 3 to x,y=(125,525)"),
|
||||
("node number=4 icon=/usr/local/share/core/icons/normal/router_red.gif",
|
||||
"change node number 4\"s icon to red"),
|
||||
("node flags=add number=5 type=0 name=\"n5\" xpos=500 ypos=500",
|
||||
"add a new router node n5"),
|
||||
("link flags=add n1number=4 n2number=5 if1ip4=\"10.0.3.2\" " \
|
||||
"if1ip4mask=24 if2ip4=\"10.0.3.1\" if2ip4mask=24",
|
||||
"link node n5 with n4 using the given interface addresses"),
|
||||
("exec flags=str,txt node=1 num=1000 cmd=\"uname -a\" -l",
|
||||
"run a command on node 1 and wait for the result"),
|
||||
("exec node=2 num=1001 cmd=\"killall ospfd\"",
|
||||
"run a command on node 2 and ignore the result"),
|
||||
("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"),
|
||||
("file flags=add node=2 name=\"test.log\" " \
|
||||
"srcname=\"./test.log\"",
|
||||
"move a test.log file from host to node 2"),
|
||||
]
|
||||
print "Example %s invocations:" % name
|
||||
for cmd, descr in examples:
|
||||
print " %s %s\n\t\t%s" % (name, cmd, descr)
|
||||
|
||||
|
||||
def receive_message(sock):
|
||||
"""
|
||||
Retrieve a message from a socket and return the CoreMessage object or
|
||||
None upon disconnect. Socket data beyond the first message is dropped.
|
||||
"""
|
||||
try:
|
||||
# large receive buffer used for UDP sockets, instead of just receiving
|
||||
# the 4-byte header
|
||||
data = sock.recv(4096)
|
||||
msghdr = data[:coreapi.CoreMessage.header_len]
|
||||
except KeyboardInterrupt:
|
||||
print "CTRL+C pressed"
|
||||
sys.exit(1)
|
||||
|
||||
if len(msghdr) == 0:
|
||||
return None
|
||||
|
||||
msgdata = None
|
||||
msgtype, msgflags, msglen = coreapi.CoreMessage.unpack_header(msghdr)
|
||||
|
||||
if msglen:
|
||||
msgdata = data[coreapi.CoreMessage.header_len:]
|
||||
try:
|
||||
msgcls = coreapi.CLASS_MAP[msgtype]
|
||||
except KeyError:
|
||||
msg = coreapi.CoreMessage(msgflags, msghdr, msgdata)
|
||||
msg.message_type = msgtype
|
||||
print "unimplemented CORE message type: %s" % msg.type_str()
|
||||
return msg
|
||||
if len(data) > msglen + coreapi.CoreMessage.header_len:
|
||||
print "received a message of type %d, dropping %d bytes of extra data" \
|
||||
% (msgtype, len(data) - (msglen + coreapi.CoreMessage.header_len))
|
||||
return msgcls(msgflags, msghdr, msgdata)
|
||||
|
||||
|
||||
def connect_to_session(sock, requested):
|
||||
"""
|
||||
Use Session Messages to retrieve the current list of sessions and
|
||||
connect to the first one.
|
||||
"""
|
||||
# request the session list
|
||||
tlvdata = coreapi.CoreSessionTlv.pack(SessionTlvs.NUMBER.value, "0")
|
||||
flags = MessageFlags.STRING.value
|
||||
smsg = coreapi.CoreSessionMessage.pack(flags, tlvdata)
|
||||
sock.sendall(smsg)
|
||||
|
||||
print "waiting for session list..."
|
||||
smsgreply = receive_message(sock)
|
||||
if smsgreply is None:
|
||||
print "disconnected"
|
||||
return False
|
||||
|
||||
sessstr = smsgreply.get_tlv(SessionTlvs.NUMBER.value)
|
||||
if sessstr is None:
|
||||
print "missing session numbers"
|
||||
return False
|
||||
|
||||
# join the first session (that is not our own connection)
|
||||
tmp, localport = sock.getsockname()
|
||||
sessions = sessstr.split("|")
|
||||
sessions.remove(str(localport))
|
||||
if len(sessions) == 0:
|
||||
print "no sessions to join"
|
||||
return False
|
||||
|
||||
if not requested:
|
||||
session = sessions[0]
|
||||
elif requested in sessions:
|
||||
session = requested
|
||||
else:
|
||||
print "requested session not found!"
|
||||
return False
|
||||
|
||||
print "joining session %s..." % session
|
||||
tlvdata = coreapi.CoreSessionTlv.pack(SessionTlvs.NUMBER, session)
|
||||
flags = MessageFlags.ADD
|
||||
smsg = coreapi.CoreSessionMessage.pack(flags, tlvdata)
|
||||
sock.sendall(smsg)
|
||||
return True
|
||||
|
||||
|
||||
def receive_response(sock, opt):
|
||||
"""
|
||||
Receive and print a CORE message from the given socket.
|
||||
"""
|
||||
print "waiting for response..."
|
||||
msg = receive_message(sock)
|
||||
if msg is None:
|
||||
print "disconnected from %s:%s" % (opt.address, opt.port)
|
||||
sys.exit(0)
|
||||
print "received message:", msg
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
Parse command-line arguments to build and send a CORE message.
|
||||
"""
|
||||
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 += "[message-TLVs]\n\n"
|
||||
usagestr += "Supported message types:\n %s\n" % types
|
||||
usagestr += "Supported message flags (flags=f1,f2,...):\n %s" % flags
|
||||
parser = optparse.OptionParser(usage=usagestr)
|
||||
parser.set_defaults(
|
||||
port=CORE_API_PORT,
|
||||
address="localhost",
|
||||
session=None,
|
||||
listen=False,
|
||||
examples=False,
|
||||
tlvs=False,
|
||||
tcp=False
|
||||
)
|
||||
|
||||
parser.add_option("-H", dest="examples", action="store_true",
|
||||
help="show example usage help message and exit")
|
||||
parser.add_option("-p", "--port", dest="port", type=int,
|
||||
help="TCP port to connect to, default: %d" % \
|
||||
parser.defaults["port"])
|
||||
parser.add_option("-a", "--address", dest="address", type=str,
|
||||
help="Address to connect to, default: %s" % \
|
||||
parser.defaults["address"])
|
||||
parser.add_option("-s", "--session", dest="session", type=str,
|
||||
help="Session to join, default: %s" % \
|
||||
parser.defaults["session"])
|
||||
parser.add_option("-l", "--listen", dest="listen", action="store_true",
|
||||
help="Listen for a response message and print it.")
|
||||
parser.add_option("-t", "--list-tlvs", dest="tlvs", action="store_true",
|
||||
help="List TLVs for the specified message type.")
|
||||
|
||||
def usage(msg=None, err=0):
|
||||
sys.stdout.write("\n")
|
||||
if msg:
|
||||
sys.stdout.write(msg + "\n\n")
|
||||
parser.print_help()
|
||||
sys.exit(err)
|
||||
|
||||
# parse command line opt
|
||||
opt, args = parser.parse_args()
|
||||
if opt.examples:
|
||||
print_examples(os.path.basename(sys.argv[0]))
|
||||
sys.exit(0)
|
||||
if len(args) == 0:
|
||||
usage("Please specify a message type to send.")
|
||||
|
||||
# given a message type t, determine the message and TLV classes
|
||||
t = args.pop(0)
|
||||
if t not in types:
|
||||
usage("Unknown message type requested: %s" % t)
|
||||
message_type = MessageTypes[t]
|
||||
msg_cls = coreapi.CLASS_MAP[message_type.value]
|
||||
tlv_cls = msg_cls.tlv_class
|
||||
|
||||
# list TLV types for this message type
|
||||
if opt.tlvs:
|
||||
print_available_tlvs(t, tlv_cls)
|
||||
sys.exit(0)
|
||||
|
||||
# build a message consisting of TLVs from "type=value" arguments
|
||||
flagstr = ""
|
||||
tlvdata = ""
|
||||
for a in args:
|
||||
typevalue = a.split("=")
|
||||
if len(typevalue) < 2:
|
||||
usage("Use \"type=value\" syntax instead of \"%s\"." % a)
|
||||
tlv_typestr = typevalue[0]
|
||||
tlv_valstr = "=".join(typevalue[1:])
|
||||
if tlv_typestr == "flags":
|
||||
flagstr = tlv_valstr
|
||||
continue
|
||||
|
||||
tlv_name = tlv_typestr
|
||||
tlv_type = tlv_cls[tlv_name].value
|
||||
try:
|
||||
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
|
||||
for f in flagstr.split(","):
|
||||
if f == "":
|
||||
continue
|
||||
|
||||
try:
|
||||
flag_enum = MessageFlags[f]
|
||||
n = flag_enum.value
|
||||
flags |= n
|
||||
except KeyError:
|
||||
usage("Invalid flag \"%s\"." % f)
|
||||
|
||||
msg = msg_cls.pack(flags, tlvdata)
|
||||
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock.setblocking(True)
|
||||
|
||||
try:
|
||||
sock.connect((opt.address, opt.port))
|
||||
except Exception as e:
|
||||
print "Error connecting to %s:%s:\n\t%s" % (opt.address, opt.port, e)
|
||||
sys.exit(1)
|
||||
|
||||
if not connect_to_session(sock, opt.session):
|
||||
print "warning: continuing without joining a session!"
|
||||
|
||||
sock.sendall(msg)
|
||||
if opt.listen:
|
||||
receive_response(sock, opt)
|
||||
if opt.tcp:
|
||||
sock.shutdown(socket.SHUT_RDWR)
|
||||
sock.close()
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Add table
Add a link
Reference in a new issue