Wrap all VMM connection related object into QubesVMMConnection class
This makes easier to import right objects in submodules (only one object). This also implement lazy connection - at first access, not at module import, which speeds up tools, which doesn't need runtime information (like qvm-prefs or qvm-service). In the future this will ease migration from xenstore to QubesDB. Also implement "offline mode" - operate on qubes.xml without connecting to VMM - raise exception at such try. This is needed to run tools during installation, where only minimal set of services are started, especially no libvirt.
This commit is contained in:
parent
9f90106db4
commit
b8c62c0279
@ -39,7 +39,7 @@ from qubes import qmemman_algo
|
|||||||
import libvirt
|
import libvirt
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
from qubes.qubes import xs,dry_run,libvirt_conn
|
from qubes.qubes import dry_run,vmm
|
||||||
from qubes.qubes import register_qubes_vm_class
|
from qubes.qubes import register_qubes_vm_class
|
||||||
from qubes.qubes import QubesVmCollection,QubesException,QubesHost,QubesVmLabels
|
from qubes.qubes import QubesVmCollection,QubesException,QubesHost,QubesVmLabels
|
||||||
from qubes.qubes import defaults,system_path,vm_files,qubes_max_qid
|
from qubes.qubes import defaults,system_path,vm_files,qubes_max_qid
|
||||||
@ -202,6 +202,10 @@ class QubesVm(object):
|
|||||||
attrs[prop]['save_skip'] = \
|
attrs[prop]['save_skip'] = \
|
||||||
lambda prop=prop: getattr(self, prop) is None
|
lambda prop=prop: getattr(self, prop) is None
|
||||||
|
|
||||||
|
# Can happen only if VM created in offline mode
|
||||||
|
attrs['maxmem']['save_skip'] = lambda: self.maxmem is None
|
||||||
|
attrs['vcpus']['save_skip'] = lambda: self.vcpus is None
|
||||||
|
|
||||||
attrs['uuid']['save_skip'] = lambda: self.uuid is None
|
attrs['uuid']['save_skip'] = lambda: self.uuid is None
|
||||||
attrs['mac']['save'] = lambda: str(self._mac)
|
attrs['mac']['save'] = lambda: str(self._mac)
|
||||||
attrs['mac']['save_skip'] = lambda: self._mac is None
|
attrs['mac']['save_skip'] = lambda: self._mac is None
|
||||||
@ -304,7 +308,7 @@ class QubesVm(object):
|
|||||||
self.netvm.connected_vms[self.qid] = self
|
self.netvm.connected_vms[self.qid] = self
|
||||||
|
|
||||||
# Not in generic way to not create QubesHost() to frequently
|
# Not in generic way to not create QubesHost() to frequently
|
||||||
if self.maxmem is None:
|
if self.maxmem is None and not vmm.offline_mode:
|
||||||
qubes_host = QubesHost()
|
qubes_host = QubesHost()
|
||||||
total_mem_mb = qubes_host.memory_total/1024
|
total_mem_mb = qubes_host.memory_total/1024
|
||||||
self.maxmem = total_mem_mb/2
|
self.maxmem = total_mem_mb/2
|
||||||
@ -314,7 +318,7 @@ class QubesVm(object):
|
|||||||
self.maxmem = self.memory * 10
|
self.maxmem = self.memory * 10
|
||||||
|
|
||||||
# By default allow use all VCPUs
|
# By default allow use all VCPUs
|
||||||
if self.vcpus is None:
|
if self.vcpus is None and not vmm.offline_mode:
|
||||||
qubes_host = QubesHost()
|
qubes_host = QubesHost()
|
||||||
self.vcpus = qubes_host.no_cpus
|
self.vcpus = qubes_host.no_cpus
|
||||||
|
|
||||||
@ -648,7 +652,7 @@ class QubesVm(object):
|
|||||||
|
|
||||||
def _update_libvirt_domain(self):
|
def _update_libvirt_domain(self):
|
||||||
domain_config = self.create_config_file()
|
domain_config = self.create_config_file()
|
||||||
self._libvirt_domain = libvirt_conn.defineXML(domain_config)
|
self._libvirt_domain = vmm.libvirt_conn.defineXML(domain_config)
|
||||||
self.uuid = uuid.UUID(bytes=self._libvirt_domain.UUID())
|
self.uuid = uuid.UUID(bytes=self._libvirt_domain.UUID())
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -658,9 +662,9 @@ class QubesVm(object):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
if self.uuid is not None:
|
if self.uuid is not None:
|
||||||
self._libvirt_domain = libvirt_conn.lookupByUUID(self.uuid.bytes)
|
self._libvirt_domain = vmm.libvirt_conn.lookupByUUID(self.uuid.bytes)
|
||||||
else:
|
else:
|
||||||
self._libvirt_domain = libvirt_conn.lookupByName(self.name)
|
self._libvirt_domain = vmm.libvirt_conn.lookupByName(self.name)
|
||||||
self.uuid = uuid.UUID(bytes=self._libvirt_domain.UUID())
|
self.uuid = uuid.UUID(bytes=self._libvirt_domain.UUID())
|
||||||
except libvirt.libvirtError:
|
except libvirt.libvirtError:
|
||||||
if libvirt.virGetLastError()[0] == libvirt.VIR_ERR_NO_DOMAIN:
|
if libvirt.virGetLastError()[0] == libvirt.VIR_ERR_NO_DOMAIN:
|
||||||
@ -788,7 +792,7 @@ class QubesVm(object):
|
|||||||
# TODO
|
# TODO
|
||||||
uuid = self.uuid
|
uuid = self.uuid
|
||||||
|
|
||||||
start_time = xs.read('', "/vm/%s/start_time" % str(uuid))
|
start_time = vmm.xs.read('', "/vm/%s/start_time" % str(uuid))
|
||||||
if start_time != '':
|
if start_time != '':
|
||||||
return datetime.datetime.fromtimestamp(float(start_time))
|
return datetime.datetime.fromtimestamp(float(start_time))
|
||||||
else:
|
else:
|
||||||
@ -820,7 +824,7 @@ class QubesVm(object):
|
|||||||
# FIXME
|
# FIXME
|
||||||
# 51712 (0xCA00) is xvda
|
# 51712 (0xCA00) is xvda
|
||||||
# backend node name not available through xenapi :(
|
# backend node name not available through xenapi :(
|
||||||
used_dmdev = xs.read('', "/local/domain/0/backend/vbd/{0}/51712/node".format(self.xid))
|
used_dmdev = vmm.xs.read('', "/local/domain/0/backend/vbd/{0}/51712/node".format(self.xid))
|
||||||
|
|
||||||
return used_dmdev != current_dmdev
|
return used_dmdev != current_dmdev
|
||||||
|
|
||||||
@ -905,15 +909,15 @@ class QubesVm(object):
|
|||||||
return
|
return
|
||||||
|
|
||||||
dev_basepath = '/local/domain/%d/device/vif' % self.xid
|
dev_basepath = '/local/domain/%d/device/vif' % self.xid
|
||||||
for dev in xs.ls('', dev_basepath):
|
for dev in vmm.xs.ls('', dev_basepath):
|
||||||
# check if backend domain is alive
|
# check if backend domain is alive
|
||||||
backend_xid = int(xs.read('', '%s/%s/backend-id' % (dev_basepath, dev)))
|
backend_xid = int(vmm.xs.read('', '%s/%s/backend-id' % (dev_basepath, dev)))
|
||||||
if backend_xid in libvirt_conn.listDomainsID():
|
if backend_xid in vmm.libvirt_conn.listDomainsID():
|
||||||
# check if device is still active
|
# check if device is still active
|
||||||
if xs.read('', '%s/%s/state' % (dev_basepath, dev)) == '4':
|
if vmm.xs.read('', '%s/%s/state' % (dev_basepath, dev)) == '4':
|
||||||
continue
|
continue
|
||||||
# remove dead device
|
# remove dead device
|
||||||
xs.rm('', '%s/%s' % (dev_basepath, dev))
|
vmm.xs.rm('', '%s/%s' % (dev_basepath, dev))
|
||||||
|
|
||||||
def create_xenstore_entries(self, xid = None):
|
def create_xenstore_entries(self, xid = None):
|
||||||
if dry_run:
|
if dry_run:
|
||||||
@ -924,69 +928,69 @@ class QubesVm(object):
|
|||||||
|
|
||||||
assert xid >= 0, "Invalid XID value"
|
assert xid >= 0, "Invalid XID value"
|
||||||
|
|
||||||
domain_path = xs.get_domain_path(xid)
|
domain_path = vmm.xs.get_domain_path(xid)
|
||||||
|
|
||||||
# Set Xen Store entires with VM networking info:
|
# Set Xen Store entires with VM networking info:
|
||||||
|
|
||||||
xs.write('', "{0}/qubes-vm-type".format(domain_path),
|
vmm.xs.write('', "{0}/qubes-vm-type".format(domain_path),
|
||||||
self.type)
|
self.type)
|
||||||
xs.write('', "{0}/qubes-vm-updateable".format(domain_path),
|
vmm.xs.write('', "{0}/qubes-vm-updateable".format(domain_path),
|
||||||
str(self.updateable))
|
str(self.updateable))
|
||||||
|
|
||||||
if self.is_netvm():
|
if self.is_netvm():
|
||||||
xs.write('',
|
vmm.xs.write('',
|
||||||
"{0}/qubes-netvm-gateway".format(domain_path),
|
"{0}/qubes-netvm-gateway".format(domain_path),
|
||||||
self.gateway)
|
self.gateway)
|
||||||
xs.write('',
|
vmm.xs.write('',
|
||||||
"{0}/qubes-netvm-secondary-dns".format(domain_path),
|
"{0}/qubes-netvm-secondary-dns".format(domain_path),
|
||||||
self.secondary_dns)
|
self.secondary_dns)
|
||||||
xs.write('',
|
vmm.xs.write('',
|
||||||
"{0}/qubes-netvm-netmask".format(domain_path),
|
"{0}/qubes-netvm-netmask".format(domain_path),
|
||||||
self.netmask)
|
self.netmask)
|
||||||
xs.write('',
|
vmm.xs.write('',
|
||||||
"{0}/qubes-netvm-network".format(domain_path),
|
"{0}/qubes-netvm-network".format(domain_path),
|
||||||
self.network)
|
self.network)
|
||||||
|
|
||||||
if self.netvm is not None:
|
if self.netvm is not None:
|
||||||
xs.write('', "{0}/qubes-ip".format(domain_path), self.ip)
|
vmm.xs.write('', "{0}/qubes-ip".format(domain_path), self.ip)
|
||||||
xs.write('', "{0}/qubes-netmask".format(domain_path),
|
vmm.xs.write('', "{0}/qubes-netmask".format(domain_path),
|
||||||
self.netvm.netmask)
|
self.netvm.netmask)
|
||||||
xs.write('', "{0}/qubes-gateway".format(domain_path),
|
vmm.xs.write('', "{0}/qubes-gateway".format(domain_path),
|
||||||
self.netvm.gateway)
|
self.netvm.gateway)
|
||||||
xs.write('',
|
vmm.xs.write('',
|
||||||
"{0}/qubes-secondary-dns".format(domain_path),
|
"{0}/qubes-secondary-dns".format(domain_path),
|
||||||
self.netvm.secondary_dns)
|
self.netvm.secondary_dns)
|
||||||
|
|
||||||
tzname = self.get_timezone()
|
tzname = self.get_timezone()
|
||||||
if tzname:
|
if tzname:
|
||||||
xs.write('',
|
vmm.xs.write('',
|
||||||
"{0}/qubes-timezone".format(domain_path),
|
"{0}/qubes-timezone".format(domain_path),
|
||||||
tzname)
|
tzname)
|
||||||
|
|
||||||
for srv in self.services.keys():
|
for srv in self.services.keys():
|
||||||
# convert True/False to "1"/"0"
|
# convert True/False to "1"/"0"
|
||||||
xs.write('', "{0}/qubes-service/{1}".format(domain_path, srv),
|
vmm.xs.write('', "{0}/qubes-service/{1}".format(domain_path, srv),
|
||||||
str(int(self.services[srv])))
|
str(int(self.services[srv])))
|
||||||
|
|
||||||
xs.write('',
|
vmm.xs.write('',
|
||||||
"{0}/qubes-block-devices".format(domain_path),
|
"{0}/qubes-block-devices".format(domain_path),
|
||||||
'')
|
'')
|
||||||
|
|
||||||
xs.write('',
|
vmm.xs.write('',
|
||||||
"{0}/qubes-usb-devices".format(domain_path),
|
"{0}/qubes-usb-devices".format(domain_path),
|
||||||
'')
|
'')
|
||||||
|
|
||||||
xs.write('', "{0}/qubes-debug-mode".format(domain_path),
|
vmm.xs.write('', "{0}/qubes-debug-mode".format(domain_path),
|
||||||
str(int(self.debug)))
|
str(int(self.debug)))
|
||||||
|
|
||||||
# Fix permissions
|
# Fix permissions
|
||||||
xs.set_permissions('', '{0}/device'.format(domain_path),
|
vmm.xs.set_permissions('', '{0}/device'.format(domain_path),
|
||||||
[{ 'dom': xid }])
|
[{ 'dom': xid }])
|
||||||
xs.set_permissions('', '{0}/memory'.format(domain_path),
|
vmm.xs.set_permissions('', '{0}/memory'.format(domain_path),
|
||||||
[{ 'dom': xid }])
|
[{ 'dom': xid }])
|
||||||
xs.set_permissions('', '{0}/qubes-block-devices'.format(domain_path),
|
vmm.xs.set_permissions('', '{0}/qubes-block-devices'.format(domain_path),
|
||||||
[{ 'dom': xid }])
|
[{ 'dom': xid }])
|
||||||
xs.set_permissions('', '{0}/qubes-usb-devices'.format(domain_path),
|
vmm.xs.set_permissions('', '{0}/qubes-usb-devices'.format(domain_path),
|
||||||
[{ 'dom': xid }])
|
[{ 'dom': xid }])
|
||||||
|
|
||||||
# fire hooks
|
# fire hooks
|
||||||
@ -1743,7 +1747,7 @@ class QubesVm(object):
|
|||||||
|
|
||||||
# Bind pci devices to pciback driver
|
# Bind pci devices to pciback driver
|
||||||
for pci in self.pcidevs:
|
for pci in self.pcidevs:
|
||||||
nd = libvirt_conn.nodeDeviceLookupByName('pci_0000_' + pci.replace(':','_').replace('.','_'))
|
nd = vmm.libvirt_conn.nodeDeviceLookupByName('pci_0000_' + pci.replace(':','_').replace('.','_'))
|
||||||
nd.dettach()
|
nd.dettach()
|
||||||
|
|
||||||
self.libvirt_domain.createWithFlags(libvirt.VIR_DOMAIN_START_PAUSED)
|
self.libvirt_domain.createWithFlags(libvirt.VIR_DOMAIN_START_PAUSED)
|
||||||
|
@ -25,7 +25,7 @@ import sys
|
|||||||
import os.path
|
import os.path
|
||||||
import xen.lowlevel.xs
|
import xen.lowlevel.xs
|
||||||
|
|
||||||
from qubes.qubes import QubesVm,register_qubes_vm_class,xs,dry_run
|
from qubes.qubes import QubesVm,register_qubes_vm_class,vmm,dry_run
|
||||||
from qubes.qubes import defaults,system_path,vm_files
|
from qubes.qubes import defaults,system_path,vm_files
|
||||||
from qubes.qubes import QubesVmCollection,QubesException
|
from qubes.qubes import QubesVmCollection,QubesException
|
||||||
|
|
||||||
@ -115,7 +115,7 @@ class QubesNetVm(QubesVm):
|
|||||||
|
|
||||||
|
|
||||||
super(QubesNetVm, self).create_xenstore_entries(xid)
|
super(QubesNetVm, self).create_xenstore_entries(xid)
|
||||||
xs.write('', "/local/domain/{0}/qubes-netvm-external-ip".format(xid), '')
|
vmm.xs.write('', "/local/domain/{0}/qubes-netvm-external-ip".format(xid), '')
|
||||||
self.update_external_ip_permissions(xid)
|
self.update_external_ip_permissions(xid)
|
||||||
|
|
||||||
def update_external_ip_permissions(self, xid = -1):
|
def update_external_ip_permissions(self, xid = -1):
|
||||||
@ -130,7 +130,7 @@ class QubesNetVm(QubesVm):
|
|||||||
perms.append({ 'dom': xid, 'read': True })
|
perms.append({ 'dom': xid, 'read': True })
|
||||||
|
|
||||||
try:
|
try:
|
||||||
xs.set_permissions('', '/local/domain/{0}/qubes-netvm-external-ip'.format(xid),
|
vmm.xs.set_permissions('', '/local/domain/{0}/qubes-netvm-external-ip'.format(xid),
|
||||||
perms)
|
perms)
|
||||||
except xen.lowlevel.xs.Error as e:
|
except xen.lowlevel.xs.Error as e:
|
||||||
print >>sys.stderr, "WARNING: failed to update external IP " \
|
print >>sys.stderr, "WARNING: failed to update external IP " \
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
from qubes.qubes import QubesNetVm,register_qubes_vm_class
|
from qubes.qubes import QubesNetVm,register_qubes_vm_class
|
||||||
from qubes.qubes import defaults
|
from qubes.qubes import defaults
|
||||||
from qubes.qubes import QubesException,dry_run,libvirt_conn
|
from qubes.qubes import QubesException,dry_run,vmm
|
||||||
import psutil
|
import psutil
|
||||||
|
|
||||||
class QubesAdminVm(QubesNetVm):
|
class QubesAdminVm(QubesNetVm):
|
||||||
@ -62,7 +62,7 @@ class QubesAdminVm(QubesNetVm):
|
|||||||
return psutil.virtual_memory().total/1024
|
return psutil.virtual_memory().total/1024
|
||||||
|
|
||||||
def get_mem_static_max(self):
|
def get_mem_static_max(self):
|
||||||
return libvirt_conn.getInfo()[1]
|
return vmm.libvirt_conn.getInfo()[1]
|
||||||
|
|
||||||
def get_disk_usage(self, file_or_dir):
|
def get_disk_usage(self, file_or_dir):
|
||||||
return 0
|
return 0
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from qubes.qubes import QubesNetVm,register_qubes_vm_class,xs,dry_run
|
from qubes.qubes import QubesNetVm,register_qubes_vm_class,vmm,dry_run
|
||||||
from qubes.qubes import QubesVmCollection,QubesException
|
from qubes.qubes import QubesVmCollection,QubesException
|
||||||
|
|
||||||
yum_proxy_ip = '10.137.255.254'
|
yum_proxy_ip = '10.137.255.254'
|
||||||
@ -99,8 +99,8 @@ class QubesProxyVm(QubesNetVm):
|
|||||||
|
|
||||||
|
|
||||||
super(QubesProxyVm, self).create_xenstore_entries(xid)
|
super(QubesProxyVm, self).create_xenstore_entries(xid)
|
||||||
xs.write('', "/local/domain/{0}/qubes-iptables-error".format(xid), '')
|
vmm.xs.write('', "/local/domain/{0}/qubes-iptables-error".format(xid), '')
|
||||||
xs.set_permissions('', "/local/domain/{0}/qubes-iptables-error".format(xid),
|
vmm.xs.set_permissions('', "/local/domain/{0}/qubes-iptables-error".format(xid),
|
||||||
[{ 'dom': xid, 'write': True }])
|
[{ 'dom': xid, 'write': True }])
|
||||||
self.write_iptables_xenstore_entry()
|
self.write_iptables_xenstore_entry()
|
||||||
|
|
||||||
@ -112,13 +112,13 @@ class QubesProxyVm(QubesNetVm):
|
|||||||
xid = self.get_xid()
|
xid = self.get_xid()
|
||||||
|
|
||||||
if self.netvm is None:
|
if self.netvm is None:
|
||||||
xs.write('', "/local/domain/{0}/qubes-netvm-domid".format(xid), '')
|
vmm.xs.write('', "/local/domain/{0}/qubes-netvm-domid".format(xid), '')
|
||||||
else:
|
else:
|
||||||
xs.write('', "/local/domain/{0}/qubes-netvm-domid".format(xid),
|
vmm.xs.write('', "/local/domain/{0}/qubes-netvm-domid".format(xid),
|
||||||
"{0}".format(self.netvm.get_xid()))
|
"{0}".format(self.netvm.get_xid()))
|
||||||
|
|
||||||
def write_iptables_xenstore_entry(self):
|
def write_iptables_xenstore_entry(self):
|
||||||
xs.rm('', "/local/domain/{0}/qubes-iptables-domainrules".format(self.get_xid()))
|
vmm.xs.rm('', "/local/domain/{0}/qubes-iptables-domainrules".format(self.get_xid()))
|
||||||
iptables = "# Generated by Qubes Core on {0}\n".format(datetime.now().ctime())
|
iptables = "# Generated by Qubes Core on {0}\n".format(datetime.now().ctime())
|
||||||
iptables += "*filter\n"
|
iptables += "*filter\n"
|
||||||
iptables += ":INPUT DROP [0:0]\n"
|
iptables += ":INPUT DROP [0:0]\n"
|
||||||
@ -140,7 +140,7 @@ class QubesProxyVm(QubesNetVm):
|
|||||||
# Deny inter-VMs networking
|
# Deny inter-VMs networking
|
||||||
iptables += "-A FORWARD -i vif+ -o vif+ -j DROP\n"
|
iptables += "-A FORWARD -i vif+ -o vif+ -j DROP\n"
|
||||||
iptables += "COMMIT\n"
|
iptables += "COMMIT\n"
|
||||||
xs.write('', "/local/domain/{0}/qubes-iptables-header".format(self.get_xid()), iptables)
|
vmm.xs.write('', "/local/domain/{0}/qubes-iptables-header".format(self.get_xid()), iptables)
|
||||||
|
|
||||||
vms = [vm for vm in self.connected_vms.values()]
|
vms = [vm for vm in self.connected_vms.values()]
|
||||||
for vm in vms:
|
for vm in vms:
|
||||||
@ -201,12 +201,12 @@ class QubesProxyVm(QubesNetVm):
|
|||||||
|
|
||||||
iptables += "-A FORWARD -s {0} -j {1}\n".format(ip, default_action)
|
iptables += "-A FORWARD -s {0} -j {1}\n".format(ip, default_action)
|
||||||
iptables += "COMMIT\n"
|
iptables += "COMMIT\n"
|
||||||
xs.write('', "/local/domain/"+str(self.get_xid())+"/qubes-iptables-domainrules/"+str(xid), iptables)
|
vmm.xs.write('', "/local/domain/"+str(self.get_xid())+"/qubes-iptables-domainrules/"+str(xid), iptables)
|
||||||
# no need for ending -A FORWARD -j DROP, cause default action is DROP
|
# no need for ending -A FORWARD -j DROP, cause default action is DROP
|
||||||
|
|
||||||
self.write_netvm_domid_entry()
|
self.write_netvm_domid_entry()
|
||||||
|
|
||||||
self.rules_applied = None
|
self.rules_applied = None
|
||||||
xs.write('', "/local/domain/{0}/qubes-iptables".format(self.get_xid()), 'reload')
|
vmm.xs.write('', "/local/domain/{0}/qubes-iptables".format(self.get_xid()), 'reload')
|
||||||
|
|
||||||
register_qubes_vm_class(QubesProxyVm)
|
register_qubes_vm_class(QubesProxyVm)
|
||||||
|
@ -28,7 +28,7 @@ import libvirt
|
|||||||
import time
|
import time
|
||||||
from qubes.qubes import QubesVm,QubesVmLabel,register_qubes_vm_class
|
from qubes.qubes import QubesVm,QubesVmLabel,register_qubes_vm_class
|
||||||
from qubes.qubes import QubesDispVmLabels
|
from qubes.qubes import QubesDispVmLabels
|
||||||
from qubes.qubes import dry_run,libvirt_conn
|
from qubes.qubes import dry_run,vmm
|
||||||
from qubes.qmemman_client import QMemmanClient
|
from qubes.qmemman_client import QMemmanClient
|
||||||
|
|
||||||
class QubesDisposableVm(QubesVm):
|
class QubesDisposableVm(QubesVm):
|
||||||
@ -146,7 +146,7 @@ class QubesDisposableVm(QubesVm):
|
|||||||
assert (len(self.pcidevs) == 0), "DispVM cannot have PCI devices"
|
assert (len(self.pcidevs) == 0), "DispVM cannot have PCI devices"
|
||||||
|
|
||||||
print >>sys.stderr, "time=%s, calling restore" % (str(time.time()))
|
print >>sys.stderr, "time=%s, calling restore" % (str(time.time()))
|
||||||
libvirt_conn.restoreFlags(self.disp_savefile,
|
vmm.libvirt_conn.restoreFlags(self.disp_savefile,
|
||||||
domain_config, libvirt.VIR_DOMAIN_SAVE_PAUSED)
|
domain_config, libvirt.VIR_DOMAIN_SAVE_PAUSED)
|
||||||
|
|
||||||
print >>sys.stderr, "time=%s, done, getting xid" % (str(time.time()))
|
print >>sys.stderr, "time=%s, done, getting xid" % (str(time.time()))
|
||||||
|
@ -30,7 +30,8 @@ import stat
|
|||||||
import sys
|
import sys
|
||||||
import re
|
import re
|
||||||
import stat
|
import stat
|
||||||
from qubes.qubes import QubesVm,register_qubes_vm_class,xs,dry_run
|
|
||||||
|
from qubes.qubes import QubesVm,register_qubes_vm_class,vmm,dry_run
|
||||||
from qubes.qubes import system_path,defaults
|
from qubes.qubes import system_path,defaults
|
||||||
from qubes.qubes import QubesException
|
from qubes.qubes import QubesException
|
||||||
|
|
||||||
@ -397,7 +398,7 @@ class QubesHVm(QubesVm):
|
|||||||
if self.xid < 0:
|
if self.xid < 0:
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
stubdom_xid_str = xs.read('', '/local/domain/%d/image/device-model-domid' % self.xid)
|
stubdom_xid_str = vmm.xs.read('', '/local/domain/%d/image/device-model-domid' % self.xid)
|
||||||
if stubdom_xid_str is not None:
|
if stubdom_xid_str is not None:
|
||||||
return int(stubdom_xid_str)
|
return int(stubdom_xid_str)
|
||||||
else:
|
else:
|
||||||
|
@ -38,7 +38,6 @@ import atexit
|
|||||||
dry_run = False
|
dry_run = False
|
||||||
#dry_run = True
|
#dry_run = True
|
||||||
|
|
||||||
|
|
||||||
if not dry_run:
|
if not dry_run:
|
||||||
import libvirt
|
import libvirt
|
||||||
import xen.lowlevel.xc
|
import xen.lowlevel.xc
|
||||||
@ -108,22 +107,76 @@ qubes_max_netid = 254
|
|||||||
class QubesException (Exception):
|
class QubesException (Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def libvirt_error_handler(ctx, error):
|
class QubesVMMConnection(object):
|
||||||
pass
|
def __init__(self):
|
||||||
|
self._libvirt_conn = None
|
||||||
|
self._xs = None
|
||||||
|
self._xc = None
|
||||||
|
self._offline_mode = False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def offline_mode(self):
|
||||||
|
return self._offline_mode
|
||||||
|
|
||||||
|
@offline_mode.setter
|
||||||
|
def offline_mode(self, value):
|
||||||
|
if not value and self._libvirt_conn is not None:
|
||||||
|
raise QubesException("Cannot change offline mode while already connected")
|
||||||
|
|
||||||
|
self._offline_mode = value
|
||||||
|
|
||||||
|
def _libvirt_error_handler(self, ctx, error):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def init_vmm_connection(self):
|
||||||
|
if self._libvirt_conn is not None:
|
||||||
|
# Already initialized
|
||||||
|
return
|
||||||
|
if self._offline_mode:
|
||||||
|
# Do not initialize in offline mode
|
||||||
|
return
|
||||||
|
|
||||||
|
self._xc = xen.lowlevel.xc.xc()
|
||||||
|
self._xs = xen.lowlevel.xs.xs()
|
||||||
|
self._libvirt_conn = libvirt.open(defaults['libvirt_uri'])
|
||||||
|
if self._libvirt_conn == None:
|
||||||
|
raise QubesException("Failed connect to libvirt driver")
|
||||||
|
libvirt.registerErrorHandler(self._libvirt_error_handler, None)
|
||||||
|
atexit.register(self._libvirt_conn.close)
|
||||||
|
|
||||||
|
def _common_getter(self, name):
|
||||||
|
if self._offline_mode:
|
||||||
|
# Do not initialize in offline mode
|
||||||
|
raise QubesException("VMM operations disabled in offline mode")
|
||||||
|
|
||||||
|
if self._libvirt_conn is None:
|
||||||
|
self.init_vmm_connection()
|
||||||
|
return getattr(self, name)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def libvirt_conn(self):
|
||||||
|
return self._common_getter('_libvirt_conn')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def xs(self):
|
||||||
|
return self._common_getter('_xs')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def xc(self):
|
||||||
|
return self._common_getter('_xc')
|
||||||
|
|
||||||
|
|
||||||
|
##### VMM global variable definition #####
|
||||||
|
|
||||||
if not dry_run:
|
if not dry_run:
|
||||||
xc = xen.lowlevel.xc.xc()
|
vmm = QubesVMMConnection()
|
||||||
xs = xen.lowlevel.xs.xs()
|
|
||||||
libvirt_conn = libvirt.open(defaults['libvirt_uri'])
|
##########################################
|
||||||
if libvirt_conn == None:
|
|
||||||
raise QubesException("Failed connect to libvirt driver")
|
|
||||||
libvirt.registerErrorHandler(libvirt_error_handler, None)
|
|
||||||
atexit.register(libvirt_conn.close)
|
|
||||||
|
|
||||||
class QubesHost(object):
|
class QubesHost(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
(model, memory, cpus, mhz, nodes, socket, cores, threads) = libvirt_conn.getInfo()
|
(model, memory, cpus, mhz, nodes, socket, cores, threads) = vmm.libvirt_conn.getInfo()
|
||||||
self.physinfo = xc.physinfo()
|
self.physinfo = vmm.xc.physinfo()
|
||||||
|
|
||||||
self._total_mem = long(memory)*1024
|
self._total_mem = long(memory)*1024
|
||||||
self._no_cpus = cpus
|
self._no_cpus = cpus
|
||||||
@ -152,7 +205,7 @@ class QubesHost(object):
|
|||||||
if previous is None:
|
if previous is None:
|
||||||
previous_time = time.time()
|
previous_time = time.time()
|
||||||
previous = {}
|
previous = {}
|
||||||
info = xc.domain_getinfo(0, qubes_max_qid)
|
info = vmm.xc.domain_getinfo(0, qubes_max_qid)
|
||||||
for vm in info:
|
for vm in info:
|
||||||
previous[vm['domid']] = {}
|
previous[vm['domid']] = {}
|
||||||
previous[vm['domid']]['cpu_time'] = (
|
previous[vm['domid']]['cpu_time'] = (
|
||||||
@ -162,7 +215,7 @@ class QubesHost(object):
|
|||||||
|
|
||||||
current_time = time.time()
|
current_time = time.time()
|
||||||
current = {}
|
current = {}
|
||||||
info = xc.domain_getinfo(0, qubes_max_qid)
|
info = vmm.xc.domain_getinfo(0, qubes_max_qid)
|
||||||
for vm in info:
|
for vm in info:
|
||||||
current[vm['domid']] = {}
|
current[vm['domid']] = {}
|
||||||
current[vm['domid']]['cpu_time'] = (
|
current[vm['domid']]['cpu_time'] = (
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
from qubes import QubesVm,QubesException,QubesVmCollection
|
from qubes import QubesVm,QubesException,QubesVmCollection
|
||||||
from qubes import QubesVmClasses
|
from qubes import QubesVmClasses
|
||||||
from qubes import xs
|
from qubes import vmm
|
||||||
from qubes import system_path,vm_files
|
from qubes import system_path,vm_files
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
@ -208,7 +208,7 @@ def block_find_unused_frontend(vm = None):
|
|||||||
assert vm is not None
|
assert vm is not None
|
||||||
assert vm.is_running()
|
assert vm.is_running()
|
||||||
|
|
||||||
vbd_list = xs.ls('', '/local/domain/%d/device/vbd' % vm.xid)
|
vbd_list = vmm.xs.ls('', '/local/domain/%d/device/vbd' % vm.xid)
|
||||||
# xvd* devices
|
# xvd* devices
|
||||||
major = 202
|
major = 202
|
||||||
# prefer xvdi
|
# prefer xvdi
|
||||||
@ -223,22 +223,22 @@ def block_list(vm = None, system_disks = False):
|
|||||||
desc_re = re.compile(r"^.{1,255}$")
|
desc_re = re.compile(r"^.{1,255}$")
|
||||||
mode_re = re.compile(r"^[rw]$")
|
mode_re = re.compile(r"^[rw]$")
|
||||||
|
|
||||||
xs_trans = xs.transaction_start()
|
xs_trans = vmm.xs.transaction_start()
|
||||||
|
|
||||||
vm_list = []
|
vm_list = []
|
||||||
if vm is not None:
|
if vm is not None:
|
||||||
if not vm.is_running():
|
if not vm.is_running():
|
||||||
xs.transaction_end(xs_trans)
|
vmm.xs.transaction_end(xs_trans)
|
||||||
return []
|
return []
|
||||||
else:
|
else:
|
||||||
vm_list = [ str(vm.xid) ]
|
vm_list = [ str(vm.xid) ]
|
||||||
else:
|
else:
|
||||||
vm_list = xs.ls(xs_trans, '/local/domain')
|
vm_list = vmm.xs.ls(xs_trans, '/local/domain')
|
||||||
|
|
||||||
devices_list = {}
|
devices_list = {}
|
||||||
for xid in vm_list:
|
for xid in vm_list:
|
||||||
vm_name = xs.read(xs_trans, '/local/domain/%s/name' % xid)
|
vm_name = vmm.xs.read(xs_trans, '/local/domain/%s/name' % xid)
|
||||||
vm_devices = xs.ls(xs_trans, '/local/domain/%s/qubes-block-devices' % xid)
|
vm_devices = vmm.xs.ls(xs_trans, '/local/domain/%s/qubes-block-devices' % xid)
|
||||||
if vm_devices is None:
|
if vm_devices is None:
|
||||||
continue
|
continue
|
||||||
for device in vm_devices:
|
for device in vm_devices:
|
||||||
@ -247,9 +247,9 @@ def block_list(vm = None, system_disks = False):
|
|||||||
print >> sys.stderr, "Invalid device name in VM '%s'" % vm_name
|
print >> sys.stderr, "Invalid device name in VM '%s'" % vm_name
|
||||||
continue
|
continue
|
||||||
|
|
||||||
device_size = xs.read(xs_trans, '/local/domain/%s/qubes-block-devices/%s/size' % (xid, device))
|
device_size = vmm.xs.read(xs_trans, '/local/domain/%s/qubes-block-devices/%s/size' % (xid, device))
|
||||||
device_desc = xs.read(xs_trans, '/local/domain/%s/qubes-block-devices/%s/desc' % (xid, device))
|
device_desc = vmm.xs.read(xs_trans, '/local/domain/%s/qubes-block-devices/%s/desc' % (xid, device))
|
||||||
device_mode = xs.read(xs_trans, '/local/domain/%s/qubes-block-devices/%s/mode' % (xid, device))
|
device_mode = vmm.xs.read(xs_trans, '/local/domain/%s/qubes-block-devices/%s/mode' % (xid, device))
|
||||||
|
|
||||||
if device_size is None or device_desc is None or device_mode is None:
|
if device_size is None or device_desc is None or device_mode is None:
|
||||||
print >> sys.stderr, "Missing field in %s device parameters" % device
|
print >> sys.stderr, "Missing field in %s device parameters" % device
|
||||||
@ -277,16 +277,16 @@ def block_list(vm = None, system_disks = False):
|
|||||||
"vm": vm_name, "device":device, "size":int(device_size),
|
"vm": vm_name, "device":device, "size":int(device_size),
|
||||||
"desc":device_desc, "mode":device_mode}
|
"desc":device_desc, "mode":device_mode}
|
||||||
|
|
||||||
xs.transaction_end(xs_trans)
|
vmm.xs.transaction_end(xs_trans)
|
||||||
return devices_list
|
return devices_list
|
||||||
|
|
||||||
def block_check_attached(backend_vm, device, backend_xid = None):
|
def block_check_attached(backend_vm, device, backend_xid = None):
|
||||||
if backend_xid is None:
|
if backend_xid is None:
|
||||||
backend_xid = backend_vm.xid
|
backend_xid = backend_vm.xid
|
||||||
xs_trans = xs.transaction_start()
|
xs_trans = vmm.xs.transaction_start()
|
||||||
vm_list = xs.ls(xs_trans, '/local/domain/%d/backend/vbd' % backend_xid)
|
vm_list = vmm.xs.ls(xs_trans, '/local/domain/%d/backend/vbd' % backend_xid)
|
||||||
if vm_list is None:
|
if vm_list is None:
|
||||||
xs.transaction_end(xs_trans)
|
vmm.xs.transaction_end(xs_trans)
|
||||||
return None
|
return None
|
||||||
device_majorminor = None
|
device_majorminor = None
|
||||||
try:
|
try:
|
||||||
@ -295,10 +295,10 @@ def block_check_attached(backend_vm, device, backend_xid = None):
|
|||||||
# Unknown devices will be compared directly - perhaps it is a filename?
|
# Unknown devices will be compared directly - perhaps it is a filename?
|
||||||
pass
|
pass
|
||||||
for vm_xid in vm_list:
|
for vm_xid in vm_list:
|
||||||
for devid in xs.ls(xs_trans, '/local/domain/%d/backend/vbd/%s' % (backend_xid, vm_xid)):
|
for devid in vmm.xs.ls(xs_trans, '/local/domain/%d/backend/vbd/%s' % (backend_xid, vm_xid)):
|
||||||
(tmp_major, tmp_minor) = (0, 0)
|
(tmp_major, tmp_minor) = (0, 0)
|
||||||
phys_device = xs.read(xs_trans, '/local/domain/%d/backend/vbd/%s/%s/physical-device' % (backend_xid, vm_xid, devid))
|
phys_device = vmm.xs.read(xs_trans, '/local/domain/%d/backend/vbd/%s/%s/physical-device' % (backend_xid, vm_xid, devid))
|
||||||
dev_params = xs.read(xs_trans, '/local/domain/%d/backend/vbd/%s/%s/params' % (backend_xid, vm_xid, devid))
|
dev_params = vmm.xs.read(xs_trans, '/local/domain/%d/backend/vbd/%s/%s/params' % (backend_xid, vm_xid, devid))
|
||||||
if phys_device and phys_device.find(':'):
|
if phys_device and phys_device.find(':'):
|
||||||
(tmp_major, tmp_minor) = phys_device.split(":")
|
(tmp_major, tmp_minor) = phys_device.split(":")
|
||||||
tmp_major = int(tmp_major, 16)
|
tmp_major = int(tmp_major, 16)
|
||||||
@ -319,9 +319,9 @@ def block_check_attached(backend_vm, device, backend_xid = None):
|
|||||||
#TODO
|
#TODO
|
||||||
vm_name = xl_ctx.domid_to_name(int(vm_xid))
|
vm_name = xl_ctx.domid_to_name(int(vm_xid))
|
||||||
frontend = block_devid_to_name(int(devid))
|
frontend = block_devid_to_name(int(devid))
|
||||||
xs.transaction_end(xs_trans)
|
vmm.xs.transaction_end(xs_trans)
|
||||||
return {"xid":int(vm_xid), "frontend": frontend, "devid": int(devid), "vm": vm_name}
|
return {"xid":int(vm_xid), "frontend": frontend, "devid": int(devid), "vm": vm_name}
|
||||||
xs.transaction_end(xs_trans)
|
vmm.xs.transaction_end(xs_trans)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def block_attach(vm, backend_vm, device, frontend=None, mode="w", auto_detach=False, wait=True):
|
def block_attach(vm, backend_vm, device, frontend=None, mode="w", auto_detach=False, wait=True):
|
||||||
@ -343,7 +343,7 @@ def do_block_attach(vm, backend_vm, device, frontend, mode, auto_detach, wait):
|
|||||||
raise QubesException("No unused frontend found")
|
raise QubesException("No unused frontend found")
|
||||||
else:
|
else:
|
||||||
# Check if any device attached at this frontend
|
# Check if any device attached at this frontend
|
||||||
if xs.read('', '/local/domain/%d/device/vbd/%d/state' % (vm.xid, block_name_to_devid(frontend))) == '4':
|
if vmm.xs.read('', '/local/domain/%d/device/vbd/%d/state' % (vm.xid, block_name_to_devid(frontend))) == '4':
|
||||||
raise QubesException("Frontend %s busy in VM %s, detach it first" % (frontend, vm.name))
|
raise QubesException("Frontend %s busy in VM %s, detach it first" % (frontend, vm.name))
|
||||||
|
|
||||||
# Check if this device is attached to some domain
|
# Check if this device is attached to some domain
|
||||||
@ -368,8 +368,8 @@ def do_block_attach(vm, backend_vm, device, frontend, mode, auto_detach, wait):
|
|||||||
# 5sec timeout
|
# 5sec timeout
|
||||||
timeout = 5/interval
|
timeout = 5/interval
|
||||||
while timeout > 0:
|
while timeout > 0:
|
||||||
be_state = xs.read('', be_path + '/state')
|
be_state = vmm.xs.read('', be_path + '/state')
|
||||||
hotplug_state = xs.read('', be_path + '/hotplug-status')
|
hotplug_state = vmm.xs.read('', be_path + '/hotplug-status')
|
||||||
if be_state is None:
|
if be_state is None:
|
||||||
raise QubesException("Backend device disappeared, something weird happened")
|
raise QubesException("Backend device disappeared, something weird happened")
|
||||||
elif int(be_state) == 4:
|
elif int(be_state) == 4:
|
||||||
@ -377,13 +377,13 @@ def do_block_attach(vm, backend_vm, device, frontend, mode, auto_detach, wait):
|
|||||||
return
|
return
|
||||||
elif int(be_state) > 4:
|
elif int(be_state) > 4:
|
||||||
# Error
|
# Error
|
||||||
error = xs.read('', '/local/domain/%d/error/backend/vbd/%d/%d/error' % (backend_vm.xid, vm.xid, block_name_to_devid(frontend)))
|
error = vmm.xs.read('', '/local/domain/%d/error/backend/vbd/%d/%d/error' % (backend_vm.xid, vm.xid, block_name_to_devid(frontend)))
|
||||||
if error is not None:
|
if error is not None:
|
||||||
raise QubesException("Error while connecting block device: " + error)
|
raise QubesException("Error while connecting block device: " + error)
|
||||||
else:
|
else:
|
||||||
raise QubesException("Unknown error while connecting block device")
|
raise QubesException("Unknown error while connecting block device")
|
||||||
elif hotplug_state == 'error':
|
elif hotplug_state == 'error':
|
||||||
hotplug_error = xs.read('', be_path + '/hotplug-error')
|
hotplug_error = vmm.xs.read('', be_path + '/hotplug-error')
|
||||||
if hotplug_error:
|
if hotplug_error:
|
||||||
raise QubesException("Error while connecting block device: " + hotplug_error)
|
raise QubesException("Error while connecting block device: " + hotplug_error)
|
||||||
else:
|
else:
|
||||||
@ -401,7 +401,7 @@ def block_detach(vm, frontend = "xvdi", vm_xid = None):
|
|||||||
vm_xid = vm.xid
|
vm_xid = vm.xid
|
||||||
|
|
||||||
# Check if this device is really connected
|
# Check if this device is really connected
|
||||||
if not xs.read('', '/local/domain/%d/device/vbd/%d/state' % (vm_xid, block_name_to_devid(frontend))) == '4':
|
if not vmm.xs.read('', '/local/domain/%d/device/vbd/%d/state' % (vm_xid, block_name_to_devid(frontend))) == '4':
|
||||||
# Do nothing - device already detached
|
# Do nothing - device already detached
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -417,21 +417,21 @@ def block_detach_all(vm, vm_xid = None):
|
|||||||
# FIXME: potential race
|
# FIXME: potential race
|
||||||
vm_xid = vm.xid
|
vm_xid = vm.xid
|
||||||
|
|
||||||
xs_trans = xs.transaction_start()
|
xs_trans = vmm.xs.transaction_start()
|
||||||
devices = xs.ls(xs_trans, '/local/domain/%d/device/vbd' % vm_xid)
|
devices = vmm.xs.ls(xs_trans, '/local/domain/%d/device/vbd' % vm_xid)
|
||||||
if devices is None:
|
if devices is None:
|
||||||
return
|
return
|
||||||
devices_to_detach = []
|
devices_to_detach = []
|
||||||
for devid in devices:
|
for devid in devices:
|
||||||
# check if this is system disk
|
# check if this is system disk
|
||||||
be_path = xs.read(xs_trans, '/local/domain/%d/device/vbd/%s/backend' % (vm_xid, devid))
|
be_path = vmm.xs.read(xs_trans, '/local/domain/%d/device/vbd/%s/backend' % (vm_xid, devid))
|
||||||
assert be_path is not None
|
assert be_path is not None
|
||||||
be_params = xs.read(xs_trans, be_path + '/params')
|
be_params = vmm.xs.read(xs_trans, be_path + '/params')
|
||||||
if be_path.startswith('/local/domain/0/') and be_params is not None and be_params.startswith(system_path["qubes_base_dir"]):
|
if be_path.startswith('/local/domain/0/') and be_params is not None and be_params.startswith(system_path["qubes_base_dir"]):
|
||||||
# system disk
|
# system disk
|
||||||
continue
|
continue
|
||||||
devices_to_detach.append(devid)
|
devices_to_detach.append(devid)
|
||||||
xs.transaction_end(xs_trans)
|
vmm.xs.transaction_end(xs_trans)
|
||||||
for devid in devices_to_detach:
|
for devid in devices_to_detach:
|
||||||
xl_cmd = [ '/usr/sbin/xl', 'block-detach', str(vm_xid), devid]
|
xl_cmd = [ '/usr/sbin/xl', 'block-detach', str(vm_xid), devid]
|
||||||
subprocess.check_call(xl_cmd)
|
subprocess.check_call(xl_cmd)
|
||||||
@ -450,7 +450,7 @@ def usb_setup(backend_vm_xid, vm_xid, devid, usb_ver):
|
|||||||
devid - id of the pvusb controller
|
devid - id of the pvusb controller
|
||||||
"""
|
"""
|
||||||
num_ports = 8
|
num_ports = 8
|
||||||
trans = xs.transaction_start()
|
trans = vmm.xs.transaction_start()
|
||||||
|
|
||||||
be_path = "/local/domain/%d/backend/vusb/%d/%d" % (backend_vm_xid, vm_xid, devid)
|
be_path = "/local/domain/%d/backend/vusb/%d/%d" % (backend_vm_xid, vm_xid, devid)
|
||||||
fe_path = "/local/domain/%d/device/vusb/%d" % (vm_xid, devid)
|
fe_path = "/local/domain/%d/device/vusb/%d" % (vm_xid, devid)
|
||||||
@ -459,35 +459,35 @@ def usb_setup(backend_vm_xid, vm_xid, devid, usb_ver):
|
|||||||
fe_perm = [{'dom': vm_xid}, {'dom': backend_vm_xid, 'read': True} ]
|
fe_perm = [{'dom': vm_xid}, {'dom': backend_vm_xid, 'read': True} ]
|
||||||
|
|
||||||
# Create directories and set permissions
|
# Create directories and set permissions
|
||||||
xs.write(trans, be_path, "")
|
vmm.xs.write(trans, be_path, "")
|
||||||
xs.set_permissions(trans, be_path, be_perm)
|
vmm.xs.set_permissions(trans, be_path, be_perm)
|
||||||
|
|
||||||
xs.write(trans, fe_path, "")
|
vmm.xs.write(trans, fe_path, "")
|
||||||
xs.set_permissions(trans, fe_path, fe_perm)
|
vmm.xs.set_permissions(trans, fe_path, fe_perm)
|
||||||
|
|
||||||
# Write backend information into the location that frontend looks for
|
# Write backend information into the location that frontend looks for
|
||||||
xs.write(trans, "%s/backend-id" % fe_path, str(backend_vm_xid))
|
vmm.xs.write(trans, "%s/backend-id" % fe_path, str(backend_vm_xid))
|
||||||
xs.write(trans, "%s/backend" % fe_path, be_path)
|
vmm.xs.write(trans, "%s/backend" % fe_path, be_path)
|
||||||
|
|
||||||
# Write frontend information into the location that backend looks for
|
# Write frontend information into the location that backend looks for
|
||||||
xs.write(trans, "%s/frontend-id" % be_path, str(vm_xid))
|
vmm.xs.write(trans, "%s/frontend-id" % be_path, str(vm_xid))
|
||||||
xs.write(trans, "%s/frontend" % be_path, fe_path)
|
vmm.xs.write(trans, "%s/frontend" % be_path, fe_path)
|
||||||
|
|
||||||
# Write USB Spec version field.
|
# Write USB Spec version field.
|
||||||
xs.write(trans, "%s/usb-ver" % be_path, usb_ver)
|
vmm.xs.write(trans, "%s/usb-ver" % be_path, usb_ver)
|
||||||
|
|
||||||
# Write virtual root hub field.
|
# Write virtual root hub field.
|
||||||
xs.write(trans, "%s/num-ports" % be_path, str(num_ports))
|
vmm.xs.write(trans, "%s/num-ports" % be_path, str(num_ports))
|
||||||
for port in range(1, num_ports+1):
|
for port in range(1, num_ports+1):
|
||||||
# Set all port to disconnected state
|
# Set all port to disconnected state
|
||||||
xs.write(trans, "%s/port/%d" % (be_path, port), "")
|
vmm.xs.write(trans, "%s/port/%d" % (be_path, port), "")
|
||||||
|
|
||||||
# Set state to XenbusStateInitialising
|
# Set state to XenbusStateInitialising
|
||||||
xs.write(trans, "%s/state" % fe_path, "1")
|
vmm.xs.write(trans, "%s/state" % fe_path, "1")
|
||||||
xs.write(trans, "%s/state" % be_path, "1")
|
vmm.xs.write(trans, "%s/state" % be_path, "1")
|
||||||
xs.write(trans, "%s/online" % be_path, "1")
|
vmm.xs.write(trans, "%s/online" % be_path, "1")
|
||||||
|
|
||||||
xs.transaction_end(trans)
|
vmm.xs.transaction_end(trans)
|
||||||
|
|
||||||
def usb_decode_device_from_xs(xs_encoded_device):
|
def usb_decode_device_from_xs(xs_encoded_device):
|
||||||
""" recover actual device name (xenstore doesn't allow dot in key names, so it was translated to underscore) """
|
""" recover actual device name (xenstore doesn't allow dot in key names, so it was translated to underscore) """
|
||||||
@ -512,12 +512,12 @@ def usb_list():
|
|||||||
|
|
||||||
devices_list = {}
|
devices_list = {}
|
||||||
|
|
||||||
xs_trans = xs.transaction_start()
|
xs_trans = vmm.xs.transaction_start()
|
||||||
vm_list = xs.ls(xs_trans, '/local/domain')
|
vm_list = vmm.xs.ls(xs_trans, '/local/domain')
|
||||||
|
|
||||||
for xid in vm_list:
|
for xid in vm_list:
|
||||||
vm_name = xs.read(xs_trans, '/local/domain/%s/name' % xid)
|
vm_name = vmm.xs.read(xs_trans, '/local/domain/%s/name' % xid)
|
||||||
vm_devices = xs.ls(xs_trans, '/local/domain/%s/qubes-usb-devices' % xid)
|
vm_devices = vmm.xs.ls(xs_trans, '/local/domain/%s/qubes-usb-devices' % xid)
|
||||||
if vm_devices is None:
|
if vm_devices is None:
|
||||||
continue
|
continue
|
||||||
# when listing devices in xenstore we get encoded names
|
# when listing devices in xenstore we get encoded names
|
||||||
@ -527,13 +527,13 @@ def usb_list():
|
|||||||
print >> sys.stderr, "Invalid device id in backend VM '%s'" % vm_name
|
print >> sys.stderr, "Invalid device id in backend VM '%s'" % vm_name
|
||||||
continue
|
continue
|
||||||
device = usb_decode_device_from_xs(xs_encoded_device)
|
device = usb_decode_device_from_xs(xs_encoded_device)
|
||||||
device_desc = xs.read(xs_trans, '/local/domain/%s/qubes-usb-devices/%s/desc' % (xid, xs_encoded_device))
|
device_desc = vmm.xs.read(xs_trans, '/local/domain/%s/qubes-usb-devices/%s/desc' % (xid, xs_encoded_device))
|
||||||
if not desc_re.match(device_desc):
|
if not desc_re.match(device_desc):
|
||||||
print >> sys.stderr, "Invalid %s device desc in VM '%s'" % (device, vm_name)
|
print >> sys.stderr, "Invalid %s device desc in VM '%s'" % (device, vm_name)
|
||||||
continue
|
continue
|
||||||
visible_name = "%s:%s" % (vm_name, device)
|
visible_name = "%s:%s" % (vm_name, device)
|
||||||
# grab version
|
# grab version
|
||||||
usb_ver = xs.read(xs_trans, '/local/domain/%s/qubes-usb-devices/%s/usb-ver' % (xid, xs_encoded_device))
|
usb_ver = vmm.xs.read(xs_trans, '/local/domain/%s/qubes-usb-devices/%s/usb-ver' % (xid, xs_encoded_device))
|
||||||
if usb_ver is None or not usb_ver_re.match(usb_ver):
|
if usb_ver is None or not usb_ver_re.match(usb_ver):
|
||||||
print >> sys.stderr, "Invalid %s device USB version in VM '%s'" % (device, vm_name)
|
print >> sys.stderr, "Invalid %s device USB version in VM '%s'" % (device, vm_name)
|
||||||
continue
|
continue
|
||||||
@ -542,7 +542,7 @@ def usb_list():
|
|||||||
"desc":device_desc,
|
"desc":device_desc,
|
||||||
"usb_ver":usb_ver}
|
"usb_ver":usb_ver}
|
||||||
|
|
||||||
xs.transaction_end(xs_trans)
|
vmm.xs.transaction_end(xs_trans)
|
||||||
return devices_list
|
return devices_list
|
||||||
|
|
||||||
def usb_check_attached(xs_trans, backend_vm, device):
|
def usb_check_attached(xs_trans, backend_vm, device):
|
||||||
@ -559,21 +559,21 @@ def usb_check_attached(xs_trans, backend_vm, device):
|
|||||||
"""
|
"""
|
||||||
# sample xs content: /local/domain/0/backend/vusb/4/0/port/1 = "7-5"
|
# sample xs content: /local/domain/0/backend/vusb/4/0/port/1 = "7-5"
|
||||||
attached_dev = None
|
attached_dev = None
|
||||||
vms = xs.ls(xs_trans, '/local/domain/%d/backend/vusb' % backend_vm)
|
vms = vmm.xs.ls(xs_trans, '/local/domain/%d/backend/vusb' % backend_vm)
|
||||||
if vms is None:
|
if vms is None:
|
||||||
return None
|
return None
|
||||||
for vm in vms:
|
for vm in vms:
|
||||||
if not vm.isdigit():
|
if not vm.isdigit():
|
||||||
print >> sys.stderr, "Invalid VM id"
|
print >> sys.stderr, "Invalid VM id"
|
||||||
continue
|
continue
|
||||||
frontend_devs = xs.ls(xs_trans, '/local/domain/%d/backend/vusb/%s' % (backend_vm, vm))
|
frontend_devs = vmm.xs.ls(xs_trans, '/local/domain/%d/backend/vusb/%s' % (backend_vm, vm))
|
||||||
if frontend_devs is None:
|
if frontend_devs is None:
|
||||||
continue
|
continue
|
||||||
for frontend_dev in frontend_devs:
|
for frontend_dev in frontend_devs:
|
||||||
if not frontend_dev.isdigit():
|
if not frontend_dev.isdigit():
|
||||||
print >> sys.stderr, "Invalid frontend in VM %s" % vm
|
print >> sys.stderr, "Invalid frontend in VM %s" % vm
|
||||||
continue
|
continue
|
||||||
ports = xs.ls(xs_trans, '/local/domain/%d/backend/vusb/%s/%s/port' % (backend_vm, vm, frontend_dev))
|
ports = vmm.xs.ls(xs_trans, '/local/domain/%d/backend/vusb/%s/%s/port' % (backend_vm, vm, frontend_dev))
|
||||||
if ports is None:
|
if ports is None:
|
||||||
continue
|
continue
|
||||||
for port in ports:
|
for port in ports:
|
||||||
@ -581,7 +581,7 @@ def usb_check_attached(xs_trans, backend_vm, device):
|
|||||||
if not port.isdigit():
|
if not port.isdigit():
|
||||||
print >> sys.stderr, "Invalid port in VM %s frontend %s" % (vm, frontend)
|
print >> sys.stderr, "Invalid port in VM %s frontend %s" % (vm, frontend)
|
||||||
continue
|
continue
|
||||||
dev = xs.read(xs_trans, '/local/domain/%d/backend/vusb/%s/%s/port/%s' % (backend_vm, vm, frontend_dev, port))
|
dev = vmm.xs.read(xs_trans, '/local/domain/%d/backend/vusb/%s/%s/port/%s' % (backend_vm, vm, frontend_dev, port))
|
||||||
if dev == "":
|
if dev == "":
|
||||||
continue
|
continue
|
||||||
# Sanitize device id
|
# Sanitize device id
|
||||||
@ -605,7 +605,7 @@ def usb_check_attached(xs_trans, backend_vm, device):
|
|||||||
# if len(devport) != 2:
|
# if len(devport) != 2:
|
||||||
# raise QubesException("Malformed frontend syntax, must be in device-port format")
|
# raise QubesException("Malformed frontend syntax, must be in device-port format")
|
||||||
# # FIXME:
|
# # FIXME:
|
||||||
# # return xs.read('', '/local/domain/%d/device/vusb/%d/state' % (vm.xid, frontend)) == '4'
|
# # return vmm.xs.read('', '/local/domain/%d/device/vusb/%d/state' % (vm.xid, frontend)) == '4'
|
||||||
# return False
|
# return False
|
||||||
|
|
||||||
def usb_find_unused_frontend(xs_trans, backend_vm_xid, vm_xid, usb_ver):
|
def usb_find_unused_frontend(xs_trans, backend_vm_xid, vm_xid, usb_ver):
|
||||||
@ -619,7 +619,7 @@ def usb_find_unused_frontend(xs_trans, backend_vm_xid, vm_xid, usb_ver):
|
|||||||
# If nothing found, this value will be used to derive the index of a new frontend.
|
# If nothing found, this value will be used to derive the index of a new frontend.
|
||||||
last_frontend_dev = -1
|
last_frontend_dev = -1
|
||||||
|
|
||||||
frontend_devs = xs.ls(xs_trans, "/local/domain/%d/device/vusb" % vm_xid)
|
frontend_devs = vmm.xs.ls(xs_trans, "/local/domain/%d/device/vusb" % vm_xid)
|
||||||
if frontend_devs is not None:
|
if frontend_devs is not None:
|
||||||
for frontend_dev in frontend_devs:
|
for frontend_dev in frontend_devs:
|
||||||
if not frontend_dev.isdigit():
|
if not frontend_dev.isdigit():
|
||||||
@ -627,12 +627,12 @@ def usb_find_unused_frontend(xs_trans, backend_vm_xid, vm_xid, usb_ver):
|
|||||||
continue
|
continue
|
||||||
frontend_dev = int(frontend_dev)
|
frontend_dev = int(frontend_dev)
|
||||||
fe_path = "/local/domain/%d/device/vusb/%d" % (vm_xid, frontend_dev)
|
fe_path = "/local/domain/%d/device/vusb/%d" % (vm_xid, frontend_dev)
|
||||||
if xs.read(xs_trans, "%s/backend-id" % fe_path) == str(backend_vm_xid):
|
if vmm.xs.read(xs_trans, "%s/backend-id" % fe_path) == str(backend_vm_xid):
|
||||||
if xs.read(xs_trans, '/local/domain/%d/backend/vusb/%d/%d/usb-ver' % (backend_vm_xid, vm_xid, frontend_dev)) != usb_ver:
|
if vmm.xs.read(xs_trans, '/local/domain/%d/backend/vusb/%d/%d/usb-ver' % (backend_vm_xid, vm_xid, frontend_dev)) != usb_ver:
|
||||||
last_frontend_dev = frontend_dev
|
last_frontend_dev = frontend_dev
|
||||||
continue
|
continue
|
||||||
# here: found an existing frontend already connected to right backend using an appropriate USB version
|
# here: found an existing frontend already connected to right backend using an appropriate USB version
|
||||||
ports = xs.ls(xs_trans, '/local/domain/%d/backend/vusb/%d/%d/port' % (backend_vm_xid, vm_xid, frontend_dev))
|
ports = vmm.xs.ls(xs_trans, '/local/domain/%d/backend/vusb/%d/%d/port' % (backend_vm_xid, vm_xid, frontend_dev))
|
||||||
if ports is None:
|
if ports is None:
|
||||||
print >> sys.stderr, "No ports in VM %d frontend_dev %d?" % (vm_xid, frontend_dev)
|
print >> sys.stderr, "No ports in VM %d frontend_dev %d?" % (vm_xid, frontend_dev)
|
||||||
last_frontend_dev = frontend_dev
|
last_frontend_dev = frontend_dev
|
||||||
@ -643,7 +643,7 @@ def usb_find_unused_frontend(xs_trans, backend_vm_xid, vm_xid, usb_ver):
|
|||||||
print >> sys.stderr, "Invalid port in VM %d frontend_dev %d" % (vm_xid, frontend_dev)
|
print >> sys.stderr, "Invalid port in VM %d frontend_dev %d" % (vm_xid, frontend_dev)
|
||||||
continue
|
continue
|
||||||
port = int(port)
|
port = int(port)
|
||||||
dev = xs.read(xs_trans, '/local/domain/%d/backend/vusb/%d/%s/port/%s' % (backend_vm_xid, vm_xid, frontend_dev, port))
|
dev = vmm.xs.read(xs_trans, '/local/domain/%d/backend/vusb/%d/%s/port/%s' % (backend_vm_xid, vm_xid, frontend_dev, port))
|
||||||
# Sanitize device id
|
# Sanitize device id
|
||||||
if not usb_port_re.match(dev):
|
if not usb_port_re.match(dev):
|
||||||
print >> sys.stderr, "Invalid device id in backend VM %d @ %d/%d/port/%d" % \
|
print >> sys.stderr, "Invalid device id in backend VM %d @ %d/%d/port/%d" % \
|
||||||
@ -661,12 +661,12 @@ def usb_find_unused_frontend(xs_trans, backend_vm_xid, vm_xid, usb_ver):
|
|||||||
def usb_attach(vm, backend_vm, device, frontend=None, auto_detach=False, wait=True):
|
def usb_attach(vm, backend_vm, device, frontend=None, auto_detach=False, wait=True):
|
||||||
device_attach_check(vm, backend_vm, device, frontend)
|
device_attach_check(vm, backend_vm, device, frontend)
|
||||||
|
|
||||||
xs_trans = xs.transaction_start()
|
xs_trans = vmm.xs.transaction_start()
|
||||||
|
|
||||||
xs_encoded_device = usb_encode_device_for_xs(device)
|
xs_encoded_device = usb_encode_device_for_xs(device)
|
||||||
usb_ver = xs.read(xs_trans, '/local/domain/%s/qubes-usb-devices/%s/usb-ver' % (backend_vm.xid, xs_encoded_device))
|
usb_ver = vmm.xs.read(xs_trans, '/local/domain/%s/qubes-usb-devices/%s/usb-ver' % (backend_vm.xid, xs_encoded_device))
|
||||||
if usb_ver is None or not usb_ver_re.match(usb_ver):
|
if usb_ver is None or not usb_ver_re.match(usb_ver):
|
||||||
xs.transaction_end(xs_trans)
|
vmm.xs.transaction_end(xs_trans)
|
||||||
raise QubesException("Invalid %s device USB version in VM '%s'" % (device, backend_vm.name))
|
raise QubesException("Invalid %s device USB version in VM '%s'" % (device, backend_vm.name))
|
||||||
|
|
||||||
if frontend is None:
|
if frontend is None:
|
||||||
@ -675,12 +675,12 @@ def usb_attach(vm, backend_vm, device, frontend=None, auto_detach=False, wait=Tr
|
|||||||
# Check if any device attached at this frontend
|
# Check if any device attached at this frontend
|
||||||
#if usb_check_frontend_busy(vm, frontend):
|
#if usb_check_frontend_busy(vm, frontend):
|
||||||
# raise QubesException("Frontend %s busy in VM %s, detach it first" % (frontend, vm.name))
|
# raise QubesException("Frontend %s busy in VM %s, detach it first" % (frontend, vm.name))
|
||||||
xs.transaction_end(xs_trans)
|
vmm.xs.transaction_end(xs_trans)
|
||||||
raise NotImplementedError("Explicit USB frontend specification is not implemented yet")
|
raise NotImplementedError("Explicit USB frontend specification is not implemented yet")
|
||||||
|
|
||||||
# Check if this device is attached to some domain
|
# Check if this device is attached to some domain
|
||||||
attached_vm = usb_check_attached(xs_trans, backend_vm.xid, device)
|
attached_vm = usb_check_attached(xs_trans, backend_vm.xid, device)
|
||||||
xs.transaction_end(xs_trans)
|
vmm.xs.transaction_end(xs_trans)
|
||||||
|
|
||||||
if attached_vm:
|
if attached_vm:
|
||||||
if auto_detach:
|
if auto_detach:
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
from qubes.qubes import QubesVmCollection
|
from qubes.qubes import QubesVmCollection,vmm
|
||||||
from qubes.qubes import QubesException
|
from qubes.qubes import QubesException
|
||||||
from optparse import OptionParser;
|
from optparse import OptionParser;
|
||||||
import sys
|
import sys
|
||||||
@ -56,6 +56,7 @@ def main():
|
|||||||
print >> sys.stderr, "... or use --force-root to continue anyway."
|
print >> sys.stderr, "... or use --force-root to continue anyway."
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
|
vmm.offline_mode = True
|
||||||
qvm_collection = QubesVmCollection()
|
qvm_collection = QubesVmCollection()
|
||||||
qvm_collection.lock_db_for_writing()
|
qvm_collection.lock_db_for_writing()
|
||||||
qvm_collection.load()
|
qvm_collection.load()
|
||||||
|
@ -21,10 +21,11 @@
|
|||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
from qubes.qubes import QubesVmCollection
|
from qubes.qubes import QubesVmCollection,vmm
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
vmm.offline_mode = True
|
||||||
qvm_collection = QubesVmCollection()
|
qvm_collection = QubesVmCollection()
|
||||||
if qvm_collection.check_if_storage_exists():
|
if qvm_collection.check_if_storage_exists():
|
||||||
print >> sys.stderr, "Storage exists, not overwriting."
|
print >> sys.stderr, "Storage exists, not overwriting."
|
||||||
|
Loading…
Reference in New Issue
Block a user