622 lines
22 KiB
Python
622 lines
22 KiB
Python
#
|
|
# List of OS Specific data
|
|
#
|
|
# Copyright 2006-2008, 2013 Red Hat, Inc.
|
|
# Jeremy Katz <katzj@redhat.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.
|
|
|
|
_SENTINEL = -1234
|
|
_allvariants = {}
|
|
from datetime import datetime
|
|
from gi.repository import Libosinfo as libosinfo
|
|
from inspect import isfunction
|
|
|
|
_aliases = {
|
|
"altlinux" : "altlinux1.0",
|
|
"debianetch" : "debian4",
|
|
"debianlenny" : "debian5",
|
|
"debiansqueeze" : "debian6",
|
|
"debianwheezy" : "debian7",
|
|
"freebsd10" : "freebsd10.0",
|
|
"freebsd6" : "freebsd6.0",
|
|
"freebsd7" : "freebsd7.0",
|
|
"freebsd8" : "freebsd8.0",
|
|
"freebsd9" : "freebsd9.0",
|
|
"mandriva2009" : "mandriva2009.0",
|
|
"mandriva2010" : "mandriva2010.0",
|
|
"mbs1" : "mbs1.0",
|
|
"msdos" : "msdos6.22",
|
|
"openbsd4" : "openbsd4.2",
|
|
"opensolaris" : "opensolaris2009.06",
|
|
"opensuse11" : "opensuse11.4",
|
|
"opensuse12" : "opensuse12.3",
|
|
"rhel4" : "rhel4.0",
|
|
"rhel5" : "rhel5.0",
|
|
"rhel6" : "rhel6.0",
|
|
"rhel7" : "rhel7.0",
|
|
"ubuntuhardy" : "ubuntu8.04",
|
|
"ubuntuintrepid" : "ubuntu8.10",
|
|
"ubuntujaunty" : "ubuntu9.04",
|
|
"ubuntukarmic" : "ubuntu9.10",
|
|
"ubuntulucid" : "ubuntu10.04",
|
|
"ubuntumaverick" : "ubuntu10.10",
|
|
"ubuntunatty" : "ubuntu11.04",
|
|
"ubuntuoneiric" : "ubuntu11.10",
|
|
"ubuntuprecise" : "ubuntu12.04",
|
|
"ubuntuquantal" : "ubuntu12.10",
|
|
"ubunturaring" : "ubuntu13.04",
|
|
"ubuntusaucy" : "ubuntu13.10",
|
|
"vista" : "winvista",
|
|
"winxp64" : "winxp",
|
|
}
|
|
|
|
|
|
def _sort(tosort, sortpref=None):
|
|
sortby_mappings = {}
|
|
distro_mappings = {}
|
|
retlist = []
|
|
sortpref = sortpref or []
|
|
|
|
# Make sure we are sorting by 'sortby' if specified, and group distros
|
|
# by their 'distro' tag first and foremost
|
|
for key, osinfo in tosort.items():
|
|
sortby = osinfo.sortby or key
|
|
# Hack to allow "sortby" duplicates. Remove when this never happens
|
|
# with libosinfo
|
|
while sortby_mappings.get(sortby):
|
|
sortby = sortby + ".1"
|
|
sortby_mappings[sortby] = key
|
|
|
|
distro = osinfo.urldistro or "zzzzzzz"
|
|
if distro not in distro_mappings:
|
|
distro_mappings[distro] = []
|
|
distro_mappings[distro].append(sortby)
|
|
|
|
# We want returned lists to be sorted descending by 'distro', so we get
|
|
# debian5, debian4, fedora14, fedora13
|
|
# rather than
|
|
# debian4, debian5, fedora13, fedora14
|
|
for distro_list in distro_mappings.values():
|
|
distro_list.sort()
|
|
distro_list.reverse()
|
|
|
|
sorted_distro_list = distro_mappings.keys()
|
|
sorted_distro_list.sort()
|
|
sortpref.reverse()
|
|
for prefer in sortpref:
|
|
if prefer not in sorted_distro_list:
|
|
continue
|
|
sorted_distro_list.remove(prefer)
|
|
sorted_distro_list.insert(0, prefer)
|
|
|
|
for distro in sorted_distro_list:
|
|
distro_list = distro_mappings[distro]
|
|
for key in distro_list:
|
|
orig_key = sortby_mappings[key]
|
|
retlist.append(tosort[orig_key])
|
|
|
|
return retlist
|
|
|
|
|
|
class _OSVariant(object):
|
|
"""
|
|
Object tracking guest OS specific configuration bits.
|
|
|
|
@name: name of the object. This must be lowercase. This becomes part of
|
|
the virt-install command line API so we cannot remove any existing
|
|
name (we could probably add aliases though)
|
|
@label: Pretty printed label. This is used in the virt-manager UI.
|
|
We can tweak this.
|
|
@is_type: virt-install historically had a distinction between an
|
|
os 'type' (windows, linux, etc), and an os 'variant' (fedora18,
|
|
winxp, etc). Back in 2009 we actually required the user to
|
|
specify --os-type if specifying an --os-variant even though we
|
|
could figure it out easily. This distinction isn't needed any
|
|
more, though it's still baked into the virt-manager UI where
|
|
it is still pretty useful, so we fake it here. New types should
|
|
not be added often.
|
|
@parent: Name of a pre-created variant that we want to extend. So
|
|
fedoraFOO would have parent fedoraFOO-1. It's used for inheriting
|
|
values.
|
|
@typename: The family of the OS, e.g. "linux", "windows", "unix".
|
|
@sortby: A different key to use for sorting the distro list. By default
|
|
it's 'name', so this doesn't need to be specified.
|
|
@urldistro: This is a distro class. It's wired up in urlfetcher to give
|
|
us a shortcut when detecting OS type from a URL.
|
|
@supported: If this distro is supported by it's owning organization,
|
|
like is it still receiving updates. We use this to limit the
|
|
distros we show in virt-manager by default, so old distros aren't
|
|
squeezing out current ones.
|
|
@three_stage_install: If True, this VM has a 3 stage install, AKA windows.
|
|
@virtionet: If True, this OS supports virtionet out of the box
|
|
@virtiodisk: If True, this OS supports virtiodisk out of the box
|
|
@virtiommio: If True, this OS supports virtio-mmio out of the box,
|
|
which provides virtio for certain ARM configurations
|
|
@virtioconsole: If True, this OS supports virtio-console out of the box,
|
|
and we should use it as the default console.
|
|
@xen_disable_acpi: If True, disable acpi/apic for this OS if on old xen.
|
|
This corresponds with the SUPPORT_CONN_CAN_DEFAULT_ACPI check
|
|
@qemu_ga: If True, this distro has qemu_ga available by default
|
|
@hyperv_features: If True, this distro prefers Hyper-V enlightenments
|
|
|
|
The rest of the parameters are about setting device/guest defaults
|
|
based on the OS. They should be self explanatory. See guest.py for
|
|
their usage.
|
|
"""
|
|
_os = None
|
|
|
|
def __init__(self, name, label, is_type=False,
|
|
sortby=None, parent=_SENTINEL, typename=_SENTINEL,
|
|
urldistro=_SENTINEL, supported=_SENTINEL,
|
|
three_stage_install=_SENTINEL,
|
|
acpi=_SENTINEL, apic=_SENTINEL, clock=_SENTINEL,
|
|
netmodel=_SENTINEL, diskbus=_SENTINEL,
|
|
inputtype=_SENTINEL, inputbus=_SENTINEL,
|
|
virtionet=_SENTINEL,
|
|
virtiodisk=_SENTINEL, virtiommio=_SENTINEL,
|
|
virtioconsole=_SENTINEL, xen_disable_acpi=_SENTINEL,
|
|
qemu_ga=_SENTINEL, hyperv_features=_SENTINEL):
|
|
if is_type:
|
|
if parent != _SENTINEL:
|
|
raise RuntimeError("OS types must not specify parent")
|
|
parent = None
|
|
elif parent == _SENTINEL:
|
|
raise RuntimeError("Must specify explicit parent")
|
|
else:
|
|
parent = _allvariants[parent]
|
|
|
|
def _get_default(name, val, default=_SENTINEL):
|
|
if val == _SENTINEL:
|
|
if not parent:
|
|
return default
|
|
return getattr(parent, name)
|
|
return val
|
|
|
|
if name != name.lower():
|
|
raise RuntimeError("OS dictionary wants lowercase name, not "
|
|
"'%s'" % name)
|
|
|
|
self.name = name
|
|
self.label = label
|
|
self.sortby = sortby
|
|
|
|
self.is_type = bool(is_type)
|
|
|
|
self.typename = typename
|
|
if typename == _SENTINEL:
|
|
self.typename = _get_default("typename",
|
|
self.is_type and self.name or _SENTINEL)
|
|
|
|
# 'types' should rarely be altered, this check will make
|
|
# doubly sure that a new type isn't accidentally added
|
|
_approved_types = ["linux", "windows", "unix",
|
|
"solaris", "other"]
|
|
if self.typename not in _approved_types:
|
|
raise RuntimeError("type '%s' for variant '%s' not in list "
|
|
"of approved distro types %s" %
|
|
(self.typename, self.name, _approved_types))
|
|
|
|
self.urldistro = _get_default("urldistro", urldistro, None)
|
|
self.supported = _get_default("supported", supported, False)
|
|
self.three_stage_install = _get_default("three_stage_install",
|
|
three_stage_install)
|
|
|
|
self.acpi = _get_default("acpi", acpi)
|
|
self.apic = _get_default("apic", apic)
|
|
self.clock = _get_default("clock", clock)
|
|
|
|
self.netmodel = _get_default("netmodel", netmodel)
|
|
self.diskbus = _get_default("diskbus", diskbus)
|
|
self.inputtype = _get_default("inputtype", inputtype)
|
|
self.inputbus = _get_default("inputbus", inputbus)
|
|
|
|
self.xen_disable_acpi = _get_default("xen_disable_acpi",
|
|
xen_disable_acpi)
|
|
self.virtiodisk = _get_default("virtiodisk", virtiodisk)
|
|
self.virtionet = _get_default("virtionet", virtionet)
|
|
self.virtiommio = _get_default("virtiommio", virtiommio)
|
|
self.virtioconsole = _get_default("virtioconsole", virtioconsole)
|
|
self.qemu_ga = _get_default("qemu_ga", qemu_ga)
|
|
self.hyperv_features = _get_default("hyperv_features", hyperv_features)
|
|
|
|
def get_recommended_resources(self, arch):
|
|
ignore1 = arch
|
|
return None
|
|
|
|
def get_videomodel(self, guest):
|
|
if guest.os.is_ppc64() and guest.os.machine == "pseries":
|
|
return "vga"
|
|
|
|
# Marc Deslauriers of canonical had previously patched us
|
|
# to use vmvga for ubuntu, see fb76c4e5. And Fedora users report
|
|
# issues with ubuntu + qxl for as late as 14.04, so carry the vmvga
|
|
# default forward until someone says otherwise. In 2014-09 I contacted
|
|
# Marc offlist and he said this was fine for now.
|
|
if self._os and self._os.get_distro() == "ubuntu":
|
|
return "vmvga"
|
|
|
|
if guest.has_spice() and guest.os.is_x86():
|
|
return "qxl"
|
|
|
|
if self._os and _OsVariantOsInfo.is_windows(self._os):
|
|
return "vga"
|
|
|
|
return None
|
|
|
|
|
|
def _add_type(*args, **kwargs):
|
|
kwargs["is_type"] = True
|
|
_t = _OSVariant(*args, **kwargs)
|
|
_allvariants[_t.name] = _t
|
|
|
|
|
|
def _add_var(*args, **kwargs):
|
|
v = _OSVariant(*args, **kwargs)
|
|
_allvariants[v.name] = v
|
|
|
|
|
|
class _OsVariantOsInfo(_OSVariant):
|
|
|
|
@staticmethod
|
|
def is_windows(o):
|
|
return o.get_family() in ['win9x', 'winnt', 'win16']
|
|
|
|
def _is_three_stage_install(self):
|
|
if _OsVariantOsInfo.is_windows(self._os):
|
|
return True
|
|
return _SENTINEL
|
|
|
|
def _get_clock(self):
|
|
if _OsVariantOsInfo.is_windows(self._os) or \
|
|
self._os.get_family() in ['solaris']:
|
|
return "localtime"
|
|
return _SENTINEL
|
|
|
|
def _is_acpi(self):
|
|
if self._os.get_family() in ['msdos']:
|
|
return False
|
|
return _SENTINEL
|
|
|
|
def _is_apic(self):
|
|
if self._os.get_family() in ['msdos']:
|
|
return False
|
|
return _SENTINEL
|
|
|
|
def _get_netmodel(self):
|
|
if self._os.get_distro() == "fedora":
|
|
return _SENTINEL
|
|
|
|
fltr = libosinfo.Filter()
|
|
fltr.add_constraint("class", "net")
|
|
devs = self._os.get_all_devices(fltr)
|
|
if devs.get_length():
|
|
return devs.get_nth(0).get_name()
|
|
return _SENTINEL
|
|
|
|
def _get_inputtype(self):
|
|
fltr = libosinfo.Filter()
|
|
fltr.add_constraint("class", "input")
|
|
devs = self._os.get_all_devices(fltr)
|
|
if devs.get_length():
|
|
return devs.get_nth(0).get_name()
|
|
return _SENTINEL
|
|
|
|
def get_inputbus(self):
|
|
fltr = libosinfo.Filter()
|
|
fltr.add_constraint("class", "input")
|
|
devs = self._os.get_all_devices(fltr)
|
|
if devs.get_length():
|
|
return devs.get_nth(0).get_bus_type()
|
|
return _SENTINEL
|
|
|
|
def _get_diskbus(self):
|
|
return _SENTINEL
|
|
|
|
@staticmethod
|
|
def is_os_related_to(o, related_os_list):
|
|
if o.get_short_id() in related_os_list:
|
|
return True
|
|
related = o.get_related(libosinfo.ProductRelationship.DERIVES_FROM)
|
|
clones = o.get_related(libosinfo.ProductRelationship.CLONES)
|
|
for r in related.get_elements() + clones.get_elements():
|
|
if r.get_short_id() in related_os_list or \
|
|
_OsVariantOsInfo.is_os_related_to(r, related_os_list):
|
|
return True
|
|
|
|
return False
|
|
|
|
def _get_xen_disable_acpi(self):
|
|
if _OsVariantOsInfo.is_os_related_to(self._os, ["winxp", "win2k"]):
|
|
return True
|
|
return _SENTINEL
|
|
|
|
def _is_virtiodisk(self):
|
|
if self._os.get_distro() == "fedora":
|
|
if self._os.get_version() == "unknown":
|
|
return _SENTINEL
|
|
return int(self._os.get_version() >= 10) or _SENTINEL
|
|
|
|
fltr = libosinfo.Filter()
|
|
fltr.add_constraint("class", "block")
|
|
devs = self._os.get_all_devices(fltr)
|
|
for dev in range(devs.get_length()):
|
|
d = devs.get_nth(dev)
|
|
if d.get_name() == "virtio-block":
|
|
return True
|
|
|
|
return _SENTINEL
|
|
|
|
def _is_virtionet(self):
|
|
if self._os.get_distro() == "fedora":
|
|
if self._os.get_version() == "unknown":
|
|
return _SENTINEL
|
|
return int(self._os.get_version() >= 9) or _SENTINEL
|
|
|
|
fltr = libosinfo.Filter()
|
|
fltr.add_constraint("class", "net")
|
|
devs = self._os.get_all_devices(fltr)
|
|
for dev in range(devs.get_length()):
|
|
d = devs.get_nth(dev)
|
|
if d.get_name() == "virtio-net":
|
|
return True
|
|
return _SENTINEL
|
|
|
|
def _is_virtioconsole(self):
|
|
# We used to enable this for Fedora 18+, because systemd would
|
|
# autostart a getty on /dev/hvc0 which made 'virsh console' work
|
|
# out of the box for a login prompt. However now in Fedora
|
|
# virtio-console is compiled as a module, and systemd doesn't
|
|
# detect it in time to start a getty. So the benefit of using
|
|
# it as the default is erased, and we reverted to this.
|
|
# https://bugzilla.redhat.com/show_bug.cgi?id=1039742
|
|
return _SENTINEL
|
|
|
|
def _is_virtiommio(self):
|
|
if _OsVariantOsInfo.is_os_related_to(self._os, ["fedora19"]):
|
|
return True
|
|
return _SENTINEL
|
|
|
|
def _is_qemu_ga(self):
|
|
if self._os.get_distro() == "fedora":
|
|
if self._os.get_version() == "unknown":
|
|
return _SENTINEL
|
|
return int(self._os.get_version()) >= 18 or _SENTINEL
|
|
return _SENTINEL
|
|
|
|
def _is_hyperv_features(self):
|
|
if _OsVariantOsInfo.is_windows(self._os):
|
|
return True
|
|
return _SENTINEL
|
|
|
|
def _get_typename(self):
|
|
if self._os.get_family() in ['linux']:
|
|
return "linux"
|
|
|
|
if self._os.get_family() in ['win9x', 'winnt', 'win16']:
|
|
return "windows"
|
|
|
|
if self._os.get_family() in ['solaris']:
|
|
return "solaris"
|
|
|
|
if self._os.get_family() in ['openbsd', 'freebsd', 'netbsd']:
|
|
return "unix"
|
|
|
|
return "other"
|
|
|
|
def _get_sortby(self):
|
|
version = self._os.get_version()
|
|
try:
|
|
t = version.split(".")
|
|
t = t[:min(4, len(t))] + [0] * (4 - min(4, len(t)))
|
|
new_version = ""
|
|
for n in t:
|
|
new_version = new_version + ("%.4i" % int(n))
|
|
version = new_version
|
|
except:
|
|
pass
|
|
|
|
distro = self._os.get_distro()
|
|
return "%s-%s" % (distro, version)
|
|
|
|
def _get_supported(self):
|
|
d = self._os.get_eol_date_string()
|
|
name = self._os.get_short_id()
|
|
|
|
if d:
|
|
return datetime.strptime(d, "%Y-%m-%d") > datetime.now()
|
|
|
|
# As of libosinfo 2.11, many clearly EOL distros don't have an
|
|
# EOL date. So assume None == EOL, add some manual work arounds.
|
|
# We should fix this in a new libosinfo version, and then drop
|
|
# this hack
|
|
if name in ["rhel7.0", "rhel7.1", "fedora19", "fedora20", "fedora21",
|
|
"debian6", "debian7", "ubuntu13.04", "ubuntu13.10", "ubuntu14.04",
|
|
"ubuntu14.10", "win8", "win8.1", "win2k12", "win2k12r2"]:
|
|
return True
|
|
return False
|
|
|
|
def _get_urldistro(self):
|
|
urldistro = self._os.get_distro()
|
|
remap = {
|
|
"opensuse" : "suse",
|
|
"sles" : "suse",
|
|
"mes" : "mandriva"
|
|
}
|
|
|
|
if remap.get(urldistro):
|
|
return remap[urldistro]
|
|
|
|
return urldistro
|
|
|
|
def _get_name(self):
|
|
return self._os.get_short_id()
|
|
|
|
def get_label(self):
|
|
return self._os.get_name()
|
|
|
|
def __init__(self, o):
|
|
self._os = o
|
|
name = self._get_name()
|
|
label = self.get_label()
|
|
sortby = self._get_sortby()
|
|
is_type = False
|
|
typename = self._get_typename()
|
|
urldistro = self._get_urldistro()
|
|
supported = self._get_supported()
|
|
three_stage_install = self._is_three_stage_install()
|
|
acpi = self._is_acpi()
|
|
apic = self._is_apic()
|
|
clock = self._get_clock()
|
|
xen_disable_acpi = self._get_xen_disable_acpi()
|
|
virtiommio = self._is_virtiommio()
|
|
qemu_ga = self._is_qemu_ga()
|
|
hyperv_features = self._is_hyperv_features()
|
|
virtioconsole = lambda: self._is_virtioconsole()
|
|
netmodel = lambda: self._get_netmodel()
|
|
diskbus = lambda: self._get_diskbus()
|
|
inputtype = lambda: self._get_inputtype()
|
|
inputbus = lambda: self.get_inputbus()
|
|
virtiodisk = lambda: self._is_virtiodisk()
|
|
virtionet = lambda: self._is_virtionet()
|
|
_OSVariant.__init__(self, name=name, label=label, is_type=is_type,
|
|
typename=typename, sortby=sortby, parent="generic",
|
|
urldistro=urldistro, supported=supported,
|
|
three_stage_install=three_stage_install, acpi=acpi, apic=apic,
|
|
clock=clock, netmodel=netmodel, diskbus=diskbus,
|
|
inputtype=inputtype, inputbus=inputbus,
|
|
virtionet=virtionet, virtiodisk=virtiodisk,
|
|
virtiommio=virtiommio, virtioconsole=virtioconsole,
|
|
xen_disable_acpi=xen_disable_acpi, qemu_ga=qemu_ga,
|
|
hyperv_features=hyperv_features)
|
|
|
|
def get_recommended_resources(self, arch):
|
|
ret = {}
|
|
def read_resource(resources, arch):
|
|
for i in range(resources.get_length()):
|
|
r = resources.get_nth(i)
|
|
if r.get_architecture() == arch:
|
|
ret["ram"] = r.get_ram()
|
|
ret["cpu"] = r.get_cpu()
|
|
ret["n-cpus"] = r.get_n_cpus()
|
|
ret["storage"] = r.get_storage()
|
|
break
|
|
|
|
read_resource(self._os.get_recommended_resources(), "all")
|
|
read_resource(self._os.get_recommended_resources(), arch)
|
|
|
|
return ret
|
|
|
|
|
|
_add_type("linux", "Linux")
|
|
_add_type("windows", "Windows", clock="localtime", three_stage_install=True, inputtype="tablet", inputbus="usb")
|
|
_add_type("solaris", "Solaris", clock="localtime")
|
|
_add_type("unix", "UNIX")
|
|
_add_type("other", "Other")
|
|
_add_var("generic", "Generic", supported=True, parent="other")
|
|
|
|
|
|
_os_data_loaded = False
|
|
_os_loader = None
|
|
|
|
|
|
def _get_os_loader():
|
|
global _os_loader
|
|
if _os_loader:
|
|
return _os_loader
|
|
_os_loader = libosinfo.Loader()
|
|
_os_loader.process_default_path()
|
|
return _os_loader
|
|
|
|
|
|
def _load_os_data():
|
|
global _os_data_loaded
|
|
if _os_data_loaded:
|
|
return
|
|
loader = _get_os_loader()
|
|
db = loader.get_db()
|
|
oslist = db.get_os_list()
|
|
for os in range(oslist.get_length()):
|
|
osi = _OsVariantOsInfo(oslist.get_nth(os))
|
|
_allvariants[osi.name] = osi
|
|
_os_data_loaded = True
|
|
|
|
|
|
def lookup_os(key):
|
|
_load_os_data()
|
|
key = _aliases.get(key) or key
|
|
ret = _allvariants.get(key)
|
|
if ret is None:
|
|
return ret
|
|
return ret
|
|
|
|
|
|
def list_os(list_types=False, typename=None,
|
|
filtervars=None, only_supported=False,
|
|
**kwargs):
|
|
_load_os_data()
|
|
sortmap = {}
|
|
filtervars = filtervars or []
|
|
|
|
for key, osinfo in _allvariants.items():
|
|
if list_types and not osinfo.is_type:
|
|
continue
|
|
if not list_types and osinfo.is_type:
|
|
continue
|
|
if typename and typename != osinfo.typename:
|
|
continue
|
|
if filtervars:
|
|
filtervars = [lookup_os(x).name for x in filtervars]
|
|
if osinfo.name not in filtervars:
|
|
continue
|
|
if only_supported and not osinfo.supported:
|
|
continue
|
|
sortmap[key] = osinfo
|
|
return _sort(sortmap, **kwargs)
|
|
|
|
|
|
def lookup_osdict_key(variant, key, default):
|
|
_load_os_data()
|
|
val = _SENTINEL
|
|
if variant is not None:
|
|
os = lookup_os(variant)
|
|
if not hasattr(os, key):
|
|
raise ValueError("Unknown osdict property '%s'" % key)
|
|
val = getattr(os, key)
|
|
if isfunction(val):
|
|
val = val()
|
|
if val == _SENTINEL:
|
|
val = default
|
|
return val
|
|
|
|
|
|
def get_recommended_resources(variant, arch):
|
|
_load_os_data()
|
|
v = _allvariants.get(variant)
|
|
if v is None:
|
|
return None
|
|
|
|
return v.get_recommended_resources(arch)
|
|
|
|
|
|
def lookup_os_by_media(location):
|
|
loader = _get_os_loader()
|
|
media = libosinfo.Media.create_from_location(location, None)
|
|
ret = loader.get_db().guess_os_from_media(media)
|
|
if ret and len(ret) > 0 and ret[0]:
|
|
return ret[0].get_short_id()
|
|
return None
|