core3: add different exceptions
From now on there are different exceptions which can be raise on different occasions. fixes QubesOS/qubes-issues#1279
This commit is contained in:
parent
4cf56b40bb
commit
96efb4568a
@ -57,6 +57,8 @@ import lxml.etree
|
|||||||
|
|
||||||
|
|
||||||
import qubes.config
|
import qubes.config
|
||||||
|
import qubes.events
|
||||||
|
import qubes.exc
|
||||||
import qubes.ext
|
import qubes.ext
|
||||||
|
|
||||||
|
|
||||||
@ -78,14 +80,6 @@ except ImportError:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class QubesException(Exception):
|
|
||||||
'''Exception that can be shown to the user'''
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
import qubes.events
|
|
||||||
|
|
||||||
|
|
||||||
class VMMConnection(object):
|
class VMMConnection(object):
|
||||||
'''Connection to Virtual Machine Manager (libvirt)'''
|
'''Connection to Virtual Machine Manager (libvirt)'''
|
||||||
|
|
||||||
@ -103,8 +97,8 @@ class VMMConnection(object):
|
|||||||
@offline_mode.setter
|
@offline_mode.setter
|
||||||
def offline_mode(self, value):
|
def offline_mode(self, value):
|
||||||
if value and self._libvirt_conn is not None:
|
if value and self._libvirt_conn is not None:
|
||||||
raise QubesException(
|
raise qubes.exc.QubesException(
|
||||||
"Cannot change offline mode while already connected")
|
'Cannot change offline mode while already connected')
|
||||||
|
|
||||||
self._offline_mode = value
|
self._offline_mode = value
|
||||||
|
|
||||||
@ -120,7 +114,8 @@ class VMMConnection(object):
|
|||||||
return
|
return
|
||||||
if self._offline_mode:
|
if self._offline_mode:
|
||||||
# Do not initialize in offline mode
|
# Do not initialize in offline mode
|
||||||
raise QubesException("VMM operations disabled in offline mode")
|
raise qubes.exc.QubesException(
|
||||||
|
'VMM operations disabled in offline mode')
|
||||||
|
|
||||||
if 'xen.lowlevel.xs' in sys.modules:
|
if 'xen.lowlevel.xs' in sys.modules:
|
||||||
self._xs = xen.lowlevel.xs.xs()
|
self._xs = xen.lowlevel.xs.xs()
|
||||||
@ -128,7 +123,7 @@ class VMMConnection(object):
|
|||||||
self._xc = xen.lowlevel.xc.xc()
|
self._xc = xen.lowlevel.xc.xc()
|
||||||
self._libvirt_conn = libvirt.open(qubes.config.defaults['libvirt_uri'])
|
self._libvirt_conn = libvirt.open(qubes.config.defaults['libvirt_uri'])
|
||||||
if self._libvirt_conn is None:
|
if self._libvirt_conn is None:
|
||||||
raise QubesException("Failed connect to libvirt driver")
|
raise qubes.exc.QubesException('Failed connect to libvirt driver')
|
||||||
libvirt.registerErrorHandler(self._libvirt_error_handler, None)
|
libvirt.registerErrorHandler(self._libvirt_error_handler, None)
|
||||||
atexit.register(self._libvirt_conn.close)
|
atexit.register(self._libvirt_conn.close)
|
||||||
|
|
||||||
@ -1371,7 +1366,7 @@ class Qubes(PropertyHolder):
|
|||||||
if isinstance(vm, qubes.vm.templatevm.TemplateVM):
|
if isinstance(vm, qubes.vm.templatevm.TemplateVM):
|
||||||
appvms = self.domains.get_vms_based_on(vm)
|
appvms = self.domains.get_vms_based_on(vm)
|
||||||
if appvms:
|
if appvms:
|
||||||
raise QubesException(
|
raise qubes.exc.QubesException(
|
||||||
'Cannot remove template that has dependent AppVMs. '
|
'Cannot remove template that has dependent AppVMs. '
|
||||||
'Affected are: {}'.format(', '.join(
|
'Affected are: {}'.format(', '.join(
|
||||||
vm.name for name in sorted(appvms))))
|
vm.name for name in sorted(appvms))))
|
||||||
@ -1399,8 +1394,9 @@ class Qubes(PropertyHolder):
|
|||||||
return
|
return
|
||||||
if 'ntpd' in newvalue.services:
|
if 'ntpd' in newvalue.services:
|
||||||
if newvalue.services['ntpd']:
|
if newvalue.services['ntpd']:
|
||||||
raise QubesException('Cannot set {!r} as {!r} property since '
|
raise qubes.exc.QubesVMError(newvalue,
|
||||||
'it has ntpd enabled.'.format(newvalue, name))
|
'Cannot set {!r} as {!r} since it has ntpd enabled.'.format(
|
||||||
|
newvalue.name, name))
|
||||||
else:
|
else:
|
||||||
newvalue.services['ntpd'] = False
|
newvalue.services['ntpd'] = False
|
||||||
|
|
||||||
@ -1414,8 +1410,9 @@ class Qubes(PropertyHolder):
|
|||||||
if newvalue is not None and oldvalue is not None \
|
if newvalue is not None and oldvalue is not None \
|
||||||
and oldvalue.is_running() and not newvalue.is_running() \
|
and oldvalue.is_running() and not newvalue.is_running() \
|
||||||
and self.domains.get_vms_connected_to(oldvalue):
|
and self.domains.get_vms_connected_to(oldvalue):
|
||||||
raise QubesException('Cannot change default_netvm to domain that '
|
raise qubes.exc.QubesVMNotRunningError(newvalue,
|
||||||
'is not running ({!r}).'.format(newvalue))
|
'Cannot change {!r} to domain that '
|
||||||
|
'is not running ({!r}).'.format(name, newvalue.name))
|
||||||
|
|
||||||
|
|
||||||
@qubes.events.handler('property-set:default_fw_netvm')
|
@qubes.events.handler('property-set:default_fw_netvm')
|
||||||
|
147
qubes/exc.py
Normal file
147
qubes/exc.py
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
#!/usr/bin/python2 -O
|
||||||
|
# vim: fileencoding=utf-8
|
||||||
|
|
||||||
|
#
|
||||||
|
# The Qubes OS Project, https://www.qubes-os.org/
|
||||||
|
#
|
||||||
|
# Copyright (C) 2015 Joanna Rutkowska <joanna@invisiblethingslab.com>
|
||||||
|
# Copyright (C) 2015 Wojtek Porczyk <woju@invisiblethingslab.com>
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along
|
||||||
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
#
|
||||||
|
|
||||||
|
'''
|
||||||
|
Qubes OS exception hierarchy
|
||||||
|
'''
|
||||||
|
|
||||||
|
class QubesException(Exception):
|
||||||
|
'''Exception that can be shown to the user'''
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class QubesVMNotFoundError(QubesException, KeyError):
|
||||||
|
'''Domain cannot be found in the system'''
|
||||||
|
def __init__(self, vmname):
|
||||||
|
super(QubesVMNotFoundError, self).__init__(
|
||||||
|
'No such domain: {!r}'.format(vmname))
|
||||||
|
self.vmname = vmname
|
||||||
|
|
||||||
|
|
||||||
|
class QubesVMError(QubesException):
|
||||||
|
'''Some problem with domain state.'''
|
||||||
|
def __init__(self, vm, msg):
|
||||||
|
super(QubesVMError, self).__init__(msg)
|
||||||
|
self.vm = vm
|
||||||
|
|
||||||
|
|
||||||
|
class QubesVMNotStartedError(QubesVMError):
|
||||||
|
'''Domain is not started.
|
||||||
|
|
||||||
|
This exception is thrown when machine is halted, but should be started
|
||||||
|
(that is, either running or paused).
|
||||||
|
'''
|
||||||
|
def __init__(self, vm, msg=None):
|
||||||
|
super(QubesVMNotStartedError, self).__init__(vm,
|
||||||
|
msg or 'Domain is powered off: {!r}'.format(vm.name))
|
||||||
|
|
||||||
|
|
||||||
|
class QubesVMNotRunningError(QubesVMNotStartedError):
|
||||||
|
'''Domain is not running.
|
||||||
|
|
||||||
|
This exception is thrown when machine should be running but is either
|
||||||
|
halted or paused.
|
||||||
|
'''
|
||||||
|
def __init__(self, vm, msg=None):
|
||||||
|
super(QubesVMNotRunningError, self).__init__(vm,
|
||||||
|
msg or 'Domain not running (either powered off or paused): {!r}' \
|
||||||
|
.format(vm.name))
|
||||||
|
|
||||||
|
|
||||||
|
class QubesVMNotPausedError(QubesVMNotStartedError):
|
||||||
|
'''Domain is not paused.
|
||||||
|
|
||||||
|
This exception is thrown when machine should be paused, but is not.
|
||||||
|
'''
|
||||||
|
def __init__(self, vm, msg=None):
|
||||||
|
super(QubesVMNotPausedError, self).__init__(vm,
|
||||||
|
msg or 'Domain is not paused: {!r}'.format(vm.name))
|
||||||
|
|
||||||
|
|
||||||
|
class QubesVMNotSuspendedError(QubesVMError):
|
||||||
|
'''Domain is not suspended.
|
||||||
|
|
||||||
|
This exception is thrown when machine should be suspended but is either
|
||||||
|
halted or running.
|
||||||
|
'''
|
||||||
|
def __init__(self, vm, msg=None):
|
||||||
|
super(QubesVMNotSuspendedError, self).__init__(vm,
|
||||||
|
msg or 'Domain is not suspended: {!r}'.format(vm.name))
|
||||||
|
|
||||||
|
|
||||||
|
class QubesVMNotHaltedError(QubesVMError):
|
||||||
|
'''Domain is not halted.
|
||||||
|
|
||||||
|
This exception is thrown when machine should be halted, but is not (either
|
||||||
|
running or paused).
|
||||||
|
'''
|
||||||
|
def __init__(self, vm, msg=None):
|
||||||
|
super(QubesVMNotHaltedError, self).__init__(vm,
|
||||||
|
msg or 'Domain is not powered off: {!r}'.format(vm.name))
|
||||||
|
|
||||||
|
|
||||||
|
class QubesNoTemplateError(QubesVMError):
|
||||||
|
'''Cannot start domain, because there is no template'''
|
||||||
|
def __init__(self, vm, msg=None):
|
||||||
|
super(QubesNoTemplateError, self).__init__(
|
||||||
|
msg or 'Template for the domain {!r} not found'.format(vm.name))
|
||||||
|
|
||||||
|
|
||||||
|
class QubesValueError(QubesException, ValueError):
|
||||||
|
'''Cannot set some value, because it is invalid, out of bounds, etc.'''
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class QubesPropertyValueError(QubesValueError):
|
||||||
|
'''Cannot set value of qubes.property, because user-supplied value is wrong.
|
||||||
|
'''
|
||||||
|
def __init__(self, holder, prop, value, msg=None):
|
||||||
|
super(QubesPropertyValueError, self).__init__(
|
||||||
|
msg or 'Invalid value {!r} for property {!r} of {!r}'.format(
|
||||||
|
value, prop.__name__, holder))
|
||||||
|
self.holder = holder
|
||||||
|
self.prop = prop
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
|
||||||
|
class QubesNotImplementedError(QubesException, NotImplementedError):
|
||||||
|
'''Thrown at user when some feature is not implemented'''
|
||||||
|
def __init__(self, msg=None):
|
||||||
|
super(QubesNotImplementedError, self).__init__(
|
||||||
|
msg or 'This feature is not available')
|
||||||
|
|
||||||
|
|
||||||
|
class BackupCancelledError(QubesException):
|
||||||
|
'''Thrown at user when backup was manually cancelled'''
|
||||||
|
def __init__(self, msg=None):
|
||||||
|
super(BackupCancelledError, self).__init__(
|
||||||
|
msg or 'Backup cancelled')
|
||||||
|
|
||||||
|
|
||||||
|
class QubesMemoryError(QubesException, MemoryError):
|
||||||
|
'''Cannot start domain, because not enough memory is available'''
|
||||||
|
def __init__(self, vm, msg=None):
|
||||||
|
super(QubesMemoryError, self).__init__(
|
||||||
|
msg or 'Not enough memory to start domain {!r}'.format(vm.name))
|
||||||
|
self.vm = vm
|
@ -35,6 +35,7 @@ import subprocess
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
import qubes
|
import qubes
|
||||||
|
import qubes.exc
|
||||||
import qubes.utils
|
import qubes.utils
|
||||||
|
|
||||||
BLKSIZE = 512
|
BLKSIZE = 512
|
||||||
@ -214,22 +215,22 @@ class VMStorage(object):
|
|||||||
|
|
||||||
def verify_files(self):
|
def verify_files(self):
|
||||||
if not os.path.exists(self.vm.dir_path):
|
if not os.path.exists(self.vm.dir_path):
|
||||||
raise qubes.QubesException(
|
raise qubes.exc.QubesVMError(self.vm,
|
||||||
'VM directory does not exist: {}'.format(self.vm.dir_path))
|
'VM directory does not exist: {}'.format(self.vm.dir_path))
|
||||||
|
|
||||||
if hasattr(self.vm, 'root_img') and not os.path.exists(self.root_img):
|
if hasattr(self.vm, 'root_img') and not os.path.exists(self.root_img):
|
||||||
raise qubes.QubesException(
|
raise qubes.exc.QubesVMError(self.vm,
|
||||||
'VM root image file does not exist: {}'.format(self.root_img))
|
'VM root image file does not exist: {}'.format(self.root_img))
|
||||||
|
|
||||||
if hasattr(self.vm, 'private_img') \
|
if hasattr(self.vm, 'private_img') \
|
||||||
and not os.path.exists(self.private_img):
|
and not os.path.exists(self.private_img):
|
||||||
raise qubes.QubesException(
|
raise qubes.exc.QubesVMError(self.vm,
|
||||||
'VM private image file does not exist: {}'.format(
|
'VM private image file does not exist: {}'.format(
|
||||||
self.private_img))
|
self.private_img))
|
||||||
|
|
||||||
if self.modules_img is not None \
|
if self.modules_img is not None \
|
||||||
and not os.path.exists(self.modules_img):
|
and not os.path.exists(self.modules_img):
|
||||||
raise qubes.QubesException(
|
raise qubes.exc.QubesVMError(self.vm,
|
||||||
'VM kernel modules image does not exists: {}'.format(
|
'VM kernel modules image does not exists: {}'.format(
|
||||||
self.modules_img))
|
self.modules_img))
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
import qubes
|
import qubes
|
||||||
|
import qubes.exc
|
||||||
import qubes.vm.adminvm
|
import qubes.vm.adminvm
|
||||||
|
|
||||||
import qubes.tests
|
import qubes.tests
|
||||||
@ -98,10 +99,10 @@ class TC_00_AdminVM(qubes.tests.QubesTestCase):
|
|||||||
self.assertEqual(self.vm.get_private_img_sz(), 0)
|
self.assertEqual(self.vm.get_private_img_sz(), 0)
|
||||||
|
|
||||||
def test_310_start(self):
|
def test_310_start(self):
|
||||||
with self.assertRaises(qubes.QubesException):
|
with self.assertRaises(qubes.exc.QubesException):
|
||||||
self.vm.start()
|
self.vm.start()
|
||||||
|
|
||||||
@unittest.skip('this functionality is undecided')
|
@unittest.skip('this functionality is undecided')
|
||||||
def test_311_suspend(self):
|
def test_311_suspend(self):
|
||||||
with self.assertRaises(qubes.QubesException):
|
with self.assertRaises(qubes.exc.QubesException):
|
||||||
self.vm.suspend()
|
self.vm.suspend()
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
import qubes
|
import qubes
|
||||||
|
import qubes.exc
|
||||||
import qubes.config
|
import qubes.config
|
||||||
import qubes.vm.qubesvm
|
import qubes.vm.qubesvm
|
||||||
|
|
||||||
@ -89,13 +90,13 @@ class TC_00_setters(qubes.tests.QubesTestCase):
|
|||||||
|
|
||||||
def test_014_setter_name_running(self):
|
def test_014_setter_name_running(self):
|
||||||
self.vm.running = True
|
self.vm.running = True
|
||||||
with self.assertRaises(qubes.QubesException):
|
with self.assertRaises(qubes.exc.QubesVMNotHaltedError):
|
||||||
qubes.vm.qubesvm._setter_name(self.vm, self.prop, 'testname')
|
qubes.vm.qubesvm._setter_name(self.vm, self.prop, 'testname')
|
||||||
|
|
||||||
def test_015_setter_name_installed_by_rpm(self):
|
def test_015_setter_name_installed_by_rpm(self):
|
||||||
# pylint: disable=invalid-name
|
# pylint: disable=invalid-name
|
||||||
self.vm.installed_by_rpm = True
|
self.vm.installed_by_rpm = True
|
||||||
with self.assertRaises(qubes.QubesException):
|
with self.assertRaises(qubes.exc.QubesException):
|
||||||
qubes.vm.qubesvm._setter_name(self.vm, self.prop, 'testname')
|
qubes.vm.qubesvm._setter_name(self.vm, self.prop, 'testname')
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import qubes
|
import qubes.exc
|
||||||
import qubes.tools
|
import qubes.tools
|
||||||
|
|
||||||
parser = qubes.tools.QubesArgumentParser(
|
parser = qubes.tools.QubesArgumentParser(
|
||||||
@ -45,7 +45,7 @@ def main(args=None):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
args.vm.force_shutdown()
|
args.vm.force_shutdown()
|
||||||
except (IOError, OSError, qubes.QubesException) as e:
|
except (IOError, OSError, qubes.exc.QubesException) as e:
|
||||||
parser.error_runtime(str(e))
|
parser.error_runtime(str(e))
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
@ -131,11 +131,7 @@ def main(args=None):
|
|||||||
preparing_dvm=args.preparing_dvm,
|
preparing_dvm=args.preparing_dvm,
|
||||||
start_guid=args.start_guid)
|
start_guid=args.start_guid)
|
||||||
# notify_function=
|
# notify_function=
|
||||||
except MemoryError:
|
except qubes.exc.QubesException as e:
|
||||||
# TODO tray
|
|
||||||
parser.error_runtime(
|
|
||||||
'not enough memory to start domain {!r}'.format(vm.name))
|
|
||||||
except qubes.QubesException as e:
|
|
||||||
parser.error_runtime('Qubes error: {!r}'.format(e))
|
parser.error_runtime('Qubes error: {!r}'.format(e))
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
@ -32,7 +32,7 @@ import docutils
|
|||||||
import docutils.core
|
import docutils.core
|
||||||
import docutils.io
|
import docutils.io
|
||||||
|
|
||||||
import qubes
|
import qubes.exc
|
||||||
|
|
||||||
|
|
||||||
def get_timezone():
|
def get_timezone():
|
||||||
@ -103,4 +103,4 @@ def parse_size(size):
|
|||||||
size = size[:-len(unit)].strip()
|
size = size[:-len(unit)].strip()
|
||||||
return int(size)*multiplier
|
return int(size)*multiplier
|
||||||
|
|
||||||
raise qubes.QubesException("Invalid size: {0}.".format(size))
|
raise qubes.exc.QubesException("Invalid size: {0}.".format(size))
|
||||||
|
@ -291,8 +291,7 @@ class BaseVM(qubes.PropertyHolder):
|
|||||||
|
|
||||||
dev_match = re.match(r'([0-9a-f]+):([0-9a-f]+)\.([0-9a-f]+)', address)
|
dev_match = re.match(r'([0-9a-f]+):([0-9a-f]+)\.([0-9a-f]+)', address)
|
||||||
if not dev_match:
|
if not dev_match:
|
||||||
raise qubes.QubesException(
|
raise ValueError('Invalid PCI device address: {!r}'.format(address))
|
||||||
'Invalid PCI device address: {}'.format(address))
|
|
||||||
|
|
||||||
hostdev = lxml.etree.Element('hostdev', type='pci', managed='yes')
|
hostdev = lxml.etree.Element('hostdev', type='pci', managed='yes')
|
||||||
source = lxml.etree.Element('source')
|
source = lxml.etree.Element('source')
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
import qubes
|
import qubes
|
||||||
|
import qubes.exc
|
||||||
import qubes.vm.qubesvm
|
import qubes.vm.qubesvm
|
||||||
|
|
||||||
class AdminVM(qubes.vm.qubesvm.QubesVM):
|
class AdminVM(qubes.vm.qubesvm.QubesVM):
|
||||||
@ -150,7 +151,7 @@ class AdminVM(qubes.vm.qubesvm.QubesVM):
|
|||||||
.. seealso:
|
.. seealso:
|
||||||
:py:meth:`qubes.vm.qubesvm.QubesVM.start`
|
:py:meth:`qubes.vm.qubesvm.QubesVM.start`
|
||||||
''' # pylint: disable=unused-argument
|
''' # pylint: disable=unused-argument
|
||||||
raise qubes.QubesException('Cannot start Dom0 fake domain!')
|
raise qubes.exc.QubesVMError('Cannot start Dom0 fake domain!')
|
||||||
|
|
||||||
|
|
||||||
def suspend(self):
|
def suspend(self):
|
||||||
|
@ -42,8 +42,7 @@ import libvirt
|
|||||||
|
|
||||||
import qubes
|
import qubes
|
||||||
import qubes.config
|
import qubes.config
|
||||||
#import qubes.qmemman
|
import qubes.exc
|
||||||
#import qubes.qmemman_algo
|
|
||||||
import qubes.storage
|
import qubes.storage
|
||||||
import qubes.utils
|
import qubes.utils
|
||||||
import qubes.vm
|
import qubes.vm
|
||||||
@ -78,12 +77,13 @@ def _setter_name(self, prop, value):
|
|||||||
raise ValueError('{} value contains illegal characters'.format(
|
raise ValueError('{} value contains illegal characters'.format(
|
||||||
prop.__name__))
|
prop.__name__))
|
||||||
if self.is_running():
|
if self.is_running():
|
||||||
raise qubes.QubesException('Cannot change name of running VM')
|
raise qubes.exc.QubesVMNotHaltedError(
|
||||||
|
self, 'Cannot change name of running VM')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if self.installed_by_rpm:
|
if self.installed_by_rpm:
|
||||||
raise qubes.QubesException('Cannot rename VM installed by RPM -- '
|
raise qubes.exc.QubesException('Cannot rename VM installed by RPM '
|
||||||
'first clone VM and then use yum to remove package.')
|
'-- first clone VM and then use yum to remove package.')
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -97,10 +97,11 @@ def _setter_kernel(self, prop, value):
|
|||||||
qubes.config.system_path['qubes_kernels_base_dir'],
|
qubes.config.system_path['qubes_kernels_base_dir'],
|
||||||
value)
|
value)
|
||||||
if not os.path.exists(dirname):
|
if not os.path.exists(dirname):
|
||||||
raise qubes.QubesException('Kernel {!r} not installed'.format(value))
|
raise qubes.exc.QubesPropertyValueError(self, prop, value,
|
||||||
|
'Kernel {!r} not installed'.format(value))
|
||||||
for filename in ('vmlinuz', 'modules.img'):
|
for filename in ('vmlinuz', 'modules.img'):
|
||||||
if not os.path.exists(os.path.join(dirname, filename)):
|
if not os.path.exists(os.path.join(dirname, filename)):
|
||||||
raise qubes.QubesException(
|
raise qubes.exc.QubesPropertyValueError(
|
||||||
'Kernel {!r} not properly installed: missing {!r} file'.format(
|
'Kernel {!r} not properly installed: missing {!r} file'.format(
|
||||||
value, filename))
|
value, filename))
|
||||||
return value
|
return value
|
||||||
@ -557,8 +558,9 @@ class QubesVM(qubes.vm.BaseVM):
|
|||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
if self.is_running() and new_netvm is not None \
|
if self.is_running() and new_netvm is not None \
|
||||||
and not new_netvm.is_running():
|
and not new_netvm.is_running():
|
||||||
raise qubes.QubesException(
|
raise qubes.exc.QubesVMNotStartedError(new_netvm,
|
||||||
'Cannot dynamically attach to stopped NetVM')
|
'Cannot dynamically attach to stopped NetVM: {!r}'.format(
|
||||||
|
new_netvm))
|
||||||
|
|
||||||
if self.netvm is not None:
|
if self.netvm is not None:
|
||||||
del self.netvm.connected_vms[self]
|
del self.netvm.connected_vms[self]
|
||||||
@ -601,7 +603,8 @@ class QubesVM(qubes.vm.BaseVM):
|
|||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
# TODO not self.is_stopped() would be more appropriate
|
# TODO not self.is_stopped() would be more appropriate
|
||||||
if self.is_running():
|
if self.is_running():
|
||||||
raise qubes.QubesException('Cannot change name of running domain')
|
raise qubes.exc.QubesVMNotHaltedError(
|
||||||
|
'Cannot change name of running domain {!r}'.format(oldvalue))
|
||||||
|
|
||||||
|
|
||||||
@qubes.events.handler('property-set:name')
|
@qubes.events.handler('property-set:name')
|
||||||
@ -640,7 +643,7 @@ class QubesVM(qubes.vm.BaseVM):
|
|||||||
if subprocess.call(['sudo', 'systemctl',
|
if subprocess.call(['sudo', 'systemctl',
|
||||||
('enable' if value else 'disable'),
|
('enable' if value else 'disable'),
|
||||||
'qubes-vm@{}.service'.format(self.name)]):
|
'qubes-vm@{}.service'.format(self.name)]):
|
||||||
raise qubes.QubesException(
|
raise qubes.exc.QubesException(
|
||||||
'Failed to set autostart for VM via systemctl')
|
'Failed to set autostart for VM via systemctl')
|
||||||
|
|
||||||
|
|
||||||
@ -648,7 +651,7 @@ class QubesVM(qubes.vm.BaseVM):
|
|||||||
def on_device_pre_attached_pci(self, event, pci):
|
def on_device_pre_attached_pci(self, event, pci):
|
||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
if not os.path.exists('/sys/bus/pci/devices/0000:{}'.format(pci)):
|
if not os.path.exists('/sys/bus/pci/devices/0000:{}'.format(pci)):
|
||||||
raise qubes.QubesException('Invalid PCI device: {}'.format(pci))
|
raise qubes.exc.QubesException('Invalid PCI device: {}'.format(pci))
|
||||||
|
|
||||||
if not self.is_running():
|
if not self.is_running():
|
||||||
return
|
return
|
||||||
@ -707,7 +710,7 @@ class QubesVM(qubes.vm.BaseVM):
|
|||||||
# Intentionally not used is_running(): eliminate also "Paused",
|
# Intentionally not used is_running(): eliminate also "Paused",
|
||||||
# "Crashed", "Halting"
|
# "Crashed", "Halting"
|
||||||
if self.get_power_state() != 'Halted':
|
if self.get_power_state() != 'Halted':
|
||||||
raise qubes.QubesException('VM is already running!')
|
raise qubes.exc.QubesVMNotHaltedError(self)
|
||||||
|
|
||||||
self.log.info('Starting {}'.format(self.name))
|
self.log.info('Starting {}'.format(self.name))
|
||||||
|
|
||||||
@ -732,8 +735,7 @@ class QubesVM(qubes.vm.BaseVM):
|
|||||||
raise IOError('Failed to connect to qmemman: {!s}'.format(e))
|
raise IOError('Failed to connect to qmemman: {!s}'.format(e))
|
||||||
if not got_memory:
|
if not got_memory:
|
||||||
qmemman_client.close()
|
qmemman_client.close()
|
||||||
raise MemoryError(
|
raise qubes.exc.QubesMemoryError(self)
|
||||||
'Insufficient memory to start VM {!r}'.format(self.name))
|
|
||||||
|
|
||||||
# Bind pci devices to pciback driver
|
# Bind pci devices to pciback driver
|
||||||
for pci in self.devices['pci']:
|
for pci in self.devices['pci']:
|
||||||
@ -794,11 +796,12 @@ class QubesVM(qubes.vm.BaseVM):
|
|||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
'''Shutdown domain.
|
'''Shutdown domain.
|
||||||
|
|
||||||
:raises QubesException: when domain is already shut down.
|
:raises qubes.exc.QubesVMNotStartedError: \
|
||||||
|
when domain is already shut down.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
if not self.is_running():
|
if not self.is_running(): # TODO not self.is_halted()
|
||||||
raise qubes.QubesException("VM already stopped!")
|
raise qubes.exc.QubesVMNotStartedError(self)
|
||||||
|
|
||||||
self.libvirt_domain.shutdown()
|
self.libvirt_domain.shutdown()
|
||||||
|
|
||||||
@ -806,11 +809,12 @@ class QubesVM(qubes.vm.BaseVM):
|
|||||||
def force_shutdown(self):
|
def force_shutdown(self):
|
||||||
'''Forcefuly shutdown (destroy) domain.
|
'''Forcefuly shutdown (destroy) domain.
|
||||||
|
|
||||||
:raises QubesException: when domain is already shut down.
|
:raises qubes.exc.QubesVMNotStartedError: \
|
||||||
|
when domain is already shut down.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
if not self.is_running() and not self.is_paused():
|
if not self.is_running() and not self.is_paused():
|
||||||
raise qubes.QubesException('VM already stopped!')
|
raise qubes.exc.QubesVMNotStartedError(self)
|
||||||
|
|
||||||
self.libvirt_domain.destroy()
|
self.libvirt_domain.destroy()
|
||||||
|
|
||||||
@ -818,15 +822,19 @@ class QubesVM(qubes.vm.BaseVM):
|
|||||||
def suspend(self):
|
def suspend(self):
|
||||||
'''Suspend (pause) domain.
|
'''Suspend (pause) domain.
|
||||||
|
|
||||||
:raises qubes.QubesException: when domain is already shut down.
|
:raises qubes.exc.QubesVMNotRunnignError: \
|
||||||
:raises NotImplemetedError: when domain has PCI devices attached.
|
when domain is already shut down.
|
||||||
|
:raises qubes.exc.QubesNotImplemetedError: \
|
||||||
|
when domain has PCI devices attached.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
if not self.is_running() and not self.is_paused():
|
if not self.is_running() and not self.is_paused():
|
||||||
raise qubes.QubesException('VM already stopped!')
|
raise qubes.exc.QubesVMNotRunningError(self)
|
||||||
|
|
||||||
if len(self.devices['pci']) > 0:
|
if len(self.devices['pci']) > 0:
|
||||||
raise NotImplementedError()
|
raise qubes.exc.QubesNotImplementedError(
|
||||||
|
'Cannot suspend domain {!r} which has PCI devices attached' \
|
||||||
|
.format(self.name))
|
||||||
else:
|
else:
|
||||||
self.libvirt_domain.suspend()
|
self.libvirt_domain.suspend()
|
||||||
|
|
||||||
@ -836,7 +844,7 @@ class QubesVM(qubes.vm.BaseVM):
|
|||||||
:py:meth:`suspend`.'''
|
:py:meth:`suspend`.'''
|
||||||
|
|
||||||
if not self.is_running():
|
if not self.is_running():
|
||||||
raise qubes.QubesException('VM not running!')
|
raise qubes.exc.QubesVMNotRunningError(self)
|
||||||
|
|
||||||
self.suspend()
|
self.suspend()
|
||||||
|
|
||||||
@ -844,18 +852,21 @@ class QubesVM(qubes.vm.BaseVM):
|
|||||||
def resume(self):
|
def resume(self):
|
||||||
'''Resume suspended domain.
|
'''Resume suspended domain.
|
||||||
|
|
||||||
:raises NotImplemetedError: when machine is alread suspended.
|
:raises qubes.exc.QubesVMNotSuspendedError: when machine is not paused
|
||||||
|
:raises qubes.exc.QubesVMError: when machine is suspended
|
||||||
'''
|
'''
|
||||||
|
|
||||||
if self.get_power_state() == "Suspended":
|
if self.get_power_state() == "Suspended":
|
||||||
raise NotImplementedError()
|
raise qubes.exc.QubesVMError(self,
|
||||||
|
'Cannot resume suspended domain {!r}'.format(self.name))
|
||||||
else:
|
else:
|
||||||
self.unpause()
|
self.unpause()
|
||||||
|
|
||||||
|
|
||||||
def unpause(self):
|
def unpause(self):
|
||||||
'''Resume (unpause) a domain'''
|
'''Resume (unpause) a domain'''
|
||||||
if not self.is_paused():
|
if not self.is_paused():
|
||||||
raise qubes.QubesException('VM not paused!')
|
raise qubes.exc.QubesVMNotPausedError(self)
|
||||||
|
|
||||||
self.libvirt_domain.resume()
|
self.libvirt_domain.resume()
|
||||||
|
|
||||||
@ -891,28 +902,21 @@ class QubesVM(qubes.vm.BaseVM):
|
|||||||
null = None
|
null = None
|
||||||
if not self.is_running() and not self.is_paused():
|
if not self.is_running() and not self.is_paused():
|
||||||
if not autostart:
|
if not autostart:
|
||||||
raise qubes.QubesException('VM not running')
|
raise qubes.exc.QubesVMNotRunningError(self)
|
||||||
|
|
||||||
try:
|
if notify_function is not None:
|
||||||
if notify_function is not None:
|
notify_function('info',
|
||||||
notify_function('info',
|
'Starting the {!r} VM...'.format(self.name))
|
||||||
'Starting the {!r} VM...'.format(self.name))
|
self.start(start_guid=gui, notify_function=notify_function)
|
||||||
self.start(start_guid=gui, notify_function=notify_function)
|
|
||||||
|
|
||||||
except (IOError, OSError, qubes.QubesException) as e:
|
|
||||||
raise qubes.QubesException(
|
|
||||||
'Error while starting the {!r} VM: {!s}'.format(
|
|
||||||
self.name, e))
|
|
||||||
except MemoryError:
|
|
||||||
raise qubes.QubesException('Not enough memory to start {!r} VM!'
|
|
||||||
' Close one or more running VMs and try again.'.format(
|
|
||||||
self.name))
|
|
||||||
|
|
||||||
if self.is_paused():
|
if self.is_paused():
|
||||||
raise qubes.QubesException('VM is paused')
|
# XXX what about autostart?
|
||||||
|
raise qubes.exc.QubesVMNotRunningError(
|
||||||
|
self, 'Domain {!r} is paused'.format(self.name))
|
||||||
|
|
||||||
if not self.is_qrexec_running():
|
if not self.is_qrexec_running():
|
||||||
raise qubes.QubesException(
|
raise qubes.exc.QubesVMError(
|
||||||
"Domain '{}': qrexec not connected.".format(self.name))
|
self, 'Domain {!r}: qrexec not connected'.format(self.name))
|
||||||
|
|
||||||
if gui and os.getenv("DISPLAY") is not None \
|
if gui and os.getenv("DISPLAY") is not None \
|
||||||
and not self.is_guid_running():
|
and not self.is_guid_running():
|
||||||
@ -1018,7 +1022,8 @@ class QubesVM(qubes.vm.BaseVM):
|
|||||||
|
|
||||||
retcode = subprocess.call(guid_cmd)
|
retcode = subprocess.call(guid_cmd)
|
||||||
if retcode != 0:
|
if retcode != 0:
|
||||||
raise qubes.QubesException('Cannot start qubes-guid!')
|
raise qubes.exc.QubesVMError(self,
|
||||||
|
'Cannot start qubes-guid for domain {!r}'.format(self.name))
|
||||||
|
|
||||||
self.log.info('Sending monitor layout')
|
self.log.info('Sending monitor layout')
|
||||||
|
|
||||||
@ -1123,8 +1128,8 @@ class QubesVM(qubes.vm.BaseVM):
|
|||||||
def resize_private_img(self, size):
|
def resize_private_img(self, size):
|
||||||
'''Resize private image.'''
|
'''Resize private image.'''
|
||||||
|
|
||||||
# TODO QubesValueError, not assert
|
if size >= self.get_private_img_sz():
|
||||||
assert size >= self.get_private_img_sz(), "Cannot shrink private.img"
|
raise qubes.exc.QubesValueError('Cannot shrink private.img')
|
||||||
|
|
||||||
# resize the image
|
# resize the image
|
||||||
self.storage.resize_private_img(size)
|
self.storage.resize_private_img(size)
|
||||||
@ -1139,8 +1144,9 @@ class QubesVM(qubes.vm.BaseVM):
|
|||||||
sleep 0.2;
|
sleep 0.2;
|
||||||
done;
|
done;
|
||||||
resize2fs /dev/xvdb'''.format(size), user="root", wait=True)
|
resize2fs /dev/xvdb'''.format(size), user="root", wait=True)
|
||||||
|
|
||||||
if retcode != 0:
|
if retcode != 0:
|
||||||
raise qubes.QubesException('resize2fs failed')
|
raise qubes.exc.QubesException('resize2fs failed')
|
||||||
|
|
||||||
|
|
||||||
def remove_from_disk(self):
|
def remove_from_disk(self):
|
||||||
@ -1155,8 +1161,9 @@ class QubesVM(qubes.vm.BaseVM):
|
|||||||
:param qubes.vm.qubesvm.QubesVM src: source VM
|
:param qubes.vm.qubesvm.QubesVM src: source VM
|
||||||
'''
|
'''
|
||||||
|
|
||||||
if src.is_running():
|
if src.is_running(): # XXX what about paused?
|
||||||
raise qubes.QubesException('Attempt to clone a running VM!')
|
raise qubes.exc.QubesVMNotHaltedError(
|
||||||
|
self, 'Cannot clone a running domain {!r}'.format(self.name))
|
||||||
|
|
||||||
self.storage.clone_disk_files(src, verbose=False)
|
self.storage.clone_disk_files(src, verbose=False)
|
||||||
|
|
||||||
@ -1184,10 +1191,8 @@ class QubesVM(qubes.vm.BaseVM):
|
|||||||
'''Attach network in this machine to it's netvm.'''
|
'''Attach network in this machine to it's netvm.'''
|
||||||
|
|
||||||
if not self.is_running():
|
if not self.is_running():
|
||||||
raise qubes.QubesException('VM not running!')
|
raise qubes.exc.QubesVMNotRunningError(self)
|
||||||
|
assert self.netvm is not None
|
||||||
if self.netvm is None:
|
|
||||||
raise qubes.QubesException('NetVM not set!')
|
|
||||||
|
|
||||||
if not self.netvm.is_running():
|
if not self.netvm.is_running():
|
||||||
self.log.info('Starting NetVM ({0})'.format(self.netvm.name))
|
self.log.info('Starting NetVM ({0})'.format(self.netvm.name))
|
||||||
@ -1201,11 +1206,8 @@ class QubesVM(qubes.vm.BaseVM):
|
|||||||
'''Detach machine from it's netvm'''
|
'''Detach machine from it's netvm'''
|
||||||
|
|
||||||
if not self.is_running():
|
if not self.is_running():
|
||||||
raise qubes.QubesException('VM not running!')
|
raise qubes.exc.QubesVMNotRunningError(self)
|
||||||
|
assert self.netvm is not None
|
||||||
if self.netvm is None:
|
|
||||||
raise qubes.QubesException('NetVM not set!')
|
|
||||||
|
|
||||||
|
|
||||||
self.libvirt_domain.detachDevice(lxml.etree.ElementTree(
|
self.libvirt_domain.detachDevice(lxml.etree.ElementTree(
|
||||||
self.lvxml_net_dev(self.ip, self.mac, self.netvm)).tostring())
|
self.lvxml_net_dev(self.ip, self.mac, self.netvm)).tostring())
|
||||||
@ -1548,12 +1550,13 @@ class QubesVM(qubes.vm.BaseVM):
|
|||||||
|
|
||||||
if not os.path.exists(
|
if not os.path.exists(
|
||||||
os.path.join(self.storage.kernels_dir, 'vmlinuz')):
|
os.path.join(self.storage.kernels_dir, 'vmlinuz')):
|
||||||
raise qubes.QubesException('VM kernel does not exist: {0}'.format(
|
raise qubes.exc.QubesException(
|
||||||
os.path.join(self.storage.kernels_dir, 'vmlinuz')))
|
'VM kernel does not exist: {0}'.format(
|
||||||
|
os.path.join(self.storage.kernels_dir, 'vmlinuz')))
|
||||||
|
|
||||||
if not os.path.exists(
|
if not os.path.exists(
|
||||||
os.path.join(self.storage.kernels_dir, 'initramfs')):
|
os.path.join(self.storage.kernels_dir, 'initramfs')):
|
||||||
raise qubes.QubesException(
|
raise qubes.exc.QubesException(
|
||||||
'VM initramfs does not exist: {0}'.format(
|
'VM initramfs does not exist: {0}'.format(
|
||||||
os.path.join(self.storage.kernels_dir, 'initramfs')))
|
os.path.join(self.storage.kernels_dir, 'initramfs')))
|
||||||
|
|
||||||
|
@ -199,6 +199,7 @@ fi
|
|||||||
%{python_sitelib}/qubes/config.py*
|
%{python_sitelib}/qubes/config.py*
|
||||||
%{python_sitelib}/qubes/dochelpers.py*
|
%{python_sitelib}/qubes/dochelpers.py*
|
||||||
%{python_sitelib}/qubes/events.py*
|
%{python_sitelib}/qubes/events.py*
|
||||||
|
%{python_sitelib}/qubes/exc.py*
|
||||||
%{python_sitelib}/qubes/log.py*
|
%{python_sitelib}/qubes/log.py*
|
||||||
%{python_sitelib}/qubes/plugins.py*
|
%{python_sitelib}/qubes/plugins.py*
|
||||||
%{python_sitelib}/qubes/rngdoc.py*
|
%{python_sitelib}/qubes/rngdoc.py*
|
||||||
|
Loading…
Reference in New Issue
Block a user