HVM part 2
This commit is contained in:
parent
8da7416f30
commit
04cc2099f7
@ -85,28 +85,8 @@ class QubesHVm(QubesResizableVm):
|
||||
'save': lambda: str(self._seamless_gui_mode) }
|
||||
attrs['services']['default'] = "{'meminfo-writer': False}"
|
||||
|
||||
attrs['memory']['default'] = defaults["hvm_memory"]
|
||||
|
||||
return attrs
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
super(QubesHVm, self).__init__(**kwargs)
|
||||
|
||||
# Default for meminfo-writer have changed to (correct) False in the
|
||||
# same version as introduction of guiagent_installed, so for older VMs
|
||||
# with wrong setting, change is based on 'guiagent_installed' presence
|
||||
if "guiagent_installed" not in kwargs and \
|
||||
(not 'xml_element' in kwargs or kwargs['xml_element'].get('guiagent_installed') is None):
|
||||
self.services['meminfo-writer'] = False
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return "HVM"
|
||||
|
||||
def is_appvm(self):
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def is_template_compatible(cls, template):
|
||||
if template and (not template.is_template() or template.type != "TemplateHVM"):
|
||||
@ -124,28 +104,6 @@ class QubesHVm(QubesResizableVm):
|
||||
attrs += [ 'guiagent_installed' ]
|
||||
return attrs
|
||||
|
||||
@property
|
||||
def qrexec_installed(self):
|
||||
return self._qrexec_installed or \
|
||||
bool(self.template and self.template.qrexec_installed)
|
||||
|
||||
@qrexec_installed.setter
|
||||
def qrexec_installed(self, value):
|
||||
if self.template and self.template.qrexec_installed and not value:
|
||||
print >>sys.stderr, "WARNING: When qrexec_installed set in template, it will be propagated to the VM"
|
||||
self._qrexec_installed = value
|
||||
|
||||
@property
|
||||
def guiagent_installed(self):
|
||||
return self._guiagent_installed or \
|
||||
bool(self.template and self.template.guiagent_installed)
|
||||
|
||||
@guiagent_installed.setter
|
||||
def guiagent_installed(self, value):
|
||||
if self.template and self.template.guiagent_installed and not value:
|
||||
print >>sys.stderr, "WARNING: When guiagent_installed set in template, it will be propagated to the VM"
|
||||
self._guiagent_installed = value
|
||||
|
||||
@property
|
||||
def seamless_gui_mode(self):
|
||||
if not self.guiagent_installed:
|
||||
@ -237,59 +195,6 @@ class QubesHVm(QubesResizableVm):
|
||||
|
||||
self.storage.resize_private_img(size)
|
||||
|
||||
def get_config_params(self):
|
||||
|
||||
params = super(QubesHVm, self).get_config_params()
|
||||
|
||||
self.storage.drive = self.drive
|
||||
params.update(self.storage.get_config_params())
|
||||
params['volatiledev'] = ''
|
||||
|
||||
if self.timezone.lower() == 'localtime':
|
||||
params['time_basis'] = 'localtime'
|
||||
params['timeoffset'] = '0'
|
||||
elif self.timezone.isdigit():
|
||||
params['time_basis'] = 'UTC'
|
||||
params['timeoffset'] = self.timezone
|
||||
else:
|
||||
print >>sys.stderr, "WARNING: invalid 'timezone' value: %s" % self.timezone
|
||||
params['time_basis'] = 'UTC'
|
||||
params['timeoffset'] = '0'
|
||||
return params
|
||||
|
||||
def verify_files(self):
|
||||
if dry_run:
|
||||
return
|
||||
|
||||
self.storage.verify_files()
|
||||
|
||||
# fire hooks
|
||||
for hook in self.hooks_verify_files:
|
||||
hook(self)
|
||||
|
||||
return True
|
||||
|
||||
@property
|
||||
def vif(self):
|
||||
if self.xid < 0:
|
||||
return None
|
||||
if self.netvm is None:
|
||||
return None
|
||||
return "vif{0}.+".format(self.stubdom_xid)
|
||||
|
||||
@property
|
||||
def mac(self):
|
||||
if self._mac is not None:
|
||||
return self._mac
|
||||
elif self.template is not None:
|
||||
return self.template.mac
|
||||
else:
|
||||
return "00:16:3E:5E:6C:{qid:02X}".format(qid=self.qid)
|
||||
|
||||
@mac.setter
|
||||
def mac(self, value):
|
||||
self._mac = value
|
||||
|
||||
def run(self, command, **kwargs):
|
||||
if self.qrexec_installed:
|
||||
if 'gui' in kwargs and kwargs['gui']==False:
|
||||
@ -298,20 +203,6 @@ class QubesHVm(QubesResizableVm):
|
||||
else:
|
||||
raise QubesException("Needs qrexec agent installed in VM to use this function. See also qvm-prefs.")
|
||||
|
||||
@property
|
||||
def stubdom_xid(self):
|
||||
if self.xid < 0:
|
||||
return -1
|
||||
|
||||
if vmm.xs is None:
|
||||
return -1
|
||||
|
||||
stubdom_xid_str = vmm.xs.read('', '/local/domain/%d/image/device-model-domid' % self.xid)
|
||||
if stubdom_xid_str is not None:
|
||||
return int(stubdom_xid_str)
|
||||
else:
|
||||
return -1
|
||||
|
||||
def start(self, *args, **kwargs):
|
||||
# make it available to storage.prepare_for_vm_startup, which is
|
||||
# called before actually building VM libvirt configuration
|
||||
@ -333,74 +224,6 @@ class QubesHVm(QubesResizableVm):
|
||||
else:
|
||||
raise
|
||||
|
||||
def start_stubdom_guid(self, verbose=True):
|
||||
|
||||
guid_cmd = [system_path["qubes_guid_path"],
|
||||
"-d", str(self.stubdom_xid),
|
||||
"-t", str(self.xid),
|
||||
"-N", self.name,
|
||||
"-c", self.label.color,
|
||||
"-i", self.label.icon_path,
|
||||
"-l", str(self.label.index)]
|
||||
if self.debug:
|
||||
guid_cmd += ['-v', '-v']
|
||||
elif not verbose:
|
||||
guid_cmd += ['-q']
|
||||
retcode = subprocess.call (guid_cmd)
|
||||
if (retcode != 0) :
|
||||
raise QubesException("Cannot start qubes-guid!")
|
||||
|
||||
def start_guid(self, verbose=True, notify_function=None,
|
||||
before_qrexec=False, **kwargs):
|
||||
if not before_qrexec:
|
||||
return
|
||||
|
||||
if not self.guiagent_installed or self.debug:
|
||||
if verbose:
|
||||
print >> sys.stderr, "--> Starting Qubes GUId (full screen)..."
|
||||
self.start_stubdom_guid(verbose=verbose)
|
||||
|
||||
kwargs['extra_guid_args'] = kwargs.get('extra_guid_args', []) + \
|
||||
['-Q', '-n']
|
||||
|
||||
stubdom_guid_pidfile = \
|
||||
'/var/run/qubes/guid-running.%d' % self.stubdom_xid
|
||||
if not self.debug and os.path.exists(stubdom_guid_pidfile):
|
||||
# Terminate stubdom guid once "real" gui agent connects
|
||||
stubdom_guid_pid = int(open(stubdom_guid_pidfile, 'r').read())
|
||||
kwargs['extra_guid_args'] += ['-K', str(stubdom_guid_pid)]
|
||||
|
||||
super(QubesHVm, self).start_guid(verbose, notify_function, **kwargs)
|
||||
|
||||
def start_qrexec_daemon(self, **kwargs):
|
||||
if not self.qrexec_installed:
|
||||
if kwargs.get('verbose', False):
|
||||
print >> sys.stderr, "--> Starting the qrexec daemon..."
|
||||
xid = self.get_xid()
|
||||
qrexec_env = os.environ.copy()
|
||||
qrexec_env['QREXEC_STARTUP_NOWAIT'] = '1'
|
||||
retcode = subprocess.call ([system_path["qrexec_daemon_path"], str(xid), self.name, self.default_user], env=qrexec_env)
|
||||
if (retcode != 0) :
|
||||
self.force_shutdown(xid=xid)
|
||||
raise OSError ("ERROR: Cannot execute qrexec-daemon!")
|
||||
else:
|
||||
super(QubesHVm, self).start_qrexec_daemon(**kwargs)
|
||||
|
||||
if self.guiagent_installed:
|
||||
if kwargs.get('verbose'):
|
||||
print >> sys.stderr, "--> Waiting for user '%s' login..." % self.default_user
|
||||
|
||||
self.wait_for_session(notify_function=kwargs.get('notify_function', None))
|
||||
self.send_gui_mode()
|
||||
|
||||
def send_gui_mode(self):
|
||||
if self.seamless_gui_mode:
|
||||
service_input = "SEAMLESS"
|
||||
else:
|
||||
service_input = "FULLSCREEN"
|
||||
|
||||
self.run_service("qubes.SetGuiMode", input=service_input)
|
||||
|
||||
def _cleanup_zombie_domains(self):
|
||||
super(QubesHVm, self)._cleanup_zombie_domains()
|
||||
if not self.is_running():
|
||||
@ -416,15 +239,6 @@ class QubesHVm(QubesResizableVm):
|
||||
guid_pid = open(guid_pidfile).read().strip()
|
||||
os.kill(int(guid_pid), 15)
|
||||
|
||||
def suspend(self):
|
||||
if dry_run:
|
||||
return
|
||||
|
||||
if not self.is_running() and not self.is_paused():
|
||||
raise QubesException ("VM not running!")
|
||||
|
||||
self.pause()
|
||||
|
||||
def is_guid_running(self):
|
||||
# If user force the guiagent, is_guid_running will mimic a standard QubesVM
|
||||
if self.guiagent_installed:
|
||||
@ -444,5 +258,3 @@ class QubesHVm(QubesResizableVm):
|
||||
if self.qrexec_installed and not self.is_qrexec_running():
|
||||
return False
|
||||
return True
|
||||
|
||||
register_qubes_vm_class(QubesHVm)
|
||||
|
@ -74,6 +74,7 @@ vm_files = {
|
||||
defaults = {
|
||||
'libvirt_uri': 'xen:///',
|
||||
'memory': 400,
|
||||
'hvm_memory': 512,
|
||||
'kernelopts': "nopat",
|
||||
'kernelopts_pcidevs': "nopat iommu=soft swiotlb=8192",
|
||||
|
||||
|
@ -58,6 +58,7 @@ class GUI(qubes.ext.Extension):
|
||||
'-c', vm.label.color,
|
||||
'-i', vm.label.icon_path,
|
||||
'-l', str(vm.label.index)]
|
||||
|
||||
if extra_guid_args is not None:
|
||||
guid_cmd += extra_guid_args
|
||||
|
||||
@ -68,8 +69,19 @@ class GUI(qubes.ext.Extension):
|
||||
else:
|
||||
guid_cmd += ['-q']
|
||||
|
||||
retcode = subprocess.call(guid_cmd)
|
||||
if retcode != 0:
|
||||
if vm.hvm:
|
||||
guid_cmd += ['-Q', '-n']
|
||||
|
||||
stubdom_guid_pidfile = \
|
||||
'/var/run/qubes/guid-running.{}'.format(self.get_stubdom_xid(vm))
|
||||
if not vm.debug and os.path.exists(stubdom_guid_pidfile):
|
||||
# Terminate stubdom guid once "real" gui agent connects
|
||||
stubdom_guid_pid = open(stubdom_guid_pidfile, 'r').read().strip()
|
||||
guid_cmd += ['-K', stubdom_guid_pid]
|
||||
|
||||
try:
|
||||
subprocess.check_call(guid_cmd)
|
||||
except subprocess.CalledProcessError:
|
||||
raise qubes.exc.QubesVMError(vm,
|
||||
'Cannot start qubes-guid for domain {!r}'.format(vm.name))
|
||||
|
||||
@ -77,6 +89,62 @@ class GUI(qubes.ext.Extension):
|
||||
vm.wait_for_session()
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_stubdom_xid(vm):
|
||||
if vm.xid < 0:
|
||||
return -1
|
||||
|
||||
if vm.app.vmm.xs is None:
|
||||
return -1
|
||||
|
||||
stubdom_xid_str = vm.app.vmm.xs.read('',
|
||||
'/local/domain/{}/image/device-model-domid'.format(vm.xid))
|
||||
if stubdom_xid_str is None or not stubdom_xid_str.isdigit():
|
||||
return -1
|
||||
|
||||
return int(stubdom_xid_str)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def send_gui_mode(vm):
|
||||
vm.run_service('qubes.SetGuiMode',
|
||||
input=('SEAMLESS'
|
||||
if vm.features.get('gui-seamless', False)
|
||||
else 'FULLSCREEN'))
|
||||
|
||||
|
||||
@qubes.ext.handler('domain-spawn')
|
||||
def on_domain_spawn(self, vm, event, start_guid=True, **kwargs):
|
||||
if not start_guid:
|
||||
return
|
||||
|
||||
if not vm.hvm:
|
||||
return
|
||||
|
||||
if not os.getenv('DISPLAY'):
|
||||
vm.log.error('Not starting gui daemon, no DISPLAY set')
|
||||
return
|
||||
|
||||
guid_cmd = [qubes.config.system_path['qubes_guid_path'],
|
||||
'-d', str(self.get_stubdom_xid(vm)),
|
||||
'-t', str(vm.xid),
|
||||
'-N', vm.name,
|
||||
'-c', vm.label.color,
|
||||
'-i', vm.label.icon_path,
|
||||
'-l', str(vm.label.index),
|
||||
]
|
||||
|
||||
if vm.debug:
|
||||
guid_cmd += ['-v', '-v']
|
||||
else:
|
||||
guid_cmd += ['-q']
|
||||
|
||||
try:
|
||||
subprocess.check_call(guid_cmd)
|
||||
except subprocess.CalledProcesException:
|
||||
raise qubes.exc.QubesVMError(vm, 'Cannot start gui daemon')
|
||||
|
||||
|
||||
@qubes.ext.handler('monitor-layout-change')
|
||||
def on_monitor_layout_change(self, vm, event, monitor_layout):
|
||||
# pylint: disable=no-self-use
|
||||
|
@ -36,7 +36,11 @@ import qubes.exc
|
||||
|
||||
class NetVMMixin(object):
|
||||
mac = qubes.property('mac', type=str,
|
||||
default=(lambda self: '00:16:3E:5E:6C:{:02X}'.format(self.qid)),
|
||||
default=(lambda self:
|
||||
self.template.mac if self.hvm
|
||||
and hasattr(self, 'template')
|
||||
and self.template is not None
|
||||
else '00:16:3E:5E:6C:{:02X}'.format(self.qid)),
|
||||
ls_width=17,
|
||||
doc='MAC address of the NIC emulated inside VM')
|
||||
|
||||
@ -109,7 +113,10 @@ class NetVMMixin(object):
|
||||
return None
|
||||
if self.netvm is None:
|
||||
return None
|
||||
return "vif{0}.+".format(self.xid)
|
||||
|
||||
# XXX ugly hack ahead
|
||||
# stubdom_xid is one more than self.xid
|
||||
return 'vif{0}.+'.format(self.xid + int(self.hvm))
|
||||
|
||||
@property
|
||||
def connected_vms(self):
|
||||
|
@ -183,7 +183,8 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
|
||||
package manager.''')
|
||||
|
||||
memory = qubes.property('memory', type=int,
|
||||
default=qubes.config.defaults['memory'],
|
||||
default=(lambda self:
|
||||
qubes.config.defaults['hvm_memory' if self.hvm else 'memory']),
|
||||
doc='Memory currently available for this VM.')
|
||||
|
||||
maxmem = qubes.property('maxmem', type=int,
|
||||
@ -765,6 +766,9 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
|
||||
raise qubes.exc.QubesNotImplementedError(
|
||||
'Cannot suspend domain {!r} which has PCI devices attached' \
|
||||
.format(self.name))
|
||||
else:
|
||||
if self.hvm:
|
||||
self.libvirt_domain.pause()
|
||||
else:
|
||||
self.libvirt_domain.suspend()
|
||||
|
||||
@ -953,22 +957,25 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
|
||||
:raises OSError: when starting fails.
|
||||
'''
|
||||
|
||||
if not self.features.check_with_template('qrexec', not self.hvm):
|
||||
self.log.debug(
|
||||
'Not starting the qrexec daemon, disabled by features')
|
||||
return
|
||||
|
||||
self.log.debug('Starting the qrexec daemon')
|
||||
qrexec_args = [str(self.xid), self.name, self.default_user]
|
||||
if not self.debug:
|
||||
qrexec_args.insert(0, "-q")
|
||||
|
||||
qrexec_env = os.environ.copy()
|
||||
if not self.features.check_with_template('qrexec', not self.hvm):
|
||||
self.log.debug(
|
||||
'Starting the qrexec daemon in background, because of features')
|
||||
qrexec_env['QREXEC_STARTUP_NOWAIT'] = '1'
|
||||
else:
|
||||
qrexec_env['QREXEC_STARTUP_TIMEOUT'] = str(self.qrexec_timeout)
|
||||
retcode = subprocess.call(
|
||||
|
||||
try:
|
||||
subprocess.check_call(
|
||||
[qubes.config.system_path["qrexec_daemon_path"]] + qrexec_args,
|
||||
env=qrexec_env)
|
||||
if retcode != 0:
|
||||
raise OSError('Cannot execute qrexec-daemon!')
|
||||
except subprocess.CalledProcessError:
|
||||
raise qubes.exc.QubesVMError(self, 'Cannot execute qrexec-daemon!')
|
||||
|
||||
|
||||
def start_qubesdb(self):
|
||||
|
@ -27,10 +27,14 @@
|
||||
<viridian/>
|
||||
</features>
|
||||
|
||||
{# TODO
|
||||
<clock offset="variable"
|
||||
adjustment='{timeoffset}' basis='{time_basis}'/>
|
||||
#}
|
||||
{% set timezone = vm.features.check_with_template('timezone', 'localtime').lower() %}
|
||||
{% if timezone == 'localtime' %}
|
||||
<clock offset="variable" adjustment="0" basis="localtime" />
|
||||
{% elif timezone.isdigit() %}
|
||||
<clock offset="variable" adjustment="{{ timezone }}" basis="UTC" />
|
||||
{% else %}
|
||||
<clock offset="variable" adjustment="0" basis="UTC" />
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<clock offset='utc' adjustment='reset'>
|
||||
<timer name="tsc" mode="native"/>
|
||||
|
Loading…
Reference in New Issue
Block a user