capabilities: Store results of guest_lookup together

Simplifies API users lives to not have to remember whether caps guest
or caps domain contains a particular value.
This commit is contained in:
Cole Robinson 2015-04-03 17:24:32 -04:00
parent 81a1910d90
commit 97259c4d9b
6 changed files with 110 additions and 81 deletions

View File

@ -353,23 +353,21 @@ def get_guest(conn, options):
arch = "i686"
try:
(capsguest,
capsdomain) = conn.caps.guest_lookup(
os_type=req_virt_type,
arch=arch,
typ=req_hv_type,
machine=options.machine)
guest = conn.caps.build_virtinst_guest(conn, capsguest, capsdomain)
guest = conn.caps.lookup_virtinst_guest(
os_type=req_virt_type,
arch=arch,
typ=req_hv_type,
machine=options.machine)
except Exception, e:
fail(e)
if (not req_virt_type and
not req_hv_type and
conn.is_qemu() and
capsguest.arch in ["i686", "x86_64"] and
not capsdomain.is_accelerated()):
guest.os.arch in ["i686", "x86_64"] and
not guest.type == "kvm"):
logging.warn("KVM acceleration not available, using '%s'",
capsdomain.hypervisor_type)
guest.type)
return guest
@ -398,8 +396,7 @@ def set_install_media(guest, location, cdpath, distro_variant):
def do_test_media_detection(conn, url):
(capsguest, capsdomain) = conn.caps.guest_lookup()
guest = conn.caps.build_virtinst_guest(conn, capsguest, capsdomain)
guest = conn.caps.lookup_virtinst_guest()
guest.installer = virtinst.DistroInstaller(conn)
guest.installer.location = url
print_stdout(guest.installer.detect_distro(guest), do_force=True)

View File

@ -82,8 +82,7 @@ class vmmCreate(vmmGObjectUI):
self.engine = engine
self.conn = None
self.capsguest = None
self.capsdomain = None
self.capsinfo = None
self.guest = None
self.disk = None
@ -186,8 +185,7 @@ class vmmCreate(vmmGObjectUI):
self.remove_conn()
self.conn = None
self.capsguest = None
self.capsdomain = None
self.capsinfo = None
self.guest = None
self.disk = None
@ -212,8 +210,7 @@ class vmmCreate(vmmGObjectUI):
def remove_conn(self):
self.conn = None
self.capsguest = None
self.capsdomain = None
self.capsinfo = None
def set_conn(self, newconn, force_validate=False):
if self.conn == newconn and not force_validate:
@ -407,23 +404,22 @@ class vmmCreate(vmmGObjectUI):
self.topwin.resize(1, 1)
def set_caps_state(self):
# State that is dependent on when capsguest changes
# State that is dependent on when capsinfo changes
# Helper state
is_local = not self.conn.is_remote()
is_storage_capable = self.conn.is_storage_capable()
can_storage = (is_local or is_storage_capable)
is_pv = (self.capsguest.os_type == "xen")
is_pv = (self.capsinfo.os_type == "xen")
is_container = self.conn.is_container()
can_remote_url = self.conn.get_backend().support_remote_url_install()
installable_arch = (self.capsguest.arch in
installable_arch = (self.capsinfo.arch in
["i686", "x86_64", "ppc64", "ia64"])
if self.capsguest.arch == "aarch64":
if self.capsinfo.arch == "aarch64":
try:
guest = self.conn.caps.build_virtinst_guest(
self.conn.get_backend(), self.capsguest, self.capsdomain)
guest = self.conn.caps.build_virtinst_guest(self.capsinfo)
guest.set_uefi_default()
installable_arch = True
logging.debug("UEFI found for aarch64, setting it as default.")
@ -470,7 +466,7 @@ class vmmCreate(vmmGObjectUI):
if not installable_arch:
msg = (_("Architecture '%s' is not installable") %
self.capsguest.arch)
self.capsinfo.arch)
tree_tt = msg
local_tt = msg
pxe_tt = msg
@ -498,9 +494,9 @@ class vmmCreate(vmmGObjectUI):
self.widget("virt-install-box").set_visible(not is_container)
self.widget("container-install-box").set_visible(is_container)
show_dtb = ("arm" in self.capsguest.arch or
"microblaze" in self.capsguest.arch or
"ppc" in self.capsguest.arch)
show_dtb = ("arm" in self.capsinfo.arch or
"microblaze" in self.capsinfo.arch or
"ppc" in self.capsinfo.arch)
self.widget("config-kernel-box").set_visible(not installable_arch)
uiutil.set_grid_row_visible(self.widget("config-dtb"), show_dtb)
@ -663,8 +659,8 @@ class vmmCreate(vmmGObjectUI):
continue
# Determine if this is the default given by guest_lookup
if (gtype == self.capsguest.os_type and
self.capsdomain.hypervisor_type == domtype):
if (gtype == self.capsinfo.os_type and
self.capsinfo.hypervisor_type == domtype):
default = len(model)
model.append([label, gtype])
@ -682,7 +678,7 @@ class vmmCreate(vmmGObjectUI):
default = 0
archs = []
for guest in self.conn.caps.guests:
if guest.os_type == self.capsguest.os_type:
if guest.os_type == self.capsinfo.os_type:
archs.append(guest.arch)
# Combine x86/i686 to avoid confusion
@ -706,8 +702,8 @@ class vmmCreate(vmmGObjectUI):
archs = prios + archs
default = 0
if self.capsguest.arch in archs:
default = archs.index(self.capsguest.arch)
if self.capsinfo.arch in archs:
default = archs.index(self.capsinfo.arch)
for arch in archs:
model.append([arch, pretty_arch(arch)])
@ -721,15 +717,14 @@ class vmmCreate(vmmGObjectUI):
model = lst.get_model()
model.clear()
machines = self.capsdomain.machines[:]
if self.capsguest.arch in ["i686", "x86_64"]:
machines = self.capsinfo.machines[:]
if self.capsinfo.arch in ["i686", "x86_64"]:
machines = []
machines.sort()
defmachine = None
prios = []
recommended_machine = self.capsdomain.get_recommended_machine(
self.conn.get_backend(), self.capsguest)
recommended_machine = self.capsinfo.get_recommended_machine()
if recommended_machine:
defmachine = recommended_machine
prios = [defmachine]
@ -889,17 +884,19 @@ class vmmCreate(vmmGObjectUI):
gtype = "hvm"
break
(newg, newdom) = self.conn.caps.guest_lookup(os_type=gtype, arch=arch)
capsinfo = self.conn.caps.guest_lookup(os_type=gtype, arch=arch)
newg, newdom = capsinfo.get_caps_objects()
if self.capsguest == newg and self.capsdomain and newdom:
return
if self.capsinfo:
oldg, olddom = self.capsinfo.get_caps_objects()
if oldg == newg and olddom and newdom:
return
self.capsguest = newg
self.capsdomain = newdom
self.capsinfo = capsinfo
logging.debug("Guest type set to os_type=%s, arch=%s, dom_type=%s",
self.capsguest.os_type,
self.capsguest.arch,
self.capsdomain.hypervisor_type)
self.capsinfo.os_type,
self.capsinfo.arch,
self.capsinfo.hypervisor_type)
self.populate_machine()
self.set_caps_state()
@ -1108,7 +1105,7 @@ class vmmCreate(vmmGObjectUI):
def machine_changed(self, ignore):
machine = self.get_config_machine()
show_dtb_virtio = (self.capsguest.arch == "armv7l" and
show_dtb_virtio = (self.capsinfo.arch == "armv7l" and
machine in ["vexpress-a9", "vexpress-15"])
uiutil.set_grid_row_visible(
self.widget("config-dtb-warn-virtio"), show_dtb_virtio)
@ -1154,7 +1151,7 @@ class vmmCreate(vmmGObjectUI):
if not arch:
return
self.change_caps(self.capsguest.os_type, arch)
self.change_caps(self.capsinfo.os_type, arch)
def media_box_changed(self, widget):
self.mediaDetected = False
@ -1408,8 +1405,7 @@ class vmmCreate(vmmGObjectUI):
page.set_visible(nr == pagenum)
def build_guest(self, variant):
guest = self.conn.caps.build_virtinst_guest(
self.conn.get_backend(), self.capsguest, self.capsdomain)
guest = self.conn.caps.build_virtinst_guest(self.capsinfo)
guest.os.machine = self.get_config_machine()
# Generate UUID (makes customize dialog happy)
@ -1627,11 +1623,11 @@ class vmmCreate(vmmGObjectUI):
self.guest.os.dtb = dtb
self.guest.os.kernel_args = kargs
require_kernel = ("arm" in self.capsguest.arch)
require_kernel = ("arm" in self.capsinfo.arch)
if require_kernel and not kernel:
return self.err.val_err(
_("A kernel is required for %s guests.") %
self.capsguest.arch)
self.capsinfo.arch)
try:
name = self._generate_default_name(distro, variant)
@ -2092,8 +2088,8 @@ class vmmCreate(vmmGObjectUI):
emu = None
if self.guest:
emu = self.guest.emulator
elif self.capsdomain:
emu = self.capsdomain.emulator
elif self.capsinfo:
emu = self.capsinfo.emulator
ret = self.conn.stable_defaults(emu)
return ret

View File

@ -758,13 +758,13 @@ class vmmDetails(vmmGObjectUI):
machines = []
try:
ignore, domain = caps.guest_lookup(
capsinfo = caps.guest_lookup(
os_type=self.vm.get_abi_type(),
arch=self.vm.get_arch(),
typ=self.vm.get_hv_type(),
machine=self.vm.get_machtype())
machines = domain.machines[:]
machines = capsinfo.machines[:]
except:
logging.exception("Error determining machine list")

View File

@ -316,8 +316,7 @@ def _import_file(doc, ctx, conn, input_file):
ignore = os_id
ignore = os_vmware
(capsguest, capsdomain) = conn.caps.guest_lookup()
guest = conn.caps.build_virtinst_guest(conn, capsguest, capsdomain)
guest = conn.caps.lookup_virtinst_guest()
guest.installer = virtinst.ImportInstaller(conn)
if not name:

View File

@ -295,8 +295,7 @@ class vmx_parser(parser_class):
not os.path.exists(disk.path)):
disk.path = None
(capsguest, capsdomain) = conn.caps.guest_lookup()
guest = conn.caps.build_virtinst_guest(conn, capsguest, capsdomain)
guest = conn.caps.lookup_virtinst_guest()
guest.installer = virtinst.ImportInstaller(conn)
guest.name = name.replace(" ", "_")

View File

@ -222,15 +222,17 @@ class _CapsDomain(XMLBuilder):
# Public APIs #
###############
def get_recommended_machine(self, conn, capsguest):
def get_recommended_machine(self, capsguest):
if self._recommended_machine:
return self._recommended_machine
if not conn.is_test() and not conn.is_qemu():
if not self.conn.is_test() and not self.conn.is_qemu():
return None
if capsguest.arch in ["ppc64", "ppc64le"] and "pseries" in self.machines:
if (capsguest.arch in ["ppc64", "ppc64le"] and
"pseries" in self.machines):
return "pseries"
if capsguest.arch in ["armv7l", "aarch64"]:
if "virt" in self.machines:
return "virt"
@ -242,9 +244,6 @@ class _CapsDomain(XMLBuilder):
def set_recommended_machine(self, machine):
self._recommended_machine = machine
def is_accelerated(self):
return self.hypervisor_type in ["kvm"]
class _CapsGuestFeatures(XMLBuilder):
_XML_ROOT_NAME = "features"
@ -259,17 +258,17 @@ class _CapsGuest(XMLBuilder):
def __init__(self, *args, **kwargs):
XMLBuilder.__init__(self, *args, **kwargs)
self.machines = []
machines = []
for m in self._machines:
self.machines.append(m.name)
machines.append(m.name)
if m.canonical:
self.machines.append(m.canonical)
machines.append(m.canonical)
for d in self.domains:
if not d.emulator:
d.emulator = self.emulator
d.emulator = self._emulator
if not d.machines:
d.machines = self.machines
d.machines = machines
_XML_ROOT_NAME = "guest"
@ -277,7 +276,7 @@ class _CapsGuest(XMLBuilder):
os_type = XMLProperty("./os_type")
arch = XMLProperty("./arch/@name")
loader = XMLProperty("./arch/loader")
emulator = XMLProperty("./arch/emulator")
_emulator = XMLProperty("./arch/emulator")
domains = XMLChildProperty(_CapsDomain, relative_xpath="./arch")
features = XMLChildProperty(_CapsGuestFeatures, is_single=True)
@ -324,6 +323,30 @@ class _CapsGuest(XMLBuilder):
# Main capabilities object #
############################
class _CapsInfo(object):
"""
Container object to hold the results of guest_lookup, so users don't
need to juggle two objects
"""
def __init__(self, guest, domain):
self._guest = guest
self._domain = domain
self.hypervisor_type = self._domain.hypervisor_type
self.os_type = self._guest.os_type
self.arch = self._guest.arch
self.loader = self._guest.loader
self.emulator = self._domain.emulator
self.machines = self._domain.machines[:]
def get_caps_objects(self):
return self._guest, self._domain
def get_recommended_machine(self):
return self._domain.get_recommended_machine(self._guest)
class Capabilities(XMLBuilder):
# Set by the test suite to force a particular code path
_force_cpumap = False
@ -453,7 +476,7 @@ class Capabilities(XMLBuilder):
@param os_type: Hypervisor name ('qemu', 'kvm', 'xen', ...)
@param machine: Optional machine type to emulate
@returns: A (Capabilities Guest, Capabilities Domain) tuple
@returns: A _CapsInfo object containing the found guest and domain
"""
guest = self._guestForOSType(os_type, arch)
if not guest:
@ -479,16 +502,31 @@ class Capabilities(XMLBuilder):
{'domain': typ, 'virttype': guest.os_type,
'arch': guest.arch, 'machine': machinestr})
return (guest, domain)
capsinfo = _CapsInfo(guest, domain)
return capsinfo
def build_virtinst_guest(self, conn, guest, domain):
def build_virtinst_guest(self, capsinfo):
"""
Fill in a new Guest() object from the results of guest_lookup
"""
from .guest import Guest
gobj = Guest(conn)
gobj.type = domain.hypervisor_type
gobj.os.os_type = guest.os_type
gobj.os.arch = guest.arch
gobj.os.loader = guest.loader
gobj.emulator = domain.emulator
gobj.os.machine = domain.get_recommended_machine(conn, guest)
gobj = Guest(self.conn)
gobj.type = capsinfo.hypervisor_type
gobj.os.os_type = capsinfo.os_type
gobj.os.arch = capsinfo.arch
gobj.os.loader = capsinfo.loader
gobj.emulator = capsinfo.emulator
gobj.os.machine = capsinfo.get_recommended_machine()
return gobj
def lookup_virtinst_guest(self, *args, **kwargs):
"""
Call guest_lookup and pass the results to build_virtinst_guest.
This is a shortcut for API users that don't need to do anything
with the output from guest_lookup
"""
capsinfo = self.guest_lookup(*args, **kwargs)
return self.build_virtinst_guest(capsinfo)