further cleanup in regards the commands that are being used within core

This commit is contained in:
Blake J. Harnden 2018-03-01 16:23:58 -08:00
parent 870d87804b
commit 6211b09585
15 changed files with 322 additions and 316 deletions

View file

@ -412,33 +412,33 @@ class PyCoreNode(PyCoreObj):
return common return common
def check_cmd(self, cmd): def check_cmd(self, args):
""" """
Runs shell command on node. Runs shell command on node.
:param list[str]/str cmd: command to run :param list[str]|str args: command to run
:return: exist status and combined stdout and stderr :return: exist status and combined stdout and stderr
:rtype: tuple[int, str] :rtype: tuple[int, str]
:raises subprocess.CalledProcessError: when a non-zero exit status occurs :raises subprocess.CalledProcessError: when a non-zero exit status occurs
""" """
raise NotImplementedError raise NotImplementedError
def cmd(self, cmd, wait=True): def cmd(self, args, wait=True):
""" """
Runs shell command on node, with option to not wait for a result. Runs shell command on node, with option to not wait for a result.
:param list[str]/str cmd: command to run :param list[str]|str args: command to run
:param bool wait: wait for command to exit, defaults to True :param bool wait: wait for command to exit, defaults to True
:return: exit status for command :return: exit status for command
:rtype: int :rtype: int
""" """
raise NotImplementedError raise NotImplementedError
def cmd_output(self, cmd): def cmd_output(self, args):
""" """
Runs shell command on node and get exit status and output. Runs shell command on node and get exit status and output.
:param list[str]/str cmd: command to run :param list[str]|str args: command to run
:return: exit status and combined stdout and stderr :return: exit status and combined stdout and stderr
:rtype: tuple[int, str] :rtype: tuple[int, str]
""" """

View file

@ -21,11 +21,11 @@ def emane_version():
""" """
global VERSION global VERSION
global VERSIONSTR global VERSIONSTR
cmd = ("emane", "--version") args = ("emane", "--version")
try: try:
status, result = utils.cmd_output(cmd) status, result = utils.check_cmd(args)
except (OSError, subprocess.CalledProcessError): except subprocess.CalledProcessError:
logger.exception("error checking emane version") logger.exception("error checking emane version")
status = -1 status = -1
result = "" result = ""

View file

@ -788,7 +788,7 @@ class EmaneManager(ConfigurableManager):
the transportdaemon*.xml. the transportdaemon*.xml.
""" """
try: try:
subprocess.check_call(["emanegentransportxml", "platform.xml"], cwd=self.session.session_dir) utils.check_cmd(["emanegentransportxml", "platform.xml"], cwd=self.session.session_dir)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
logger.exception("error running emanegentransportxml") logger.exception("error running emanegentransportxml")
@ -845,23 +845,23 @@ class EmaneManager(ConfigurableManager):
if realtime: if realtime:
emanecmd += "-r", emanecmd += "-r",
try: try:
cmd = emanecmd + [os.path.join(path, "platform.xml")] args = emanecmd + [os.path.join(path, "platform.xml")]
logger.info("Emane.startdaemons() running %s" % str(cmd)) logger.info("Emane.startdaemons() running %s" % str(args))
subprocess.check_call(cmd, cwd=path) utils.check_cmd(args, cwd=path)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
logger.exception("error starting emane") logger.exception("error starting emane")
# start one transport daemon per transportdaemon*.xml file # start one transport daemon per transportdaemon*.xml file
transcmd = ["emanetransportd", "-d", "--logl", loglevel, "-f", os.path.join(path, "emanetransportd.log")] args = ["emanetransportd", "-d", "--logl", loglevel, "-f", os.path.join(path, "emanetransportd.log")]
if realtime: if realtime:
transcmd += "-r", args += "-r",
files = os.listdir(path) files = os.listdir(path)
for file in files: for file in files:
if file[-3:] == "xml" and file[:15] == "transportdaemon": if file[-3:] == "xml" and file[:15] == "transportdaemon":
cmd = transcmd + [os.path.join(path, file)] args = args + [os.path.join(path, file)]
try: try:
logger.info("Emane.startdaemons() running %s" % str(cmd)) logger.info("Emane.startdaemons() running %s" % str(args))
subprocess.check_call(cmd, cwd=path) utils.check_cmd(args, cwd=path)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
logger.exception("error starting emanetransportd") logger.exception("error starting emanetransportd")
@ -910,24 +910,24 @@ class EmaneManager(ConfigurableManager):
self.session.add_remove_control_interface(node, eventservicenetidx, remove=False, conf_required=False) self.session.add_remove_control_interface(node, eventservicenetidx, remove=False, conf_required=False)
# multicast route is needed for OTA data # multicast route is needed for OTA data
cmd = [constants.IP_BIN, "route", "add", otagroup, "dev", otadev] args = [constants.IP_BIN, "route", "add", otagroup, "dev", otadev]
try: try:
node.check_cmd(cmd) node.check_cmd(args)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
logger.exception("error adding route for OTA data") logger.exception("error adding route for OTA data")
# multicast route is also needed for event data if on control network # multicast route is also needed for event data if on control network
if eventservicenetidx >= 0 and eventgroup != otagroup: if eventservicenetidx >= 0 and eventgroup != otagroup:
cmd = [constants.IP_BIN, "route", "add", eventgroup, "dev", eventdev] args = [constants.IP_BIN, "route", "add", eventgroup, "dev", eventdev]
try: try:
node.check_cmd(cmd) node.check_cmd(args)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
logger.exception("error adding route for event data") logger.exception("error adding route for event data")
try: try:
cmd = emanecmd + ["-f", os.path.join(path, "emane%d.log" % n), os.path.join(path, "platform%d.xml" % n)] args = emanecmd + ["-f", os.path.join(path, "emane%d.log" % n), os.path.join(path, "platform%d.xml" % n)]
logger.info("Emane.startdaemons2() running %s" % str(cmd)) logger.info("Emane.startdaemons2() running %s" % str(args))
status, output = node.check_cmd(cmd) status, output = node.check_cmd(args)
logger.info("Emane.startdaemons2() return code %d" % status) logger.info("Emane.startdaemons2() return code %d" % status)
logger.info("Emane.startdaemons2() output: %s" % output) logger.info("Emane.startdaemons2() output: %s" % output)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
@ -939,9 +939,9 @@ class EmaneManager(ConfigurableManager):
path = self.session.session_dir path = self.session.session_dir
try: try:
emanecmd += ["-f", os.path.join(path, "emane.log")] emanecmd += ["-f", os.path.join(path, "emane.log")]
cmd = emanecmd + [os.path.join(path, "platform.xml")] args = emanecmd + [os.path.join(path, "platform.xml")]
logger.info("Emane.startdaemons2() running %s" % cmd) logger.info("Emane.startdaemons2() running %s" % args)
utils.check_cmd(cmd, cwd=path) utils.check_cmd(args, cwd=path)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
logger.exception("error starting emane") logger.exception("error starting emane")
@ -951,7 +951,7 @@ class EmaneManager(ConfigurableManager):
""" """
# TODO: we may want to improve this if we had the PIDs from the # TODO: we may want to improve this if we had the PIDs from the
# specific EMANE daemons that we"ve started # specific EMANE daemons that we"ve started
cmd = ["killall", "-q", "emane"] args = ["killall", "-q", "emane"]
stop_emane_on_host = False stop_emane_on_host = False
if emane.VERSION > emane.EMANE091: if emane.VERSION > emane.EMANE091:
for node in self.getnodes(): for node in self.getnodes():
@ -960,13 +960,17 @@ class EmaneManager(ConfigurableManager):
stop_emane_on_host = True stop_emane_on_host = True
continue continue
if node.up: if node.up:
node.cmd(cmd, wait=False) node.cmd(args, wait=False)
# TODO: RJ45 node # TODO: RJ45 node
else: else:
stop_emane_on_host = True stop_emane_on_host = True
if stop_emane_on_host: if stop_emane_on_host:
subprocess.call(cmd) try:
subprocess.call(["killall", "-q", "emanetransportd"]) utils.check_cmd(args)
utils.check_cmd(["killall", "-q", "emanetransportd"])
except subprocess.CalledProcessError:
logger.exception("error shutting down emane daemons")
def installnetifs(self, do_netns=True): def installnetifs(self, do_netns=True):
""" """
@ -1160,13 +1164,13 @@ class EmaneManager(ConfigurableManager):
is running, False otherwise. is running, False otherwise.
""" """
status = -1 status = -1
cmd = ["pkill", "-0", "-x", "emane"] args = ["pkill", "-0", "-x", "emane"]
try: try:
if emane.VERSION < emane.EMANE092: if emane.VERSION < emane.EMANE092:
status = subprocess.check_call(cmd) status = utils.check_cmd(args)
else: else:
status, _ = node.check_cmd(cmd) status, _ = node.check_cmd(args)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
logger.exception("error checking if emane is running") logger.exception("error checking if emane is running")

View file

@ -14,6 +14,8 @@ import resource
from core import logger from core import logger
DEVNULL = open(os.devnull, "wb")
def closeonexec(fd): def closeonexec(fd):
""" """
@ -112,18 +114,18 @@ def maketuplefromstr(s, value_type):
return tuple(value_type(i) for i in values) return tuple(value_type(i) for i in values)
def split_cmd(cmd): def split_args(args):
""" """
Convenience method for splitting potential string commands into a shell-like syntax list. Convenience method for splitting potential string commands into a shell-like syntax list.
:param list/str cmd: command list or string :param list/str args: command list or string
:return: shell-like syntax list :return: shell-like syntax list
:rtype: list :rtype: list
""" """
# split shell string to shell array for convenience # split shell string to shell array for convenience
if type(cmd) == str: if type(args) == str:
cmd = shlex.split(cmd) args = shlex.split(args)
return cmd return args
def mutecall(*args, **kwargs): def mutecall(*args, **kwargs):
@ -135,25 +137,11 @@ def mutecall(*args, **kwargs):
:return: command result :return: command result
:rtype: int :rtype: int
""" """
kwargs["stdout"] = open(os.devnull, "w") kwargs["stdout"] = DEVNULL
kwargs["stderr"] = subprocess.STDOUT kwargs["stderr"] = subprocess.STDOUT
return subprocess.call(*args, **kwargs) return subprocess.call(*args, **kwargs)
def check_alloutput(cmd, **kwargs):
"""
Convenience wrapper to run subprocess.check_output and include stderr as well.
:param list[str]/str cmd: command arguments to run
:param dict kwargs: option for running subprocess.check_output, beyond setting stderr to stdout
:return: combined stdout and stderr
:raises subprocess.CalledProcessError: when a non-zero exit status is encountered
"""
cmd = split_cmd(cmd)
kwargs["stderr"] = subprocess.STDOUT
return subprocess.check_output(cmd, **kwargs)
def mutecheck_call(*args, **kwargs): def mutecheck_call(*args, **kwargs):
""" """
Run a muted check call command. Run a muted check call command.
@ -163,7 +151,7 @@ def mutecheck_call(*args, **kwargs):
:return: command result :return: command result
:rtype: int :rtype: int
""" """
kwargs["stdout"] = open(os.devnull, "w") kwargs["stdout"] = DEVNULL
kwargs["stderr"] = subprocess.STDOUT kwargs["stderr"] = subprocess.STDOUT
return subprocess.check_call(*args, **kwargs) return subprocess.check_call(*args, **kwargs)
@ -189,7 +177,7 @@ def mutespawn(*args, **kwargs):
:return: process id of the command :return: process id of the command
:rtype: int :rtype: int
""" """
kwargs["stdout"] = open(os.devnull, "w") kwargs["stdout"] = DEVNULL
kwargs["stderr"] = subprocess.STDOUT kwargs["stderr"] = subprocess.STDOUT
return subprocess.Popen(*args, **kwargs).pid return subprocess.Popen(*args, **kwargs).pid
@ -229,48 +217,73 @@ def mutedetach(*args, **kwargs):
:rtype: int :rtype: int
""" """
kwargs["preexec_fn"] = detachinit kwargs["preexec_fn"] = detachinit
kwargs["stdout"] = open(os.devnull, "w") kwargs["stdout"] = DEVNULL
kwargs["stderr"] = subprocess.STDOUT kwargs["stderr"] = subprocess.STDOUT
return subprocess.Popen(*args, **kwargs).pid return subprocess.Popen(*args, **kwargs).pid
def cmd_output(cmd): def cmd(args, wait=True):
"""
Runs a command on and returns the exit status.
:param list[str]|str args: command arguments
:param bool wait: wait for command to end or not
:return: command status
:rtype: int
"""
args = split_args(args)
try:
p = subprocess.Popen(args)
if not wait:
return 0
return p.wait()
except OSError:
raise subprocess.CalledProcessError(-1, args)
def cmd_output(args):
""" """
Execute a command on the host and return a tuple containing the exit status and result string. stderr output Execute a command on the host and return a tuple containing the exit status and result string. stderr output
is folded into the stdout result string. is folded into the stdout result string.
:param list[str]/str cmd: command arguments :param list[str]|str args: command arguments
:return: command status and stdout :return: command status and stdout
:rtype: tuple[int, str] :rtype: tuple[int, str]
:raises subprocess.CalledProcessError: when the file to execute is not found
""" """
# split shell string to shell array for convenience args = split_args(args)
cmd = split_cmd(cmd) try:
p = subprocess.Popen(cmd, stdin=open(os.devnull, "r"), stdout=subprocess.PIPE, stderr=subprocess.STDOUT) p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout, _ = p.communicate() stdout, _ = p.communicate()
status = p.wait() status = p.wait()
return status, stdout return status, stdout
except OSError:
raise subprocess.CalledProcessError(-1, args)
def check_cmd(cmd, **kwargs): def check_cmd(args, **kwargs):
""" """
Execute a command on the host and return a tuple containing the exit status and result string. stderr output Execute a command on the host and return a tuple containing the exit status and result string. stderr output
is folded into the stdout result string. is folded into the stdout result string.
:param list[str]/str cmd: command arguments :param list[str]|str args: command arguments
:param dict kwargs: keyword arguments to pass to subprocess.Popen :param dict kwargs: keyword arguments to pass to subprocess.Popen
:return: command status and stdout :return: command status and stdout
:rtype: tuple[int, str] :rtype: tuple[int, str]
:raises subprocess.CalledProcessError: when there is a non-zero exit status :raises subprocess.CalledProcessError: when there is a non-zero exit status or the file to execute is not found
""" """
kwargs["stdout"] = subprocess.PIPE kwargs["stdout"] = subprocess.PIPE
kwargs["stderr"] = subprocess.STDOUT kwargs["stderr"] = subprocess.STDOUT
cmd = split_cmd(cmd) args = split_args(args)
p = subprocess.Popen(cmd, **kwargs) try:
stdout, _ = p.communicate() p = subprocess.Popen(args, **kwargs)
status = p.wait() stdout, _ = p.communicate()
if status: status = p.wait()
raise subprocess.CalledProcessError(status, cmd, stdout) if status:
return status, stdout raise subprocess.CalledProcessError(status, args, stdout)
return status, stdout
except OSError:
raise subprocess.CalledProcessError(-1, args)
def hexdump(s, bytes_per_word=2, words_per_line=8): def hexdump(s, bytes_per_word=2, words_per_line=8):

View file

@ -21,6 +21,7 @@ from core.enumerations import MessageFlags
from core.enumerations import MessageTypes from core.enumerations import MessageTypes
from core.enumerations import NodeTlvs from core.enumerations import NodeTlvs
from core.enumerations import RegisterTlvs from core.enumerations import RegisterTlvs
from core.misc import utils
from core.misc.ipaddress import IpAddress from core.misc.ipaddress import IpAddress
@ -1238,10 +1239,7 @@ class Ns2ScriptedMobility(WayPointMobility):
return return
filename = self.findfile(filename) filename = self.findfile(filename)
try: try:
subprocess.check_call( args = ["/bin/sh", filename, typestr]
["/bin/sh", filename, typestr], utils.check_cmd(args, cwd=self.session.sessiondir, env=self.session.get_environment())
cwd=self.session.sessiondir,
env=self.session.get_environment()
)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
logger.exception("Error running script '%s' for WLAN state %s", filename, typestr) logger.exception("Error running script '%s' for WLAN state %s", filename, typestr)

View file

@ -73,26 +73,31 @@ class CtrlNet(LxBrNet):
return return
LxBrNet.startup(self) LxBrNet.startup(self)
if self.hostid: if self.hostid:
addr = self.prefix.addr(self.hostid) addr = self.prefix.addr(self.hostid)
else: else:
addr = self.prefix.max_addr() addr = self.prefix.max_addr()
msg = "Added control network bridge: %s %s" % (self.brname, self.prefix) msg = "Added control network bridge: %s %s" % (self.brname, self.prefix)
addrlist = ["%s/%s" % (addr, self.prefix.prefixlen)] addrlist = ["%s/%s" % (addr, self.prefix.prefixlen)]
if self.assign_address: if self.assign_address:
self.addrconfig(addrlist=addrlist) self.addrconfig(addrlist=addrlist)
msg += " address %s" % addr msg += " address %s" % addr
logger.info(msg) logger.info(msg)
if self.updown_script is not None: if self.updown_script is not None:
logger.info("interface %s updown script (%s startup) called", logger.info("interface %s updown script (%s startup) called",
self.brname, self.updown_script) self.brname, self.updown_script)
subprocess.check_call([self.updown_script, self.brname, "startup"]) utils.check_cmd([self.updown_script, self.brname, "startup"])
if self.serverintf is not None: if self.serverintf is not None:
try: try:
subprocess.check_call([constants.BRCTL_BIN, "addif", self.brname, self.serverintf]) utils.check_cmd([constants.BRCTL_BIN, "addif", self.brname, self.serverintf])
subprocess.check_call([constants.IP_BIN, "link", "set", self.serverintf, "up"]) utils.check_cmd([constants.IP_BIN, "link", "set", self.serverintf, "up"])
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
logger.exception("Error joining server interface %s to controlnet bridge %s", logger.exception("error joining server interface %s to controlnet bridge %s",
self.serverintf, self.brname) self.serverintf, self.brname)
def detectoldbridge(self): def detectoldbridge(self):
@ -103,32 +108,24 @@ class CtrlNet(LxBrNet):
:return: True if an old bridge was detected, False otherwise :return: True if an old bridge was detected, False otherwise
:rtype: bool :rtype: bool
""" """
retstat, retstr = utils.cmd_output([constants.BRCTL_BIN, "show"]) status, output = utils.cmd_output([constants.BRCTL_BIN, "show"])
if retstat != 0: if status != 0:
logger.error("Unable to retrieve list of installed bridges") logger.error("Unable to retrieve list of installed bridges")
lines = retstr.split("\n") else:
for line in lines[1:]: lines = output.split("\n")
cols = line.split("\t") for line in lines[1:]:
oldbr = cols[0] cols = line.split("\t")
flds = cols[0].split(".") oldbr = cols[0]
if len(flds) == 3: flds = cols[0].split(".")
if flds[0] == "b" and flds[1] == self.objid: if len(flds) == 3:
logger.error( if flds[0] == "b" and flds[1] == self.objid:
"Error: An active control net bridge (%s) found. " \ logger.error(
"An older session might still be running. " \ "Error: An active control net bridge (%s) found. "
"Stop all sessions and, if needed, delete %s to continue." % \ "An older session might still be running. "
(oldbr, oldbr) "Stop all sessions and, if needed, delete %s to continue." %
) (oldbr, oldbr)
return True )
""" return True
# Do this if we want to delete the old bridge
logger.warn("Warning: Old %s bridge found: %s" % (self.objid, oldbr))
try:
check_call([BRCTL_BIN, "delbr", oldbr])
except subprocess.CalledProcessError as e:
logger.exception("Error deleting old bridge %s", oldbr, e)
logger.info("Deleted %s", oldbr)
"""
return False return False
def shutdown(self): def shutdown(self):
@ -139,14 +136,14 @@ class CtrlNet(LxBrNet):
""" """
if self.serverintf is not None: if self.serverintf is not None:
try: try:
subprocess.check_call([constants.BRCTL_BIN, "delif", self.brname, self.serverintf]) utils.check_cmd([constants.BRCTL_BIN, "delif", self.brname, self.serverintf])
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
logger.exception("Error deleting server interface %s to controlnet bridge %s", logger.exception("error deleting server interface %s to controlnet bridge %s",
self.serverintf, self.brname) self.serverintf, self.brname)
if self.updown_script is not None: if self.updown_script is not None:
logger.info("interface %s updown script (%s shutdown) called" % (self.brname, self.updown_script)) logger.info("interface %s updown script (%s shutdown) called" % (self.brname, self.updown_script))
subprocess.check_call([self.updown_script, self.brname, "shutdown"]) utils.check_cmd([self.updown_script, self.brname, "shutdown"])
LxBrNet.shutdown(self) LxBrNet.shutdown(self)
def all_link_data(self, flags): def all_link_data(self, flags):
@ -324,7 +321,7 @@ class HubNode(LxBrNet):
""" """
LxBrNet.__init__(self, session, objid, name, start) LxBrNet.__init__(self, session, objid, name, start)
if start: if start:
subprocess.check_call([constants.BRCTL_BIN, "setageing", self.brname, "0"]) utils.check_cmd([constants.BRCTL_BIN, "setageing", self.brname, "0"])
class WlanNode(LxBrNet): class WlanNode(LxBrNet):
@ -457,6 +454,8 @@ class RJ45Node(PyCoreNode, PyCoreNetIf):
# the following are PyCoreNetIf attributes # the following are PyCoreNetIf attributes
self.transport_type = "raw" self.transport_type = "raw"
self.localname = name self.localname = name
self.old_up = False
self.old_addrs = []
if start: if start:
self.startup() self.startup()
@ -470,7 +469,7 @@ class RJ45Node(PyCoreNode, PyCoreNetIf):
self.savestate() self.savestate()
try: try:
subprocess.check_call([constants.IP_BIN, "link", "set", self.localname, "up"]) utils.check_cmd([constants.IP_BIN, "link", "set", self.localname, "up"])
self.up = True self.up = True
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
logger.exception("failed to run command: %s link set %s up", constants.IP_BIN, self.localname) logger.exception("failed to run command: %s link set %s up", constants.IP_BIN, self.localname)
@ -484,9 +483,14 @@ class RJ45Node(PyCoreNode, PyCoreNetIf):
""" """
if not self.up: if not self.up:
return return
subprocess.check_call([constants.IP_BIN, "link", "set", self.localname, "down"])
subprocess.check_call([constants.IP_BIN, "addr", "flush", "dev", self.localname]) try:
utils.mutecall([constants.TC_BIN, "qdisc", "del", "dev", self.localname, "root"]) utils.check_cmd([constants.IP_BIN, "link", "set", self.localname, "down"])
utils.check_cmd([constants.IP_BIN, "addr", "flush", "dev", self.localname])
utils.mutecall([constants.TC_BIN, "qdisc", "del", "dev", self.localname, "root"])
except subprocess.CalledProcessError as e:
logger.exception("error shutting down: %s", e.output)
self.up = False self.up = False
self.restorestate() self.restorestate()
@ -604,7 +608,7 @@ class RJ45Node(PyCoreNode, PyCoreNetIf):
:return: nothing :return: nothing
""" """
if self.up: if self.up:
subprocess.check_call([constants.IP_BIN, "addr", "add", str(addr), "dev", self.name]) utils.check_cmd([constants.IP_BIN, "addr", "add", str(addr), "dev", self.name])
PyCoreNetIf.addaddr(self, addr) PyCoreNetIf.addaddr(self, addr)
def deladdr(self, addr): def deladdr(self, addr):
@ -615,7 +619,7 @@ class RJ45Node(PyCoreNode, PyCoreNetIf):
:return: nothing :return: nothing
""" """
if self.up: if self.up:
subprocess.check_call([constants.IP_BIN, "addr", "del", str(addr), "dev", self.name]) utils.check_cmd([constants.IP_BIN, "addr", "del", str(addr), "dev", self.name])
PyCoreNetIf.deladdr(self, addr) PyCoreNetIf.deladdr(self, addr)
def savestate(self): def savestate(self):
@ -627,30 +631,26 @@ class RJ45Node(PyCoreNode, PyCoreNetIf):
""" """
self.old_up = False self.old_up = False
self.old_addrs = [] self.old_addrs = []
cmd = [constants.IP_BIN, "addr", "show", "dev", self.localname] args = [constants.IP_BIN, "addr", "show", "dev", self.localname]
try: try:
tmp = subprocess.Popen(cmd, stdout=subprocess.PIPE) _, output = utils.check_cmd(args)
except OSError: for line in output.split("\n"):
logger.exception("Failed to run %s command: %s", constants.IP_BIN, cmd) items = line.split()
if tmp.wait(): if len(items) < 2:
logger.warn("Command failed: %s", cmd)
return
lines = tmp.stdout.read()
tmp.stdout.close()
for l in lines.split("\n"):
items = l.split()
if len(items) < 2:
continue
if items[1] == "%s:" % self.localname:
flags = items[2][1:-1].split(",")
if "UP" in flags:
self.old_up = True
elif items[0] == "inet":
self.old_addrs.append((items[1], items[3]))
elif items[0] == "inet6":
if items[1][:4] == "fe80":
continue continue
self.old_addrs.append((items[1], None))
if items[1] == "%s:" % self.localname:
flags = items[2][1:-1].split(",")
if "UP" in flags:
self.old_up = True
elif items[0] == "inet":
self.old_addrs.append((items[1], items[3]))
elif items[0] == "inet6":
if items[1][:4] == "fe80":
continue
self.old_addrs.append((items[1], None))
except subprocess.CalledProcessError:
logger.exception("error during save state")
def restorestate(self): def restorestate(self):
""" """
@ -660,11 +660,12 @@ class RJ45Node(PyCoreNode, PyCoreNetIf):
""" """
for addr in self.old_addrs: for addr in self.old_addrs:
if addr[1] is None: if addr[1] is None:
subprocess.check_call([constants.IP_BIN, "addr", "add", addr[0], "dev", self.localname]) utils.check_cmd([constants.IP_BIN, "addr", "add", addr[0], "dev", self.localname])
else: else:
subprocess.check_call([constants.IP_BIN, "addr", "add", addr[0], "brd", addr[1], "dev", self.localname]) utils.check_cmd([constants.IP_BIN, "addr", "add", addr[0], "brd", addr[1], "dev", self.localname])
if self.old_up: if self.old_up:
subprocess.check_call([constants.IP_BIN, "link", "set", self.localname, "up"]) utils.check_cmd([constants.IP_BIN, "link", "set", self.localname, "up"])
def setposition(self, x=None, y=None, z=None): def setposition(self, x=None, y=None, z=None):
""" """

View file

@ -82,18 +82,18 @@ class OvsNet(PyCoreNet):
def startup(self): def startup(self):
try: try:
subprocess.check_call([constants.OVS_BIN, "add-br", self.bridge_name]) utils.check_cmd([constants.OVS_BIN, "add-br", self.bridge_name])
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
logger.exception("error adding bridge") logger.exception("error adding bridge")
try: try:
# turn off spanning tree protocol and forwarding delay # turn off spanning tree protocol and forwarding delay
# TODO: appears stp and rstp are off by default, make sure this always holds true # TODO: appears stp and rstp are off by default, make sure this always holds true
# TODO: apears ovs only supports rstp forward delay and again it"s off by default # TODO: apears ovs only supports rstp forward delay and again it's off by default
subprocess.check_call([constants.IP_BIN, "link", "set", self.bridge_name, "up"]) utils.check_cmd([constants.IP_BIN, "link", "set", self.bridge_name, "up"])
# create a new ebtables chain for this bridge # create a new ebtables chain for this bridge
ebtables_commands(subprocess.check_call, [ ebtables_commands(utils.check_cmd, [
[constants.EBTABLES_BIN, "-N", self.bridge_name, "-P", self.policy], [constants.EBTABLES_BIN, "-N", self.bridge_name, "-P", self.policy],
[constants.EBTABLES_BIN, "-A", "FORWARD", "--logical-in", self.bridge_name, "-j", self.bridge_name] [constants.EBTABLES_BIN, "-A", "FORWARD", "--logical-in", self.bridge_name, "-j", self.bridge_name]
]) ])
@ -129,8 +129,8 @@ class OvsNet(PyCoreNet):
def attach(self, interface): def attach(self, interface):
if self.up: if self.up:
try: try:
subprocess.check_call([constants.OVS_BIN, "add-port", self.bridge_name, interface.localname]) utils.check_cmd([constants.OVS_BIN, "add-port", self.bridge_name, interface.localname])
subprocess.check_call([constants.IP_BIN, "link", "set", interface.localname, "up"]) utils.check_cmd([constants.IP_BIN, "link", "set", interface.localname, "up"])
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
logger.exception("error joining interface %s to bridge %s", interface.localname, self.bridge_name) logger.exception("error joining interface %s to bridge %s", interface.localname, self.bridge_name)
return return
@ -140,7 +140,7 @@ class OvsNet(PyCoreNet):
def detach(self, interface): def detach(self, interface):
if self.up: if self.up:
try: try:
subprocess.check_call([constants.OVS_BIN, "del-port", self.bridge_name, interface.localname]) utils.check_cmd([constants.OVS_BIN, "del-port", self.bridge_name, interface.localname])
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
logger.exception("error removing interface %s from bridge %s", interface.localname, self.bridge_name) logger.exception("error removing interface %s from bridge %s", interface.localname, self.bridge_name)
return return
@ -217,14 +217,14 @@ class OvsNet(PyCoreNet):
limit = 0xffff # max IP payload limit = 0xffff # max IP payload
tbf = ["tbf", "rate", str(bw), "burst", str(burst), "limit", str(limit)] tbf = ["tbf", "rate", str(bw), "burst", str(burst), "limit", str(limit)]
logger.info("linkconfig: %s" % [tc + parent + ["handle", "1:"] + tbf]) logger.info("linkconfig: %s" % [tc + parent + ["handle", "1:"] + tbf])
subprocess.check_call(tc + parent + ["handle", "1:"] + tbf) utils.check_cmd(tc + parent + ["handle", "1:"] + tbf)
interface.setparam("has_tbf", True) interface.setparam("has_tbf", True)
elif interface.getparam("has_tbf") and bw <= 0: elif interface.getparam("has_tbf") and bw <= 0:
tcd = [] + tc tcd = [] + tc
tcd[2] = "delete" tcd[2] = "delete"
if self.up: if self.up:
subprocess.check_call(tcd + parent) utils.check_cmd(tcd + parent)
interface.setparam("has_tbf", False) interface.setparam("has_tbf", False)
# removing the parent removes the child # removing the parent removes the child
@ -273,12 +273,12 @@ class OvsNet(PyCoreNet):
if self.up: if self.up:
logger.info("linkconfig: %s" % ([tc + parent + ["handle", "10:"]],)) logger.info("linkconfig: %s" % ([tc + parent + ["handle", "10:"]],))
subprocess.check_call(tc + parent + ["handle", "10:"]) utils.check_cmd(tc + parent + ["handle", "10:"])
interface.setparam("has_netem", False) interface.setparam("has_netem", False)
elif len(netem) > 1: elif len(netem) > 1:
if self.up: if self.up:
logger.info("linkconfig: %s" % ([tc + parent + ["handle", "10:"] + netem],)) logger.info("linkconfig: %s" % ([tc + parent + ["handle", "10:"] + netem],))
subprocess.check_call(tc + parent + ["handle", "10:"] + netem) utils.check_cmd(tc + parent + ["handle", "10:"] + netem)
interface.setparam("has_netem", True) interface.setparam("has_netem", True)
def linknet(self, network): def linknet(self, network):
@ -312,8 +312,8 @@ class OvsNet(PyCoreNet):
if network.up: if network.up:
# this is similar to net.attach() but uses netif.name instead # this is similar to net.attach() but uses netif.name instead
# of localname # of localname
subprocess.check_call([constants.OVS_BIN, "add-port", network.bridge_name, interface.name]) utils.check_cmd([constants.OVS_BIN, "add-port", network.bridge_name, interface.name])
subprocess.check_call([constants.IP_BIN, "link", "set", interface.name, "up"]) utils.check_cmd([constants.IP_BIN, "link", "set", interface.name, "up"])
# TODO: is there a native method for this? see if this causes issues # TODO: is there a native method for this? see if this causes issues
# i = network.newifindex() # i = network.newifindex()
@ -347,7 +347,7 @@ class OvsNet(PyCoreNet):
for address in addresses: for address in addresses:
try: try:
subprocess.check_call([constants.IP_BIN, "addr", "add", str(address), "dev", self.bridge_name]) utils.check_cmd([constants.IP_BIN, "addr", "add", str(address), "dev", self.bridge_name])
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
logger.exception("error adding IP address") logger.exception("error adding IP address")
@ -390,12 +390,12 @@ class OvsCtrlNet(OvsNet):
if self.updown_script: if self.updown_script:
logger.info("interface %s updown script %s startup called" % (self.bridge_name, self.updown_script)) logger.info("interface %s updown script %s startup called" % (self.bridge_name, self.updown_script))
subprocess.check_call([self.updown_script, self.bridge_name, "startup"]) utils.check_cmd([self.updown_script, self.bridge_name, "startup"])
if self.serverintf: if self.serverintf:
try: try:
subprocess.check_call([constants.OVS_BIN, "add-port", self.bridge_name, self.serverintf]) utils.check_cmd([constants.OVS_BIN, "add-port", self.bridge_name, self.serverintf])
subprocess.check_call([constants.IP_BIN, "link", "set", self.serverintf, "up"]) utils.check_cmd([constants.IP_BIN, "link", "set", self.serverintf, "up"])
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
logger.exception("error joining server interface %s to controlnet bridge %s", logger.exception("error joining server interface %s to controlnet bridge %s",
self.serverintf, self.bridge_name) self.serverintf, self.bridge_name)
@ -420,14 +420,14 @@ class OvsCtrlNet(OvsNet):
def shutdown(self): def shutdown(self):
if self.serverintf: if self.serverintf:
try: try:
subprocess.check_call([constants.OVS_BIN, "del-port", self.bridge_name, self.serverintf]) utils.check_cmd([constants.OVS_BIN, "del-port", self.bridge_name, self.serverintf])
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
logger.exception("Error deleting server interface %s to controlnet bridge %s", logger.exception("Error deleting server interface %s to controlnet bridge %s",
self.serverintf, self.bridge_name) self.serverintf, self.bridge_name)
if self.updown_script: if self.updown_script:
logger.info("interface %s updown script (%s shutdown) called", self.bridge_name, self.updown_script) logger.info("interface %s updown script (%s shutdown) called", self.bridge_name, self.updown_script)
subprocess.check_call([self.updown_script, self.bridge_name, "shutdown"]) utils.check_cmd([self.updown_script, self.bridge_name, "shutdown"])
OvsNet.shutdown(self) OvsNet.shutdown(self)
@ -576,7 +576,7 @@ class OvsHubNode(OvsNet):
if start: if start:
# TODO: verify that the below flow accomplishes what is desired for a "HUB" # TODO: verify that the below flow accomplishes what is desired for a "HUB"
# TODO: replace "brctl setageing 0" # TODO: replace "brctl setageing 0"
subprocess.check_call([constants.OVS_FLOW_BIN, "add-flow", self.bridge_name, "action=flood"]) utils.check_cmd([constants.OVS_FLOW_BIN, "add-flow", self.bridge_name, "action=flood"])
class OvsWlanNode(OvsNet): class OvsWlanNode(OvsNet):

View file

@ -46,9 +46,9 @@ class VEth(PyCoreNetIf):
:return: nothing :return: nothing
""" """
subprocess.check_call([constants.IP_BIN, "link", "add", "name", self.localname, utils.check_cmd([constants.IP_BIN, "link", "add", "name", self.localname,
"type", "veth", "peer", "name", self.name]) "type", "veth", "peer", "name", self.name])
subprocess.check_call([constants.IP_BIN, "link", "set", self.localname, "up"]) utils.check_cmd([constants.IP_BIN, "link", "set", self.localname, "up"])
self.up = True self.up = True
def shutdown(self): def shutdown(self):
@ -164,8 +164,8 @@ class TunTap(PyCoreNetIf):
""" """
def localdevexists(): def localdevexists():
cmd = (constants.IP_BIN, "link", "show", self.localname) args = (constants.IP_BIN, "link", "show", self.localname)
return utils.mutecall(cmd) return utils.mutecall(args)
self.waitfor(localdevexists) self.waitfor(localdevexists)
@ -177,8 +177,8 @@ class TunTap(PyCoreNetIf):
""" """
def nodedevexists(): def nodedevexists():
cmd = [constants.IP_BIN, "link", "show", self.name] args = [constants.IP_BIN, "link", "show", self.name]
return self.node.cmd(cmd) return self.node.cmd(args)
count = 0 count = 0
while True: while True:
@ -268,17 +268,17 @@ class GreTap(PyCoreNetIf):
if remoteip is None: if remoteip is None:
raise ValueError, "missing remote IP required for GRE TAP device" raise ValueError, "missing remote IP required for GRE TAP device"
cmd = ("ip", "link", "add", self.localname, "type", "gretap", args = ("ip", "link", "add", self.localname, "type", "gretap",
"remote", str(remoteip)) "remote", str(remoteip))
if localip: if localip:
cmd += ("local", str(localip)) args += ("local", str(localip))
if ttl: if ttl:
cmd += ("ttl", str(ttl)) args += ("ttl", str(ttl))
if key: if key:
cmd += ("key", str(key)) args += ("key", str(key))
subprocess.check_call(cmd) utils.check_cmd(args)
cmd = ("ip", "link", "set", self.localname, "up") args = ("ip", "link", "set", self.localname, "up")
subprocess.check_call(cmd) utils.check_cmd(args)
self.up = True self.up = True
def shutdown(self): def shutdown(self):
@ -288,10 +288,10 @@ class GreTap(PyCoreNetIf):
:return: nothing :return: nothing
""" """
if self.localname: if self.localname:
cmd = ("ip", "link", "set", self.localname, "down") args = ("ip", "link", "set", self.localname, "down")
subprocess.check_call(cmd) utils.check_cmd(args)
cmd = ("ip", "link", "del", self.localname) args = ("ip", "link", "del", self.localname)
subprocess.check_call(cmd) utils.check_cmd(args)
self.localname = None self.localname = None
def data(self, message_type): def data(self, message_type):

View file

@ -165,30 +165,30 @@ class EbtablesQueue(object):
:return: nothing :return: nothing
""" """
# save kernel ebtables snapshot to a file # save kernel ebtables snapshot to a file
cmd = self.ebatomiccmd(["--atomic-save", ]) args = self.ebatomiccmd(["--atomic-save", ])
try: try:
subprocess.check_call(cmd) utils.check_cmd(args)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
logger.exception("atomic-save (%s)", cmd) logger.exception("atomic-save (%s)", args)
# no atomic file, exit # no atomic file, exit
return return
# modify the table file using queued ebtables commands # modify the table file using queued ebtables commands
for c in self.cmds: for c in self.cmds:
cmd = self.ebatomiccmd(c) args = self.ebatomiccmd(c)
try: try:
subprocess.check_call(cmd) utils.check_cmd(args)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
logger.exception("cmd=%s", cmd) logger.exception("cmd=%s", args)
self.cmds = [] self.cmds = []
# commit the table file to the kernel # commit the table file to the kernel
cmd = self.ebatomiccmd(["--atomic-commit", ]) args = self.ebatomiccmd(["--atomic-commit", ])
try: try:
subprocess.check_call(cmd) utils.check_cmd(args)
os.unlink(self.atomic_file) os.unlink(self.atomic_file)
except OSError: except OSError:
logger.exception("atomic-commit (%s)", cmd) logger.exception("atomic-commit (%s)", args)
def ebchange(self, wlan): def ebchange(self, wlan):
""" """
@ -241,8 +241,8 @@ def ebtablescmds(call, cmds):
:return: nothing :return: nothing
""" """
with ebtables_lock: with ebtables_lock:
for cmd in cmds: for args in cmds:
call(cmd) call(args)
class LxBrNet(PyCoreNet): class LxBrNet(PyCoreNet):
@ -281,17 +281,17 @@ class LxBrNet(PyCoreNet):
:return: nothing :return: nothing
""" """
try: try:
subprocess.check_call([constants.BRCTL_BIN, "addbr", self.brname]) utils.check_cmd([constants.BRCTL_BIN, "addbr", self.brname])
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
logger.exception("Error adding bridge") logger.exception("Error adding bridge")
try: try:
# turn off spanning tree protocol and forwarding delay # turn off spanning tree protocol and forwarding delay
subprocess.check_call([constants.BRCTL_BIN, "stp", self.brname, "off"]) utils.check_cmd([constants.BRCTL_BIN, "stp", self.brname, "off"])
subprocess.check_call([constants.BRCTL_BIN, "setfd", self.brname, "0"]) utils.check_cmd([constants.BRCTL_BIN, "setfd", self.brname, "0"])
subprocess.check_call([constants.IP_BIN, "link", "set", self.brname, "up"]) utils.check_cmd([constants.IP_BIN, "link", "set", self.brname, "up"])
# create a new ebtables chain for this bridge # create a new ebtables chain for this bridge
ebtablescmds(subprocess.check_call, [ ebtablescmds(utils.check_cmd, [
[constants.EBTABLES_BIN, "-N", self.brname, "-P", self.policy], [constants.EBTABLES_BIN, "-N", self.brname, "-P", self.policy],
[constants.EBTABLES_BIN, "-A", "FORWARD", "--logical-in", self.brname, "-j", self.brname] [constants.EBTABLES_BIN, "-A", "FORWARD", "--logical-in", self.brname, "-j", self.brname]
]) ])
@ -336,8 +336,8 @@ class LxBrNet(PyCoreNet):
""" """
if self.up: if self.up:
try: try:
subprocess.check_call([constants.BRCTL_BIN, "addif", self.brname, netif.localname]) utils.check_cmd([constants.BRCTL_BIN, "addif", self.brname, netif.localname])
subprocess.check_call([constants.IP_BIN, "link", "set", netif.localname, "up"]) utils.check_cmd([constants.IP_BIN, "link", "set", netif.localname, "up"])
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
logger.exception("Error joining interface %s to bridge %s", netif.localname, self.brname) logger.exception("Error joining interface %s to bridge %s", netif.localname, self.brname)
return return
@ -352,7 +352,7 @@ class LxBrNet(PyCoreNet):
""" """
if self.up: if self.up:
try: try:
subprocess.check_call([constants.BRCTL_BIN, "delif", self.brname, netif.localname]) utils.check_cmd([constants.BRCTL_BIN, "delif", self.brname, netif.localname])
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
logger.exception("Error removing interface %s from bridge %s", netif.localname, self.brname) logger.exception("Error removing interface %s from bridge %s", netif.localname, self.brname)
return return
@ -452,14 +452,14 @@ class LxBrNet(PyCoreNet):
if bw > 0: if bw > 0:
if self.up: if self.up:
logger.info("linkconfig: %s" % ([tc + parent + ["handle", "1:"] + tbf],)) logger.info("linkconfig: %s" % ([tc + parent + ["handle", "1:"] + tbf],))
subprocess.check_call(tc + parent + ["handle", "1:"] + tbf) utils.check_cmd(tc + parent + ["handle", "1:"] + tbf)
netif.setparam("has_tbf", True) netif.setparam("has_tbf", True)
changed = True changed = True
elif netif.getparam("has_tbf") and bw <= 0: elif netif.getparam("has_tbf") and bw <= 0:
tcd = [] + tc tcd = [] + tc
tcd[2] = "delete" tcd[2] = "delete"
if self.up: if self.up:
subprocess.check_call(tcd + parent) utils.check_cmd(tcd + parent)
netif.setparam("has_tbf", False) netif.setparam("has_tbf", False)
# removing the parent removes the child # removing the parent removes the child
netif.setparam("has_netem", False) netif.setparam("has_netem", False)
@ -497,12 +497,12 @@ class LxBrNet(PyCoreNet):
tc[2] = "delete" tc[2] = "delete"
if self.up: if self.up:
logger.info("linkconfig: %s" % ([tc + parent + ["handle", "10:"]],)) logger.info("linkconfig: %s" % ([tc + parent + ["handle", "10:"]],))
subprocess.check_call(tc + parent + ["handle", "10:"]) utils.check_cmd(tc + parent + ["handle", "10:"])
netif.setparam("has_netem", False) netif.setparam("has_netem", False)
elif len(netem) > 1: elif len(netem) > 1:
if self.up: if self.up:
logger.info("linkconfig: %s" % ([tc + parent + ["handle", "10:"] + netem],)) logger.info("linkconfig: %s" % ([tc + parent + ["handle", "10:"] + netem],))
subprocess.check_call(tc + parent + ["handle", "10:"] + netem) utils.check_cmd(tc + parent + ["handle", "10:"] + netem)
netif.setparam("has_netem", True) netif.setparam("has_netem", True)
def linknet(self, net): def linknet(self, net):
@ -535,8 +535,8 @@ class LxBrNet(PyCoreNet):
if net.up: if net.up:
# this is similar to net.attach() but uses netif.name instead # this is similar to net.attach() but uses netif.name instead
# of localname # of localname
subprocess.check_call([constants.BRCTL_BIN, "addif", net.brname, netif.name]) utils.check_cmd([constants.BRCTL_BIN, "addif", net.brname, netif.name])
subprocess.check_call([constants.IP_BIN, "link", "set", netif.name, "up"]) utils.check_cmd([constants.IP_BIN, "link", "set", netif.name, "up"])
i = net.newifindex() i = net.newifindex()
net._netif[i] = netif net._netif[i] = netif
with net._linked_lock: with net._linked_lock:
@ -570,7 +570,7 @@ class LxBrNet(PyCoreNet):
return return
for addr in addrlist: for addr in addrlist:
try: try:
subprocess.check_call([constants.IP_BIN, "addr", "add", str(addr), "dev", self.brname]) utils.check_cmd([constants.IP_BIN, "addr", "add", str(addr), "dev", self.brname])
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
logger.exception("Error adding IP address") logger.exception("Error adding IP address")

View file

@ -99,11 +99,7 @@ class SimpleLxcNode(PyCoreNode):
env["NODE_NAME"] = str(self.name) env["NODE_NAME"] = str(self.name)
try: try:
output = utils.check_alloutput(vnoded, env=env) _, output = utils.check_cmd(vnoded, env=env)
# p = subprocess.Popen(vnoded, stdout=subprocess.PIPE, env=env)
# stdout, _ = p.communicate()
# if p.returncode:
# raise IOError("vnoded command failed: %s" % vnoded)
self.pid = int(output) self.pid = int(output)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
logger.exception("vnoded failed to create a namespace; check kernel support and user privileges") logger.exception("vnoded failed to create a namespace; check kernel support and user privileges")
@ -171,37 +167,37 @@ class SimpleLxcNode(PyCoreNode):
""" """
pass pass
def cmd(self, cmd, wait=True): def cmd(self, args, wait=True):
""" """
Runs shell command on node, with option to not wait for a result. Runs shell command on node, with option to not wait for a result.
:param list[str]/str cmd: command to run :param list[str]|str args: command to run
:param bool wait: wait for command to exit, defaults to True :param bool wait: wait for command to exit, defaults to True
:return: exit status for command :return: exit status for command
:rtype: int :rtype: int
""" """
return self.client.cmd(cmd, wait) return self.client.cmd(args, wait)
def cmd_output(self, cmd): def cmd_output(self, args):
""" """
Runs shell command on node and get exit status and output. Runs shell command on node and get exit status and output.
:param list[str]/str cmd: command to run :param list[str]|str args: command to run
:return: exit status and combined stdout and stderr :return: exit status and combined stdout and stderr
:rtype: tuple[int, str] :rtype: tuple[int, str]
""" """
return self.client.cmd_output(cmd) return self.client.cmd_output(args)
def check_cmd(self, cmd): def check_cmd(self, args):
""" """
Runs shell command on node. Runs shell command on node.
:param list[str]/str cmd: command to run :param list[str]|str args: command to run
:return: exist status and combined stdout and stderr :return: exist status and combined stdout and stderr
:rtype: tuple[int, str] :rtype: tuple[int, str]
:raises subprocess.CalledProcessError: when a non-zero exit status occurs :raises subprocess.CalledProcessError: when a non-zero exit status occurs
""" """
return self.client.check_cmd(cmd) return self.client.check_cmd(args)
def termcmdstring(self, sh="/bin/sh"): def termcmdstring(self, sh="/bin/sh"):
""" """
@ -359,9 +355,9 @@ class SimpleLxcNode(PyCoreNode):
""" """
self._netif[ifindex].sethwaddr(addr) self._netif[ifindex].sethwaddr(addr)
if self.up: if self.up:
cmd = [constants.IP_BIN, "link", "set", "dev", self.ifname(ifindex), "address", str(addr)] args = [constants.IP_BIN, "link", "set", "dev", self.ifname(ifindex), "address", str(addr)]
try: try:
self.check_cmd(cmd) self.check_cmd(args)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
logger.exception("error setting MAC address %s: %s", addr) logger.exception("error setting MAC address %s: %s", addr)
@ -377,11 +373,11 @@ class SimpleLxcNode(PyCoreNode):
try: try:
# check if addr is ipv6 # check if addr is ipv6
if ":" in str(addr): if ":" in str(addr):
cmd = [constants.IP_BIN, "addr", "add", str(addr), "dev", self.ifname(ifindex)] args = [constants.IP_BIN, "addr", "add", str(addr), "dev", self.ifname(ifindex)]
self.check_cmd(cmd) self.check_cmd(args)
else: else:
cmd = [constants.IP_BIN, "addr", "add", str(addr), "broadcast", "+", "dev", self.ifname(ifindex)] args = [constants.IP_BIN, "addr", "add", str(addr), "broadcast", "+", "dev", self.ifname(ifindex)]
self.check_cmd(cmd) self.check_cmd(args)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
logger.exception("failure adding interface address") logger.exception("failure adding interface address")

View file

@ -61,41 +61,37 @@ class VnodeClient(object):
""" """
self.cmdchnl.close() self.cmdchnl.close()
def cmd(self, cmd, wait=True): def cmd(self, args, wait=True):
""" """
Execute a command on a node and return the status (return code). Execute a command on a node and return the status (return code).
:param list[str]/str cmd: command arguments :param list[str]|str args: command arguments
:param bool wait: wait for command to end or not :param bool wait: wait for command to end or not
:return: command status :return: command status
:rtype: int :rtype: int
""" """
self._verify_connection() self._verify_connection()
cmd = utils.split_cmd(cmd) args = utils.split_args(args)
# run command, return process when not waiting # run command, return process when not waiting
p = self.cmdchnl.qcmd(cmd) p = self.cmdchnl.qcmd(args)
if not wait: if not wait:
return 0 return 0
# wait for and return exit status # wait for and return exit status
status = p.wait() return p.wait()
if status:
logger.warn("cmd exited with status %s: %s", status, cmd)
return status def cmd_output(self, args):
def cmd_output(self, cmd):
""" """
Execute a command on a node and return a tuple containing the Execute a command on a node and return a tuple containing the
exit status and result string. stderr output exit status and result string. stderr output
is folded into the stdout result string. is folded into the stdout result string.
:param list[str]/str cmd: command to run :param list[str]|str args: command to run
:return: command status and combined stdout and stderr output :return: command status and combined stdout and stderr output
:rtype: tuple[int, str] :rtype: tuple[int, str]
""" """
p, stdin, stdout, stderr = self.popen(cmd) p, stdin, stdout, stderr = self.popen(args)
stdin.close() stdin.close()
output = stdout.read() + stderr.read() output = stdout.read() + stderr.read()
stdout.close() stdout.close()
@ -103,44 +99,44 @@ class VnodeClient(object):
status = p.wait() status = p.wait()
return status, output.strip() return status, output.strip()
def check_cmd(self, cmd): def check_cmd(self, args):
""" """
Run command and return exit status and combined stdout and stderr. Run command and return exit status and combined stdout and stderr.
:param list[str]/str cmd: command to run :param list[str]|str args: command to run
:return: exit status and combined stdout and stderr :return: exit status and combined stdout and stderr
:rtype: tuple[int, str] :rtype: tuple[int, str]
:raises subprocess.CalledProcessError: when there is a non-zero exit status :raises subprocess.CalledProcessError: when there is a non-zero exit status
""" """
status, output = self.cmd_output(cmd) status, output = self.cmd_output(args)
if status: if status:
raise subprocess.CalledProcessError(status, cmd, output) raise subprocess.CalledProcessError(status, args, output)
return status, output.strip() return status, output.strip()
def popen(self, cmd): def popen(self, args):
""" """
Execute a popen command against the node. Execute a popen command against the node.
:param list[str]/str cmd: command arguments :param list[str]|str args: command arguments
:return: popen object, stdin, stdout, and stderr :return: popen object, stdin, stdout, and stderr
:rtype: tuple :rtype: tuple
""" """
self._verify_connection() self._verify_connection()
cmd = utils.split_cmd(cmd) args = utils.split_args(args)
return self.cmdchnl.popen(cmd) return self.cmdchnl.popen(args)
def icmd(self, cmd): def icmd(self, args):
""" """
Execute an icmd against a node. Execute an icmd against a node.
:param list[str]/str cmd: command arguments :param list[str]|str args: command arguments
:return: command result :return: command result
:rtype: int :rtype: int
""" """
cmd = utils.split_cmd(cmd) args = utils.split_args(args)
return os.spawnlp(os.P_WAIT, VCMD, VCMD, "-c", self.ctrlchnlname, "--", *cmd) return os.spawnlp(os.P_WAIT, VCMD, VCMD, "-c", self.ctrlchnlname, "--", *args)
def redircmd(self, infd, outfd, errfd, cmd, wait=True): def redircmd(self, infd, outfd, errfd, args, wait=True):
""" """
Execute a command on a node with standard input, output, and Execute a command on a node with standard input, output, and
error redirected according to the given file descriptors. error redirected according to the given file descriptors.
@ -148,7 +144,7 @@ class VnodeClient(object):
:param infd: stdin file descriptor :param infd: stdin file descriptor
:param outfd: stdout file descriptor :param outfd: stdout file descriptor
:param errfd: stderr file descriptor :param errfd: stderr file descriptor
:param list[str]/str cmd: command arguments :param list[str]|str args: command arguments
:param bool wait: wait flag :param bool wait: wait flag
:return: command status :return: command status
:rtype: int :rtype: int
@ -156,15 +152,15 @@ class VnodeClient(object):
self._verify_connection() self._verify_connection()
# run command, return process when not waiting # run command, return process when not waiting
cmd = utils.split_cmd(cmd) args = utils.split_args(args)
p = self.cmdchnl.redircmd(infd, outfd, errfd, cmd) p = self.cmdchnl.redircmd(infd, outfd, errfd, args)
if not wait: if not wait:
return p return p
# wait for and return exit status # wait for and return exit status
status = p.wait() status = p.wait()
if status: if status:
logger.warn("cmd exited with status %s: %s", status, cmd) logger.warn("cmd exited with status %s: %s", status, args)
return status return status
def term(self, sh="/bin/sh"): def term(self, sh="/bin/sh"):
@ -175,12 +171,12 @@ class VnodeClient(object):
:return: terminal command result :return: terminal command result
:rtype: int :rtype: int
""" """
cmd = ("xterm", "-ut", "-title", self.name, "-e", VCMD, "-c", self.ctrlchnlname, "--", sh) args = ("xterm", "-ut", "-title", self.name, "-e", VCMD, "-c", self.ctrlchnlname, "--", sh)
if "SUDO_USER" in os.environ: if "SUDO_USER" in os.environ:
cmd = ("su", "-s", "/bin/sh", "-c", args = ("su", "-s", "/bin/sh", "-c",
"exec " + " ".join(map(lambda x: "'%s'" % x, cmd)), "exec " + " ".join(map(lambda x: "'%s'" % x, args)),
os.environ["SUDO_USER"]) os.environ["SUDO_USER"])
return os.spawnvp(os.P_NOWAIT, cmd[0], cmd) return os.spawnvp(os.P_NOWAIT, args[0], args)
def termcmdstring(self, sh="/bin/sh"): def termcmdstring(self, sh="/bin/sh"):
""" """
@ -226,8 +222,8 @@ class VnodeClient(object):
return self._addr[ifname] return self._addr[ifname]
interface = {"ether": [], "inet": [], "inet6": [], "inet6link": []} interface = {"ether": [], "inet": [], "inet6": [], "inet6link": []}
cmd = [constants.IP_BIN, "addr", "show", "dev", ifname] args = [constants.IP_BIN, "addr", "show", "dev", ifname]
p, stdin, stdout, stderr = self.popen(cmd) p, stdin, stdout, stderr = self.popen(args)
stdin.close() stdin.close()
for line in stdout: for line in stdout:
@ -249,7 +245,7 @@ class VnodeClient(object):
stderr.close() stderr.close()
status = p.wait() status = p.wait()
if status: if status:
logger.warn("nonzero exist status (%s) for cmd: %s", status, cmd) logger.warn("nonzero exist status (%s) for cmd: %s", status, args)
if err: if err:
logger.warn("error output: %s", err) logger.warn("error output: %s", err)
self._addr[ifname] = interface self._addr[ifname] = interface
@ -264,8 +260,8 @@ class VnodeClient(object):
:rtype: dict :rtype: dict
""" """
stats = {} stats = {}
cmd = ["cat", "/proc/net/dev"] args = ["cat", "/proc/net/dev"]
p, stdin, stdout, stderr = self.popen(cmd) p, stdin, stdout, stderr = self.popen(args)
stdin.close() stdin.close()
# ignore first line # ignore first line
stdout.readline() stdout.readline()
@ -291,7 +287,7 @@ class VnodeClient(object):
stderr.close() stderr.close()
status = p.wait() status = p.wait()
if status: if status:
logger.warn("nonzero exist status (%s) for cmd: %s", status, cmd) logger.warn("nonzero exist status (%s) for cmd: %s", status, args)
if err: if err:
logger.warn("error output: %s", err) logger.warn("error output: %s", err)
if ifname is not None: if ifname is not None:

View file

@ -55,34 +55,33 @@ class PhysicalNode(PyCoreNode):
def termcmdstring(self, sh="/bin/sh"): def termcmdstring(self, sh="/bin/sh"):
""" """
The broker will add the appropriate SSH command to open a terminal Create a terminal command string.
on this physical node.
:param str sh: shell to execute command in
:return: str
""" """
return sh return sh
def cmd(self, args, wait=True): def cmd(self, args, wait=True):
""" """
run a command on the physical node Runs shell command on node, with option to not wait for a result.
:param list[str]|str args: command to run
:param bool wait: wait for command to exit, defaults to True
:return: exit status for command
:rtype: int
""" """
os.chdir(self.nodedir) os.chdir(self.nodedir)
status = -1 status = utils.cmd(args, wait)
try:
if wait:
# os.spawnlp(os.P_WAIT, args)
status = subprocess.call(args)
else:
# os.spawnlp(os.P_NOWAIT, args)
subprocess.Popen(args)
status = 0
except subprocess.CalledProcessError:
logger.exception("cmd exited with status: %s", args)
return status return status
def cmd_output(self, args): def cmd_output(self, args):
""" """
run a command on the physical node and get the result Runs shell command on node and get exit status and output.
:param list[str]|str args: command to run
:return: exit status and combined stdout and stderr
:rtype: tuple[int, str]
""" """
os.chdir(self.nodedir) os.chdir(self.nodedir)
# in Python 2.7 we can use subprocess.check_output() here # in Python 2.7 we can use subprocess.check_output() here
@ -92,18 +91,18 @@ class PhysicalNode(PyCoreNode):
status = p.wait() status = p.wait()
return status, stdout.strip() return status, stdout.strip()
def check_cmd(self, cmd): def check_cmd(self, args):
""" """
Runs shell command on node. Runs shell command on node.
:param list[str]/str cmd: command to run :param list[str]|str args: command to run
:return: exist status and combined stdout and stderr :return: exist status and combined stdout and stderr
:rtype: tuple[int, str] :rtype: tuple[int, str]
:raises subprocess.CalledProcessError: when a non-zero exit status occurs :raises subprocess.CalledProcessError: when a non-zero exit status occurs
""" """
status, output = self.cmd_output(cmd) status, output = self.cmd_output(args)
if status: if status:
raise subprocess.CalledProcessError(status, cmd, output) raise subprocess.CalledProcessError(status, args, output)
return status, output.strip() return status, output.strip()
def shcmd(self, cmdstr, sh="/bin/sh"): def shcmd(self, cmdstr, sh="/bin/sh"):

View file

@ -304,12 +304,12 @@ class CoreServices(ConfigurableManager):
if use_startup_service and not self.is_startup_service(service): if use_startup_service and not self.is_startup_service(service):
return return
for cmd in service.getstartup(node, services): for args in service.getstartup(node, services):
try: try:
# TODO: this wait=False can be problematic! # TODO: this wait=False can be problematic!
node.cmd(cmd, wait=False) node.cmd(args, wait=False)
except: except:
logger.exception("error starting command %s", cmd) logger.exception("error starting command %s", args)
def bootnodecustomservice(self, node, service, services, use_startup_service): def bootnodecustomservice(self, node, service, services, use_startup_service):
""" """
@ -350,12 +350,12 @@ class CoreServices(ConfigurableManager):
if use_startup_service and not self.is_startup_service(service): if use_startup_service and not self.is_startup_service(service):
return return
for cmd in service._startup: for args in service._startup:
try: try:
# TODO: this wait=False can be problematic! # TODO: this wait=False can be problematic!
node.cmd(cmd, wait=False) node.cmd(args, wait=False)
except: except:
logger.exception("error starting command %s", cmd) logger.exception("error starting command %s", args)
def copyservicefile(self, node, filename, cfg): def copyservicefile(self, node, filename, cfg):
""" """
@ -409,10 +409,10 @@ class CoreServices(ConfigurableManager):
status = 0 status = 0
# has validate commands # has validate commands
if len(validate_cmds) > 0: if len(validate_cmds) > 0:
for cmd in validate_cmds: for args in validate_cmds:
logger.info("validating service %s using: %s", service._name, cmd) logger.info("validating service %s using: %s", service._name, args)
try: try:
status, _ = node.check_cmd(cmd) status, _ = node.check_cmd(args)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
logger.exception("validate command failed") logger.exception("validate command failed")
status = -1 status = -1
@ -444,12 +444,12 @@ class CoreServices(ConfigurableManager):
# doesn't have a shutdown command # doesn't have a shutdown command
status += "0" status += "0"
else: else:
for cmd in service._shutdown: for args in service._shutdown:
try: try:
status, _ = node.check_cmd(cmd) status, _ = node.check_cmd(args)
status = str(status) status = str(status)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
logger.exception("error running stop command %s", cmd) logger.exception("error running stop command %s", args)
# TODO: determine if its ok to just return the bad exit status # TODO: determine if its ok to just return the bad exit status
status = "-1" status = "-1"
return status return status
@ -757,12 +757,12 @@ class CoreServices(ConfigurableManager):
else: else:
cmds = s.getstartup(node, services) cmds = s.getstartup(node, services)
if len(cmds) > 0: if len(cmds) > 0:
for cmd in cmds: for args in cmds:
try: try:
node.check_cmd(cmd) node.check_cmd(args)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
logger.exception("error starting command %s", cmd) logger.exception("error starting command %s", args)
fail += "Start %s(%s)," % (s._name, cmd) fail += "Start %s(%s)," % (s._name, args)
if event_type == EventTypes.PAUSE.value: if event_type == EventTypes.PAUSE.value:
status = self.validatenodeservice(node, s, services) status = self.validatenodeservice(node, s, services)
if status != 0: if status != 0:

View file

@ -429,11 +429,11 @@ class Session(object):
# execute hook file # execute hook file
try: try:
subprocess.check_call(["/bin/sh", file_name], stdin=open(os.devnull, 'r'), args = ["/bin/sh", file_name]
stdout=stdout, stderr=stderr, close_fds=True, subprocess.check_call(args, stdout=stdout, stderr=stderr,
cwd=self.session_dir, env=self.get_environment()) close_fds=True, cwd=self.session_dir, env=self.get_environment())
except subprocess.CalledProcessError: except (OSError, subprocess.CalledProcessError):
logger.exception("error running hook '%s'", file_name) logger.exception("error running hook: %s", file_name)
def run_state_hooks(self, state): def run_state_hooks(self, state):
""" """

View file

@ -1,12 +1,11 @@
import os import os
import socket import socket
import subprocess
from core import constants from core import constants
from core import emane from core import emane
from core import logger from core import logger
from core.enumerations import NodeTypes from core.enumerations import NodeTypes
from core.misc import ipaddress from core.misc import ipaddress, utils
from core.misc import nodeutils from core.misc import nodeutils
from core.netns import nodes from core.netns import nodes
from core.xml import xmlutils from core.xml import xmlutils
@ -26,8 +25,8 @@ class CoreDeploymentWriter(object):
def get_ipv4_addresses(hostname): def get_ipv4_addresses(hostname):
if hostname == 'localhost': if hostname == 'localhost':
addr_list = [] addr_list = []
cmd = (constants.IP_BIN, '-o', '-f', 'inet', 'addr', 'show') args = (constants.IP_BIN, '-o', '-f', 'inet', 'addr', 'show')
output = subprocess.check_output(cmd) _, output = utils.check_cmd(args)
for line in output.split(os.linesep): for line in output.split(os.linesep):
split = line.split() split = line.split()
if not split: if not split:
@ -48,8 +47,8 @@ class CoreDeploymentWriter(object):
""" """
if hostname == 'localhost': if hostname == 'localhost':
iface_list = [] iface_list = []
cmd = (constants.IP_BIN, '-o', '-f', 'inet', 'addr', 'show') args = (constants.IP_BIN, '-o', '-f', 'inet', 'addr', 'show')
output = subprocess.check_output(cmd) _, output = utils.check_cmd(args)
for line in output.split(os.linesep): for line in output.split(os.linesep):
split = line.split() split = line.split()
if not split: if not split: