updates to consolidate commands that need to be defined by a new node type
This commit is contained in:
parent
0b8ee7760d
commit
d3bd61ddcf
25 changed files with 314 additions and 175 deletions
|
@ -103,7 +103,7 @@ class CtrlNet(LxBrNet):
|
|||
:return: True if an old bridge was detected, False otherwise
|
||||
:rtype: bool
|
||||
"""
|
||||
retstat, retstr = utils.cmdresult([constants.BRCTL_BIN, "show"])
|
||||
retstat, retstr = utils.cmd_output([constants.BRCTL_BIN, "show"])
|
||||
if retstat != 0:
|
||||
logger.error("Unable to retrieve list of installed bridges")
|
||||
lines = retstr.split("\n")
|
||||
|
|
|
@ -406,7 +406,7 @@ class OvsCtrlNet(OvsNet):
|
|||
Check if there are old control net bridges and delete them
|
||||
"""
|
||||
|
||||
status, output = utils.cmdresult([constants.OVS_BIN, "list-br"])
|
||||
status, output = utils.cmd_output([constants.OVS_BIN, "list-br"])
|
||||
output = output.strip()
|
||||
if output:
|
||||
for line in output.split("\n"):
|
||||
|
|
|
@ -59,10 +59,16 @@ class VEth(PyCoreNetIf):
|
|||
"""
|
||||
if not self.up:
|
||||
return
|
||||
|
||||
if self.node:
|
||||
self.node.client.cmd([constants.IP_BIN, "-6", "addr", "flush", "dev", self.name])
|
||||
try:
|
||||
self.node.check_cmd([constants.IP_BIN, "-6", "addr", "flush", "dev", self.name])
|
||||
except subprocess.CalledProcessError:
|
||||
logger.exception("error shutting down interface")
|
||||
|
||||
if self.localname:
|
||||
utils.mutedetach([constants.IP_BIN, "link", "delete", self.localname])
|
||||
|
||||
self.up = False
|
||||
|
||||
|
||||
|
@ -98,10 +104,10 @@ class TunTap(PyCoreNetIf):
|
|||
"""
|
||||
# TODO: more sophisticated TAP creation here
|
||||
# Debian does not support -p (tap) option, RedHat does.
|
||||
# For now, this is disabled to allow the TAP to be created by another
|
||||
# system (e.g. EMANE"s emanetransportd)
|
||||
# check_call(["tunctl", "-t", self.name])
|
||||
# self.install()
|
||||
# For now, this is disabled to allow the TAP to be created by another
|
||||
# system (e.g. EMANE"s emanetransportd)
|
||||
# check_call(["tunctl", "-t", self.name])
|
||||
# self.install()
|
||||
self.up = True
|
||||
|
||||
def shutdown(self):
|
||||
|
@ -112,9 +118,12 @@ class TunTap(PyCoreNetIf):
|
|||
"""
|
||||
if not self.up:
|
||||
return
|
||||
self.node.client.cmd([constants.IP_BIN, "-6", "addr", "flush", "dev", self.name])
|
||||
# if self.name:
|
||||
# mutedetach(["tunctl", "-d", self.localname])
|
||||
|
||||
try:
|
||||
self.node.check_cmd([constants.IP_BIN, "-6", "addr", "flush", "dev", self.name])
|
||||
except subprocess.CalledProcessError:
|
||||
logger.exception("error shutting down tunnel tap")
|
||||
|
||||
self.up = False
|
||||
|
||||
def waitfor(self, func, attempts=10, maxretrydelay=0.25):
|
||||
|
@ -169,7 +178,7 @@ class TunTap(PyCoreNetIf):
|
|||
|
||||
def nodedevexists():
|
||||
cmd = [constants.IP_BIN, "link", "show", self.name]
|
||||
return self.node.client.cmd(cmd)
|
||||
return self.node.cmd(cmd)
|
||||
|
||||
count = 0
|
||||
while True:
|
||||
|
@ -199,15 +208,11 @@ class TunTap(PyCoreNetIf):
|
|||
netns = str(self.node.pid)
|
||||
|
||||
try:
|
||||
subprocess.check_call([constants.IP_BIN, "link", "set", self.localname, "netns", netns])
|
||||
utils.check_cmd([constants.IP_BIN, "link", "set", self.localname, "netns", netns])
|
||||
self.node.check_cmd([constants.IP_BIN, "link", "set", self.localname, "name", self.name])
|
||||
self.node.check_cmd([constants.IP_BIN, "link", "set", self.name, "up"])
|
||||
except subprocess.CalledProcessError:
|
||||
msg = "error installing TAP interface %s, command:" % self.localname
|
||||
msg += "ip link set %s netns %s" % (self.localname, netns)
|
||||
logger.exception(msg)
|
||||
return
|
||||
|
||||
self.node.client.cmd([constants.IP_BIN, "link", "set", self.localname, "name", self.name])
|
||||
self.node.client.cmd([constants.IP_BIN, "link", "set", self.name, "up"])
|
||||
logger.exception("error installing TAP interface")
|
||||
|
||||
def setaddrs(self):
|
||||
"""
|
||||
|
@ -217,7 +222,10 @@ class TunTap(PyCoreNetIf):
|
|||
"""
|
||||
self.waitfordevicenode()
|
||||
for addr in self.addrlist:
|
||||
self.node.client.cmd([constants.IP_BIN, "addr", "add", str(addr), "dev", self.name])
|
||||
try:
|
||||
self.node.check_cmd([constants.IP_BIN, "addr", "add", str(addr), "dev", self.name])
|
||||
except subprocess.CalledProcessError:
|
||||
logger.exception("failure setting interface address")
|
||||
|
||||
|
||||
class GreTap(PyCoreNetIf):
|
||||
|
|
|
@ -114,11 +114,11 @@ class SimpleLxcNode(PyCoreNode):
|
|||
try:
|
||||
# bring up the loopback interface
|
||||
logger.info("bringing up loopback interface")
|
||||
self.client.check_alloutput([constants.IP_BIN, "link", "set", "lo", "up"])
|
||||
self.check_cmd([constants.IP_BIN, "link", "set", "lo", "up"])
|
||||
|
||||
# set hostname for node
|
||||
logger.info("setting hostname: %s" % self.name)
|
||||
self.client.check_alloutput(["hostname", self.name])
|
||||
self.check_cmd(["hostname", self.name])
|
||||
except subprocess.CalledProcessError:
|
||||
logger.exception("error setting up loopback and hostname: %s")
|
||||
|
||||
|
@ -171,6 +171,47 @@ class SimpleLxcNode(PyCoreNode):
|
|||
"""
|
||||
pass
|
||||
|
||||
def cmd(self, cmd, wait=True):
|
||||
"""
|
||||
Runs shell command on node, with option to not wait for a result.
|
||||
|
||||
:param list[str]/str cmd: command to run
|
||||
:param bool wait: wait for command to exit, defaults to True
|
||||
:return: exit status for command
|
||||
:rtype: int
|
||||
"""
|
||||
return self.client.cmd(cmd, wait)
|
||||
|
||||
def cmd_output(self, cmd):
|
||||
"""
|
||||
Runs shell command on node and get exit status and output.
|
||||
|
||||
:param list[str]/str cmd: command to run
|
||||
:return: exit status and combined stdout and stderr
|
||||
:rtype: tuple[int, str]
|
||||
"""
|
||||
return self.client.cmd_output(cmd)
|
||||
|
||||
def check_cmd(self, cmd):
|
||||
"""
|
||||
Runs shell command on node.
|
||||
|
||||
:param list[str]/str cmd: command to run
|
||||
:return: exist status and combined stdout and stderr
|
||||
:rtype: tuple[int, str]
|
||||
:raises subprocess.CalledProcessError: when a non-zero exit status occurs
|
||||
"""
|
||||
return self.client.check_cmd(cmd)
|
||||
|
||||
def termcmdstring(self, sh="/bin/sh"):
|
||||
"""
|
||||
Create a terminal command string.
|
||||
|
||||
:param str sh: shell to execute command in
|
||||
:return: str
|
||||
"""
|
||||
return self.client.termcmdstring(sh)
|
||||
|
||||
# TODO: should change how this exception is just swallowed up
|
||||
def mount(self, source, target):
|
||||
"""
|
||||
|
@ -200,7 +241,7 @@ class SimpleLxcNode(PyCoreNode):
|
|||
"""
|
||||
logger.info("unmounting: %s", target)
|
||||
try:
|
||||
self.client.check_alloutput([constants.UMOUNT_BIN, "-n", "-l", target])
|
||||
self.check_cmd([constants.UMOUNT_BIN, "-n", "-l", target])
|
||||
except subprocess.CalledProcessError:
|
||||
logger.exception("error during unmount")
|
||||
|
||||
|
@ -247,8 +288,8 @@ class SimpleLxcNode(PyCoreNode):
|
|||
|
||||
if self.up:
|
||||
try:
|
||||
utils.check_alloutput([constants.IP_BIN, "link", "set", veth.name, "netns", str(self.pid)])
|
||||
self.client.check_alloutput([constants.IP_BIN, "link", "set", veth.name, "name", ifname])
|
||||
utils.check_cmd([constants.IP_BIN, "link", "set", veth.name, "netns", str(self.pid)])
|
||||
self.check_cmd([constants.IP_BIN, "link", "set", veth.name, "name", ifname])
|
||||
except subprocess.CalledProcessError:
|
||||
logger.exception("failure setting eth name")
|
||||
|
||||
|
@ -258,7 +299,7 @@ class SimpleLxcNode(PyCoreNode):
|
|||
# TODO: potentially find better way to query interface ID
|
||||
# retrieve interface information
|
||||
try:
|
||||
output = self.client.check_alloutput(["ip", "link", "show", veth.name])
|
||||
_, output = self.check_cmd(["ip", "link", "show", veth.name])
|
||||
logger.info("interface command output: %s", output)
|
||||
output = output.split("\n")
|
||||
veth.flow_id = int(output[0].strip().split(":")[0]) + 1
|
||||
|
@ -320,7 +361,7 @@ class SimpleLxcNode(PyCoreNode):
|
|||
if self.up:
|
||||
cmd = [constants.IP_BIN, "link", "set", "dev", self.ifname(ifindex), "address", str(addr)]
|
||||
try:
|
||||
self.client.check_alloutput(cmd)
|
||||
self.check_cmd(cmd)
|
||||
except subprocess.CalledProcessError:
|
||||
logger.exception("error setting MAC address %s: %s", addr)
|
||||
|
||||
|
@ -337,10 +378,10 @@ class SimpleLxcNode(PyCoreNode):
|
|||
# check if addr is ipv6
|
||||
if ":" in str(addr):
|
||||
cmd = [constants.IP_BIN, "addr", "add", str(addr), "dev", self.ifname(ifindex)]
|
||||
self.client.check_alloutput(cmd)
|
||||
self.check_cmd(cmd)
|
||||
else:
|
||||
cmd = [constants.IP_BIN, "addr", "add", str(addr), "broadcast", "+", "dev", self.ifname(ifindex)]
|
||||
self.client.check_alloutput(cmd)
|
||||
self.check_cmd(cmd)
|
||||
except subprocess.CalledProcessError:
|
||||
logger.exception("failure adding interface address")
|
||||
|
||||
|
@ -361,7 +402,7 @@ class SimpleLxcNode(PyCoreNode):
|
|||
|
||||
if self.up:
|
||||
try:
|
||||
self.client.check_alloutput([constants.IP_BIN, "addr", "del", str(addr), "dev", self.ifname(ifindex)])
|
||||
self.check_cmd([constants.IP_BIN, "addr", "del", str(addr), "dev", self.ifname(ifindex)])
|
||||
except subprocess.CalledProcessError:
|
||||
logger.exception("failure deleting address")
|
||||
|
||||
|
@ -394,7 +435,7 @@ class SimpleLxcNode(PyCoreNode):
|
|||
"""
|
||||
if self.up:
|
||||
try:
|
||||
self.client.check_alloutput([constants.IP_BIN, "link", "set", self.ifname(ifindex), "up"])
|
||||
self.check_cmd([constants.IP_BIN, "link", "set", self.ifname(ifindex), "up"])
|
||||
except subprocess.CalledProcessError:
|
||||
logger.exception("failure bringing interface up")
|
||||
|
||||
|
@ -454,15 +495,15 @@ class SimpleLxcNode(PyCoreNode):
|
|||
tmplen = 8
|
||||
tmp1 = "tmp." + "".join([random.choice(string.ascii_lowercase) for _ in xrange(tmplen)])
|
||||
tmp2 = "tmp." + "".join([random.choice(string.ascii_lowercase) for _ in xrange(tmplen)])
|
||||
utils.check_alloutput([constants.IP_BIN, "link", "add", "name", tmp1, "type", "veth", "peer", "name", tmp2])
|
||||
utils.check_cmd([constants.IP_BIN, "link", "add", "name", tmp1, "type", "veth", "peer", "name", tmp2])
|
||||
|
||||
utils.check_alloutput([constants.IP_BIN, "link", "set", tmp1, "netns", str(self.pid)])
|
||||
self.client.check_alloutput([constants.IP_BIN, "link", "set", tmp1, "name", ifname])
|
||||
utils.check_cmd([constants.IP_BIN, "link", "set", tmp1, "netns", str(self.pid)])
|
||||
self.check_cmd([constants.IP_BIN, "link", "set", tmp1, "name", ifname])
|
||||
interface = PyCoreNetIf(node=self, name=ifname, mtu=_DEFAULT_MTU)
|
||||
self.addnetif(interface, self.newifindex())
|
||||
|
||||
utils.check_alloutput([constants.IP_BIN, "link", "set", tmp2, "netns", str(othernode.pid)])
|
||||
othernode.client.check_alloutput([constants.IP_BIN, "link", "set", tmp2, "name", otherifname])
|
||||
utils.check_cmd([constants.IP_BIN, "link", "set", tmp2, "netns", str(othernode.pid)])
|
||||
othernode.check_cmd([constants.IP_BIN, "link", "set", tmp2, "name", otherifname])
|
||||
other_interface = PyCoreNetIf(node=othernode, name=otherifname, mtu=_DEFAULT_MTU)
|
||||
othernode.addnetif(other_interface, othernode.newifindex())
|
||||
|
||||
|
|
|
@ -6,13 +6,13 @@ by invoking the vcmd shell command.
|
|||
"""
|
||||
|
||||
import os
|
||||
import shlex
|
||||
import subprocess
|
||||
|
||||
import vcmd
|
||||
|
||||
from core import constants
|
||||
from core import logger
|
||||
from core.misc import utils
|
||||
|
||||
VCMD = os.path.join(constants.CORE_BIN_DIR, "vcmd")
|
||||
|
||||
|
@ -61,89 +61,86 @@ class VnodeClient(object):
|
|||
"""
|
||||
self.cmdchnl.close()
|
||||
|
||||
def cmd(self, args, wait=True):
|
||||
def cmd(self, cmd, wait=True):
|
||||
"""
|
||||
Execute a command on a node and return the status (return code).
|
||||
|
||||
:param list args: command arguments
|
||||
:param list[str]/str cmd: command arguments
|
||||
:param bool wait: wait for command to end or not
|
||||
:return: command status
|
||||
:rtype: int
|
||||
"""
|
||||
self._verify_connection()
|
||||
cmd = utils.split_cmd(cmd)
|
||||
|
||||
# run command, return process when not waiting
|
||||
p = self.cmdchnl.qcmd(args)
|
||||
p = self.cmdchnl.qcmd(cmd)
|
||||
if not wait:
|
||||
return p
|
||||
return 0
|
||||
|
||||
# wait for and return exit status
|
||||
status = p.wait()
|
||||
if status:
|
||||
logger.warn("cmd exited with status %s: %s", status, args)
|
||||
logger.warn("cmd exited with status %s: %s", status, cmd)
|
||||
|
||||
return status
|
||||
|
||||
def cmdresult(self, cmd):
|
||||
def cmd_output(self, cmd):
|
||||
"""
|
||||
Execute a command on a node and return a tuple containing the
|
||||
exit status and result string. stderr output
|
||||
is folded into the stdout result string.
|
||||
|
||||
:param list cmd: command arguments
|
||||
:param list[str]/str cmd: command to run
|
||||
:return: command status and combined stdout and stderr output
|
||||
:rtype: tuple[int, str]
|
||||
"""
|
||||
self._verify_connection()
|
||||
|
||||
# split shell string to shell array for convenience
|
||||
if type(cmd) == str:
|
||||
cmd = shlex.split(cmd)
|
||||
|
||||
p, stdin, stdout, stderr = self.popen(cmd)
|
||||
stdin.close()
|
||||
output = stdout.read() + stderr.read()
|
||||
stdout.close()
|
||||
stderr.close()
|
||||
status = p.wait()
|
||||
|
||||
return status, output
|
||||
|
||||
def check_alloutput(self, cmd):
|
||||
def check_cmd(self, cmd):
|
||||
"""
|
||||
Run command and return output, raises exception when non-zero exit status is encountered.
|
||||
Run command and return exit status and combined stdout and stderr.
|
||||
|
||||
:param cmd:
|
||||
:return: combined stdout and stderr combined
|
||||
:rtype: str
|
||||
:param list[str]/str cmd: command to run
|
||||
:return: exit status and combined stdout and stderr
|
||||
:rtype: tuple[int, str]
|
||||
:raises subprocess.CalledProcessError: when there is a non-zero exit status
|
||||
"""
|
||||
status, output = self.cmdresult(cmd)
|
||||
status, output = self.cmd_output(cmd)
|
||||
if status:
|
||||
raise subprocess.CalledProcessError(status, cmd, output)
|
||||
return output
|
||||
return status, output
|
||||
|
||||
def popen(self, args):
|
||||
def popen(self, cmd):
|
||||
"""
|
||||
Execute a popen command against the node.
|
||||
|
||||
:param list args: command arguments
|
||||
:param list[str]/str cmd: command arguments
|
||||
:return: popen object, stdin, stdout, and stderr
|
||||
:rtype: tuple
|
||||
"""
|
||||
self._verify_connection()
|
||||
return self.cmdchnl.popen(args)
|
||||
cmd = utils.split_cmd(cmd)
|
||||
return self.cmdchnl.popen(cmd)
|
||||
|
||||
def icmd(self, args):
|
||||
def icmd(self, cmd):
|
||||
"""
|
||||
Execute an icmd against a node.
|
||||
|
||||
:param list args: command arguments
|
||||
:param list[str]/str cmd: command arguments
|
||||
:return: command result
|
||||
:rtype: int
|
||||
"""
|
||||
return os.spawnlp(os.P_WAIT, VCMD, VCMD, "-c", self.ctrlchnlname, "--", *args)
|
||||
cmd = utils.split_cmd(cmd)
|
||||
return os.spawnlp(os.P_WAIT, VCMD, VCMD, "-c", self.ctrlchnlname, "--", *cmd)
|
||||
|
||||
def redircmd(self, infd, outfd, errfd, args, wait=True):
|
||||
def redircmd(self, infd, outfd, errfd, cmd, wait=True):
|
||||
"""
|
||||
Execute a command on a node with standard input, output, and
|
||||
error redirected according to the given file descriptors.
|
||||
|
@ -151,7 +148,7 @@ class VnodeClient(object):
|
|||
:param infd: stdin file descriptor
|
||||
:param outfd: stdout file descriptor
|
||||
:param errfd: stderr file descriptor
|
||||
:param list args: command arguments
|
||||
:param list[str]/str cmd: command arguments
|
||||
:param bool wait: wait flag
|
||||
:return: command status
|
||||
:rtype: int
|
||||
|
@ -159,14 +156,15 @@ class VnodeClient(object):
|
|||
self._verify_connection()
|
||||
|
||||
# run command, return process when not waiting
|
||||
p = self.cmdchnl.redircmd(infd, outfd, errfd, args)
|
||||
cmd = utils.split_cmd(cmd)
|
||||
p = self.cmdchnl.redircmd(infd, outfd, errfd, cmd)
|
||||
if not wait:
|
||||
return p
|
||||
|
||||
# wait for and return exit status
|
||||
status = p.wait()
|
||||
if status:
|
||||
logger.warn("cmd exited with status %s: %s", status, args)
|
||||
logger.warn("cmd exited with status %s: %s", status, cmd)
|
||||
return status
|
||||
|
||||
def term(self, sh="/bin/sh"):
|
||||
|
@ -193,16 +191,16 @@ class VnodeClient(object):
|
|||
"""
|
||||
return "%s -c %s -- %s" % (VCMD, self.ctrlchnlname, sh)
|
||||
|
||||
def shcmd(self, cmdstr, sh="/bin/sh"):
|
||||
def shcmd(self, cmd, sh="/bin/sh"):
|
||||
"""
|
||||
Execute a shell command.
|
||||
|
||||
:param str cmdstr: command string
|
||||
:param str cmd: command string
|
||||
:param str sh: shell to run command in
|
||||
:return: command result
|
||||
:rtype: int
|
||||
"""
|
||||
return self.cmd([sh, "-c", cmdstr])
|
||||
return self.cmd([sh, "-c", cmd])
|
||||
|
||||
def shcmd_result(self, cmd, sh="/bin/sh"):
|
||||
"""
|
||||
|
@ -213,7 +211,7 @@ class VnodeClient(object):
|
|||
:return: exist status and combined output
|
||||
:rtype: tuple[int, str]
|
||||
"""
|
||||
return self.cmdresult([sh, "-c", cmd])
|
||||
return self.cmd_output([sh, "-c", cmd])
|
||||
|
||||
def getaddr(self, ifname, rescan=False):
|
||||
"""
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue