From 974559843ab425c04f53a8923fd10e04112e2e6b Mon Sep 17 00:00:00 2001 From: "Blake J. Harnden" Date: Fri, 2 Mar 2018 16:22:20 -0800 Subject: [PATCH] defined custom core command error that defaults to printing command output as well --- daemon/core/__init__.py | 10 +++++++++- daemon/core/coreobj.py | 2 +- daemon/core/emane/__init__.py | 5 ++--- daemon/core/emane/emanemanager.py | 4 ++-- daemon/core/misc/utils.py | 13 +++++++------ daemon/core/netns/nodes.py | 31 +++++++++++++++---------------- daemon/core/netns/openvswitch.py | 18 +++++++++--------- daemon/core/netns/vif.py | 26 +++++++++++++------------- daemon/core/netns/vnet.py | 8 ++++---- daemon/core/netns/vnode.py | 22 +++++++++++----------- daemon/core/netns/vnodeclient.py | 6 +++--- daemon/core/phys/pnodes.py | 9 +++++---- daemon/core/service.py | 10 +++++----- daemon/core/services/utility.py | 4 ++-- daemon/core/xen/xen.py | 3 ++- 15 files changed, 90 insertions(+), 81 deletions(-) diff --git a/daemon/core/__init__.py b/daemon/core/__init__.py index e8899fc7..3a0d31a6 100644 --- a/daemon/core/__init__.py +++ b/daemon/core/__init__.py @@ -2,10 +2,10 @@ import json import logging import logging.config import os +import subprocess from core import constants - # setup logging log_config_path = os.path.join(constants.CORE_CONF_DIR, "logging.conf") with open(log_config_path, "r") as log_config_file: @@ -14,3 +14,11 @@ with open(log_config_path, "r") as log_config_file: logger = logging.getLogger() + +class CoreCommandError(subprocess.CalledProcessError): + """ + Used when encountering internal CORE command errors. + """ + + def __str__(self): + return "Command(%s), Status(%s):\n%s" % (self.cmd, self.returncode, self.output) diff --git a/daemon/core/coreobj.py b/daemon/core/coreobj.py index 10bf83ea..e9fe024e 100644 --- a/daemon/core/coreobj.py +++ b/daemon/core/coreobj.py @@ -419,7 +419,7 @@ class PyCoreNode(PyCoreObj): :param list[str]|str args: command to run :return: combined stdout and stderr :rtype: str - :raises subprocess.CalledProcessError: when a non-zero exit status occurs + :raises CoreCommandError: when a non-zero exit status occurs """ raise NotImplementedError diff --git a/daemon/core/emane/__init__.py b/daemon/core/emane/__init__.py index 18f01a83..5446bf88 100644 --- a/daemon/core/emane/__init__.py +++ b/daemon/core/emane/__init__.py @@ -1,5 +1,4 @@ -import subprocess - +from core import CoreCommandError from core import logger from core.misc import utils @@ -39,7 +38,7 @@ def emane_version(): VERSION = EMANE093 elif output.startswith("1.0.1"): VERSION = EMANE101 - except subprocess.CalledProcessError: + except CoreCommandError: logger.exception("error checking emane version") output = "" diff --git a/daemon/core/emane/emanemanager.py b/daemon/core/emane/emanemanager.py index 5724590c..4777e050 100644 --- a/daemon/core/emane/emanemanager.py +++ b/daemon/core/emane/emanemanager.py @@ -3,10 +3,10 @@ emane.py: definition of an Emane class for implementing configuration control of """ import os -import subprocess import threading from xml.dom.minidom import parseString +from core import CoreCommandError from core import constants from core import emane from core import logger @@ -949,7 +949,7 @@ class EmaneManager(ConfigurableManager): try: utils.check_cmd(args) utils.check_cmd(["killall", "-q", "emanetransportd"]) - except subprocess.CalledProcessError: + except CoreCommandError: logger.exception("error shutting down emane daemons") def installnetifs(self, do_netns=True): diff --git a/daemon/core/misc/utils.py b/daemon/core/misc/utils.py index d8b31fd3..f13f0152 100644 --- a/daemon/core/misc/utils.py +++ b/daemon/core/misc/utils.py @@ -12,6 +12,7 @@ import sys import fcntl import resource +from core import CoreCommandError from core import logger DEVNULL = open(os.devnull, "wb") @@ -181,7 +182,7 @@ def cmd(args, wait=True): return 0 return p.wait() except OSError: - raise subprocess.CalledProcessError(-1, args) + raise CoreCommandError(-1, args) def cmd_output(args): @@ -192,7 +193,7 @@ def cmd_output(args): :param list[str]|str args: command arguments :return: command status and stdout :rtype: tuple[int, str] - :raises subprocess.CalledProcessError: when the file to execute is not found + :raises CoreCommandError: when the file to execute is not found """ args = split_args(args) try: @@ -201,7 +202,7 @@ def cmd_output(args): status = p.wait() return status, stdout.strip() except OSError: - raise subprocess.CalledProcessError(-1, args) + raise CoreCommandError(-1, args) def check_cmd(args, **kwargs): @@ -213,7 +214,7 @@ def check_cmd(args, **kwargs): :param dict kwargs: keyword arguments to pass to subprocess.Popen :return: combined stdout and stderr :rtype: str - :raises subprocess.CalledProcessError: when there is a non-zero exit status or the file to execute is not found + :raises CoreCommandError: when there is a non-zero exit status or the file to execute is not found """ kwargs["stdout"] = subprocess.PIPE kwargs["stderr"] = subprocess.STDOUT @@ -223,10 +224,10 @@ def check_cmd(args, **kwargs): stdout, _ = p.communicate() status = p.wait() if status != 0: - raise subprocess.CalledProcessError(status, args, stdout) + raise CoreCommandError(status, args, stdout) return stdout.strip() except OSError: - raise subprocess.CalledProcessError(-1, args) + raise CoreCommandError(-1, args) def hex_dump(s, bytes_per_word=2, words_per_line=8): diff --git a/daemon/core/netns/nodes.py b/daemon/core/netns/nodes.py index 0fe6c3d7..a225eb6f 100644 --- a/daemon/core/netns/nodes.py +++ b/daemon/core/netns/nodes.py @@ -4,11 +4,11 @@ implementing specific node types. """ import socket -import subprocess import threading from socket import AF_INET from socket import AF_INET6 +from core import CoreCommandError from core import constants from core import logger from core.coreobj import PyCoreNetIf @@ -68,7 +68,7 @@ class CtrlNet(LxBrNet): Startup functionality for the control network. :return: nothing - :raises subprocess.CalledProcessError: when there is a command exception + :raises CoreCommandError: when there is a command exception """ if self.detectoldbridge(): return @@ -134,16 +134,15 @@ class CtrlNet(LxBrNet): if self.serverintf is not None: try: utils.check_cmd([constants.BRCTL_BIN, "delif", self.brname, self.serverintf]) - except subprocess.CalledProcessError as e: - logger.exception("error deleting server interface %s from bridge %s: %s", - self.serverintf, self.brname, e.output) + except CoreCommandError: + logger.exception("error deleting server interface %s from bridge %s", self.serverintf, self.brname) if self.updown_script is not None: try: logger.info("interface %s updown script (%s shutdown) called", self.brname, self.updown_script) utils.check_cmd([self.updown_script, self.brname, "shutdown"]) - except subprocess.CalledProcessError as e: - logger.exception("error issuing shutdown script shutdown: %s", e.output) + except CoreCommandError: + logger.exception("error issuing shutdown script shutdown") LxBrNet.shutdown(self) @@ -328,7 +327,7 @@ class HubNode(LxBrNet): :param int objid: node id :param str name: node namee :param bool start: start flag - :raises subprocess.CalledProcessError: when there is a command exception + :raises CoreCommandError: when there is a command exception """ LxBrNet.__init__(self, session, objid, name, start) @@ -479,7 +478,7 @@ class RJ45Node(PyCoreNode, PyCoreNetIf): Set the interface in the up state. :return: nothing - :raises subprocess.CalledProcessError: when there is a command exception + :raises CoreCommandError: when there is a command exception """ # interface will also be marked up during net.attach() self.savestate() @@ -500,8 +499,8 @@ class RJ45Node(PyCoreNode, PyCoreNetIf): utils.check_cmd([constants.IP_BIN, "link", "set", self.localname, "down"]) utils.check_cmd([constants.IP_BIN, "addr", "flush", "dev", self.localname]) utils.check_cmd([constants.TC_BIN, "qdisc", "del", "dev", self.localname, "root"]) - except subprocess.CalledProcessError as e: - logger.exception("error shutting down: %s", e.output) + except CoreCommandError: + logger.exception("error shutting down") self.up = False self.restorestate() @@ -619,7 +618,7 @@ class RJ45Node(PyCoreNode, PyCoreNetIf): :param str addr: address to add :return: nothing - :raises subprocess.CalledProcessError: when there is a command exception + :raises CoreCommandError: when there is a command exception """ if self.up: utils.check_cmd([constants.IP_BIN, "addr", "add", str(addr), "dev", self.name]) @@ -632,7 +631,7 @@ class RJ45Node(PyCoreNode, PyCoreNetIf): :param str addr: address to delete :return: nothing - :raises subprocess.CalledProcessError: when there is a command exception + :raises CoreCommandError: when there is a command exception """ if self.up: utils.check_cmd([constants.IP_BIN, "addr", "del", str(addr), "dev", self.name]) @@ -645,7 +644,7 @@ class RJ45Node(PyCoreNode, PyCoreNetIf): interface for emulation purposes. TODO: save/restore the PROMISC flag :return: nothing - :raises subprocess.CalledProcessError: when there is a command exception + :raises CoreCommandError: when there is a command exception """ self.old_up = False self.old_addrs = [] @@ -672,7 +671,7 @@ class RJ45Node(PyCoreNode, PyCoreNetIf): Restore the addresses and other interface state after using it. :return: nothing - :raises subprocess.CalledProcessError: when there is a command exception + :raises CoreCommandError: when there is a command exception """ for addr in self.old_addrs: if addr[1] is None: @@ -704,7 +703,7 @@ class RJ45Node(PyCoreNode, PyCoreNetIf): :param list[str]|str args: 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 + :raises CoreCommandError: when a non-zero exit status occurs """ raise NotImplementedError diff --git a/daemon/core/netns/openvswitch.py b/daemon/core/netns/openvswitch.py index bb515d67..341ab92a 100644 --- a/daemon/core/netns/openvswitch.py +++ b/daemon/core/netns/openvswitch.py @@ -3,11 +3,11 @@ TODO: probably goes away, or implement the usage of "unshare", or docker formal. """ import socket -import subprocess import threading from socket import AF_INET from socket import AF_INET6 +from core import CoreCommandError from core import constants from core import logger from core.coreobj import PyCoreNet @@ -81,7 +81,7 @@ class OvsNet(PyCoreNet): """ :return: - :raises subprocess.CalledProcessError: when there is a command exception + :raises CoreCommandError: when there is a command exception """ utils.check_cmd([constants.OVS_BIN, "add-br", self.bridge_name]) @@ -112,8 +112,8 @@ class OvsNet(PyCoreNet): [constants.EBTABLES_BIN, "-D", "FORWARD", "--logical-in", self.bridge_name, "-j", self.bridge_name], [constants.EBTABLES_BIN, "-X", self.bridge_name] ]) - except subprocess.CalledProcessError as e: - logger.exception("error bringing bridge down and removing it: %s", e.output) + except CoreCommandError: + logger.exception("error bringing bridge down and removing it") # removes veth pairs used for bridge-to-bridge connections for interface in self.netifs(): @@ -404,16 +404,16 @@ class OvsCtrlNet(OvsNet): if self.serverintf: try: utils.check_cmd([constants.OVS_BIN, "del-port", self.bridge_name, self.serverintf]) - except subprocess.CalledProcessError as e: - logger.exception("error deleting server interface %s to controlnet bridge %s: %s", - self.serverintf, self.bridge_name, e.output) + except CoreCommandError: + logger.exception("error deleting server interface %s to controlnet bridge %s", + self.serverintf, self.bridge_name) if self.updown_script: try: logger.info("interface %s updown script (%s shutdown) called", self.bridge_name, self.updown_script) utils.check_cmd([self.updown_script, self.bridge_name, "shutdown"]) - except subprocess.CalledProcessError as e: - logger.exception("error during updown script shutdown: %s", e.output) + except CoreCommandError: + logger.exception("error during updown script shutdown") OvsNet.shutdown(self) diff --git a/daemon/core/netns/vif.py b/daemon/core/netns/vif.py index eee8801b..b7d77d23 100644 --- a/daemon/core/netns/vif.py +++ b/daemon/core/netns/vif.py @@ -2,9 +2,9 @@ virtual ethernet classes that implement the interfaces available under Linux. """ -import subprocess import time +from core import CoreCommandError from core import constants from core import logger from core.coreobj import PyCoreNetIf @@ -31,7 +31,7 @@ class VEth(PyCoreNetIf): :param mtu: interface mtu :param net: network :param bool start: start flag - :raises subprocess.CalledProcessError: when there is a command exception + :raises CoreCommandError: when there is a command exception """ # note that net arg is ignored PyCoreNetIf.__init__(self, node=node, name=name, mtu=mtu) @@ -45,7 +45,7 @@ class VEth(PyCoreNetIf): Interface startup logic. :return: nothing - :raises subprocess.CalledProcessError: when there is a command exception + :raises CoreCommandError: when there is a command exception """ utils.check_cmd([constants.IP_BIN, "link", "add", "name", self.localname, "type", "veth", "peer", "name", self.name]) @@ -64,14 +64,14 @@ class VEth(PyCoreNetIf): if self.node: try: self.node.check_cmd([constants.IP_BIN, "-6", "addr", "flush", "dev", self.name]) - except subprocess.CalledProcessError as e: - logger.exception("error shutting down interface: %s", e.output) + except CoreCommandError: + logger.exception("error shutting down interface") if self.localname: try: utils.check_cmd([constants.IP_BIN, "link", "delete", self.localname]) - except subprocess.CalledProcessError as e: - logger.exception("error deleting link: %s", e.output) + except CoreCommandError: + logger.exception("error deleting link") self.up = False @@ -125,8 +125,8 @@ class TunTap(PyCoreNetIf): try: self.node.check_cmd([constants.IP_BIN, "-6", "addr", "flush", "dev", self.name]) - except subprocess.CalledProcessError as e: - logger.exception("error shutting down tunnel tap: %s", e.output) + except CoreCommandError: + logger.exception("error shutting down tunnel tap") self.up = False @@ -212,7 +212,7 @@ class TunTap(PyCoreNetIf): end of the TAP. :return: nothing - :raises subprocess.CalledProcessError: when there is a command exception + :raises CoreCommandError: when there is a command exception """ self.waitfordevicelocal() netns = str(self.node.pid) @@ -254,7 +254,7 @@ class GreTap(PyCoreNetIf): :param ttl: ttl value :param key: gre tap key :param bool start: start flag - :raises subprocess.CalledProcessError: when there is a command exception + :raises CoreCommandError: when there is a command exception """ PyCoreNetIf.__init__(self, node=node, name=name, mtu=mtu) self.session = session @@ -297,8 +297,8 @@ class GreTap(PyCoreNetIf): utils.check_cmd(args) args = ["ip", "link", "del", self.localname] utils.check_cmd(args) - except subprocess.CalledProcessError as e: - logger.exception("error during shutdown: %s", e.output) + except CoreCommandError: + logger.exception("error during shutdown") self.localname = None diff --git a/daemon/core/netns/vnet.py b/daemon/core/netns/vnet.py index 8467a87d..545ca648 100644 --- a/daemon/core/netns/vnet.py +++ b/daemon/core/netns/vnet.py @@ -4,10 +4,10 @@ Linux Ethernet bridging and ebtables rules. """ import os -import subprocess import threading import time +from core import CoreCommandError from core import constants from core import logger from core.coreobj import PyCoreNet @@ -272,7 +272,7 @@ class LxBrNet(PyCoreNet): Linux bridge starup logic. :return: nothing - :raises subprocess.CalledProcessError: when there is a command exception + :raises CoreCommandError: when there is a command exception """ utils.check_cmd([constants.BRCTL_BIN, "addbr", self.brname]) @@ -311,8 +311,8 @@ class LxBrNet(PyCoreNet): [constants.EBTABLES_BIN, "-D", "FORWARD", "--logical-in", self.brname, "-j", self.brname], [constants.EBTABLES_BIN, "-X", self.brname] ]) - except subprocess.CalledProcessError as e: - logger.exception("error during shutdown: %s", e.output) + except CoreCommandError: + logger.exception("error during shutdown") # removes veth pairs used for bridge-to-bridge connections for netif in self.netifs(): diff --git a/daemon/core/netns/vnode.py b/daemon/core/netns/vnode.py index 12784d18..987fdac5 100644 --- a/daemon/core/netns/vnode.py +++ b/daemon/core/netns/vnode.py @@ -7,9 +7,9 @@ import random import shutil import signal import string -import subprocess import threading +from core import CoreCommandError from core import constants from core import logger from core.coreobj import PyCoreNetIf @@ -189,7 +189,7 @@ class SimpleLxcNode(PyCoreNode): :param list[str]|str args: command to run :return: combined stdout and stderr :rtype: str - :raises subprocess.CalledProcessError: when a non-zero exit status occurs + :raises CoreCommandError: when a non-zero exit status occurs """ return self.client.check_cmd(args) @@ -209,14 +209,14 @@ class SimpleLxcNode(PyCoreNode): :param str source: source directory to mount :param str target: target directory to create :return: nothing - :raises subprocess.CalledProcessError: when a non-zero exit status occurs + :raises CoreCommandError: when a non-zero exit status occurs """ source = os.path.abspath(source) logger.info("mounting %s at %s" % (source, target)) cmd = 'mkdir -p "%s" && %s -n --bind "%s" "%s"' % (target, constants.MOUNT_BIN, source, target) status, output = self.client.shcmd_result(cmd) if status: - raise subprocess.CalledProcessError(status, cmd, output) + raise CoreCommandError(status, cmd, output) self._mounts.append((source, target)) def umount(self, target): @@ -229,8 +229,8 @@ class SimpleLxcNode(PyCoreNode): logger.info("unmounting: %s", target) try: self.check_cmd([constants.UMOUNT_BIN, "-n", "-l", target]) - except subprocess.CalledProcessError as e: - logger.exception("error during unmount: %s", e.output) + except CoreCommandError: + logger.exception("error during unmount") def newifindex(self): """ @@ -339,7 +339,7 @@ class SimpleLxcNode(PyCoreNode): :param int ifindex: index of interface to set hardware address for :param core.misc.ipaddress.MacAddress addr: hardware address to set :return: nothing - :raises subprocess.CalledProcessError: when a non-zero exit status occurs + :raises CoreCommandError: when a non-zero exit status occurs """ self._netif[ifindex].sethwaddr(addr) if self.up: @@ -372,7 +372,7 @@ class SimpleLxcNode(PyCoreNode): :param int ifindex: index of interface to delete address from :param str addr: address to delete from interface :return: nothing - :raises subprocess.CalledProcessError: when a non-zero exit status occurs + :raises CoreCommandError: when a non-zero exit status occurs """ try: self._netif[ifindex].deladdr(addr) @@ -389,7 +389,7 @@ class SimpleLxcNode(PyCoreNode): :param int ifindex: index of interface to delete address types from :param tuple[str] address_types: address types to delete :return: nothing - :raises subprocess.CalledProcessError: when a non-zero exit status occurs + :raises CoreCommandError: when a non-zero exit status occurs """ interface_name = self.ifname(ifindex) addresses = self.client.getaddr(interface_name, rescan=True) @@ -488,7 +488,7 @@ class SimpleLxcNode(PyCoreNode): :param str srcname: source file name :param str filename: file name to add :return: nothing - :raises subprocess.CalledProcessError: when a non-zero exit status occurs + :raises CoreCommandError: when a non-zero exit status occurs """ logger.info("adding file from %s to %s", srcname, filename) directory = os.path.dirname(filename) @@ -496,7 +496,7 @@ class SimpleLxcNode(PyCoreNode): cmd = 'mkdir -p "%s" && mv "%s" "%s" && sync' % (directory, srcname, filename) status, output = self.client.shcmd_result(cmd) if status: - raise subprocess.CalledProcessError(status, cmd, output) + raise CoreCommandError(status, cmd, output) class LxcNode(SimpleLxcNode): diff --git a/daemon/core/netns/vnodeclient.py b/daemon/core/netns/vnodeclient.py index 5b61decb..5d5ebea0 100644 --- a/daemon/core/netns/vnodeclient.py +++ b/daemon/core/netns/vnodeclient.py @@ -6,10 +6,10 @@ by invoking the vcmd shell command. """ import os -import subprocess import vcmd +from core import CoreCommandError from core import constants from core import logger from core.misc import utils @@ -106,11 +106,11 @@ class VnodeClient(object): :param list[str]|str args: command to run :return: combined stdout and stderr :rtype: str - :raises subprocess.CalledProcessError: when there is a non-zero exit status + :raises core.CoreCommandError: when there is a non-zero exit status """ status, output = self.cmd_output(args) if status != 0: - raise subprocess.CalledProcessError(status, args, output) + raise CoreCommandError(status, args, output) return output.strip() def popen(self, args): diff --git a/daemon/core/phys/pnodes.py b/daemon/core/phys/pnodes.py index 4e47c71f..eb3d9bbb 100644 --- a/daemon/core/phys/pnodes.py +++ b/daemon/core/phys/pnodes.py @@ -6,6 +6,7 @@ import os import subprocess import threading +from core import CoreCommandError from core import constants from core import logger from core.coreobj import PyCoreNode @@ -91,11 +92,11 @@ class PhysicalNode(PyCoreNode): :param list[str]|str args: command to run :return: combined stdout and stderr :rtype: str - :raises subprocess.CalledProcessError: when a non-zero exit status occurs + :raises CoreCommandError: when a non-zero exit status occurs """ status, output = self.cmd_output(args) if status: - raise subprocess.CalledProcessError(status, args, output) + raise CoreCommandError(status, args, output) return output.strip() def shcmd(self, cmdstr, sh="/bin/sh"): @@ -224,8 +225,8 @@ class PhysicalNode(PyCoreNode): logger.info("unmounting '%s'" % target) try: self.check_cmd([constants.UMOUNT_BIN, "-l", target]) - except subprocess.CalledProcessError as e: - logger.exception("unmounting failed for %s: %s", target, e.output) + except CoreCommandError: + logger.exception("unmounting failed for %s", target) def opennodefile(self, filename, mode="w"): dirname, basename = os.path.split(filename) diff --git a/daemon/core/service.py b/daemon/core/service.py index 385ca524..c54d8c4a 100644 --- a/daemon/core/service.py +++ b/daemon/core/service.py @@ -6,10 +6,10 @@ The CoreServices class handles configuration messages for sending a list of available services to the GUI and for configuring individual services. """ -import subprocess import time from itertools import repeat +from core import CoreCommandError from core import logger from core.conf import Configurable from core.conf import ConfigurableManager @@ -413,7 +413,7 @@ class CoreServices(ConfigurableManager): logger.info("validating service %s using: %s", service._name, args) try: node.check_cmd(args) - except subprocess.CalledProcessError: + except CoreCommandError: logger.exception("validate command failed") status = -1 @@ -444,7 +444,7 @@ class CoreServices(ConfigurableManager): for args in service._shutdown: try: node.check_cmd(args) - except subprocess.CalledProcessError: + except CoreCommandError: logger.exception("error running stop command %s", args) # TODO: determine if its ok to just return the bad exit status status = "-1" @@ -756,8 +756,8 @@ class CoreServices(ConfigurableManager): for args in cmds: try: node.check_cmd(args) - except subprocess.CalledProcessError: - logger.exception("error starting command %s", args) + except CoreCommandError: + logger.exception("error starting command") fail += "Start %s(%s)," % (s._name, args) if event_type == EventTypes.PAUSE.value: status = self.validatenodeservice(node, s, services) diff --git a/daemon/core/services/utility.py b/daemon/core/services/utility.py index 87289639..6049c9a5 100644 --- a/daemon/core/services/utility.py +++ b/daemon/core/services/utility.py @@ -3,8 +3,8 @@ utility.py: defines miscellaneous utility services. """ import os -import subprocess +from core import CoreCommandError from core import constants from core.misc import utils from core.misc.ipaddress import Ipv4Prefix @@ -419,7 +419,7 @@ class HttpService(UtilService): """ try: status, result = utils.cmd_output(['a2query', '-v']) - except subprocess.CalledProcessError: + except CoreCommandError: status = -1 if status == 0 and result[:3] == '2.4': diff --git a/daemon/core/xen/xen.py b/daemon/core/xen/xen.py index 1cdbf6f0..95ae72fe 100644 --- a/daemon/core/xen/xen.py +++ b/daemon/core/xen/xen.py @@ -13,6 +13,7 @@ import threading import crypt +from core import CoreCommandError from core import constants from core import logger from core.coreobj import PyCoreNetIf @@ -263,7 +264,7 @@ class XenNode(PyCoreNode): if self.booted: utils.check_cmd([XM_PATH, "destroy", self.vmname]) self.booted = False - except (OSError, subprocess.CalledProcessError): + except CoreCommandError: # ignore this error too, the VM may have exited already logger.exception("error during shutdown")