Radostin Stoyanov b93cc3bbc9 pycodestyle: Do not use bare 'except:'
A bare 'except:' catches all exceptions [1], including SystemExit,
KeyboardInterrupt, and GeneratorExit (which is not an error and should
not normally be caught by user code). In situations where you need to
catch all “normal” errors, you can catch the base class for all normal
exceptions, Exception [2].

[1] https://docs.python.org/2/howto/doanddont.html#except
[2] https://docs.python.org/2/library/exceptions.html#Exception
2017-08-02 13:57:43 -04:00

569 lines
17 KiB
Python

#
# List of OS Specific data
#
# Copyright 2006-2008, 2013-2014 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.
import datetime
import logging
import re
import gi
gi.require_version('Libosinfo', '1.0')
from gi.repository import Libosinfo as libosinfo
###################
# Sorting helpers #
###################
def _remove_older_point_releases(distro_list):
ret = distro_list[:]
def _get_minor_version(osobj):
return int(osobj.name.rsplit(".", 1)[-1])
def _find_latest(prefix):
"""
Given a prefix like 'rhel4', find the latest 'rhel4.X',
and remove the rest from the os list
"""
latest_os = None
first_id = None
for osobj in ret[:]:
if not re.match("%s\.\d+" % prefix, osobj.name):
continue
if first_id is None:
first_id = ret.index(osobj)
ret.remove(osobj)
if (latest_os and
_get_minor_version(latest_os) > _get_minor_version(osobj)):
continue
latest_os = osobj
if latest_os:
ret.insert(first_id, latest_os)
_find_latest("rhel4")
_find_latest("rhel5")
_find_latest("rhel6")
_find_latest("rhel7")
_find_latest("freebsd9")
_find_latest("freebsd10")
_find_latest("freebsd11")
_find_latest("centos6")
_find_latest("centos7")
return ret
def _sort(tosort, sortpref=None, limit_point_releases=False):
sortby_mappings = {}
distro_mappings = {}
retlist = []
sortpref = sortpref or []
for key, osinfo in tosort.items():
# Libosinfo has some duplicate version numbers here, so append .1
# if there's a collision
sortby = osinfo.sortby
while sortby_mappings.get(sortby):
sortby = sortby + ".1"
sortby_mappings[sortby] = key
# Group distros by their urldistro value first, so debian is clumped
# together, and fedora, etc.
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()
# Move the sortpref values to the front of the list
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)
# Build the final list of sorted os objects
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])
# Filter out older point releases
if limit_point_releases:
retlist = _remove_older_point_releases(retlist)
return retlist
class _OSDB(object):
"""
Entry point for the public API
"""
def __init__(self):
self.__os_loader = None
self.__all_variants = None
# This is only for back compatibility with pre-libosinfo support.
# This should never change.
_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",
"virtio26": "fedora10",
"vista" : "winvista",
"winxp64" : "winxp",
# Old --os-type values
"linux" : "generic",
"windows" : "winxp",
"solaris" : "solaris10",
"unix": "freebsd9.0",
"other": "generic",
}
#################
# Internal APIs #
#################
def _make_default_variants(self):
ret = {}
# Generic variant
v = _OsVariant(None)
ret[v.name] = v
return ret
@property
def _os_loader(self):
if not self.__os_loader:
loader = libosinfo.Loader()
loader.process_default_path()
self.__os_loader = loader
return self.__os_loader
@property
def _all_variants(self):
if not self.__all_variants:
loader = self._os_loader
allvariants = self._make_default_variants()
db = loader.get_db()
oslist = db.get_os_list()
for os in range(oslist.get_length()):
osi = _OsVariant(oslist.get_nth(os))
allvariants[osi.name] = osi
self.__all_variants = allvariants
return self.__all_variants
###############
# Public APIs #
###############
def lookup_os(self, key):
key = self._aliases.get(key) or key
return self._all_variants.get(key)
def lookup_os_by_media(self, location):
media = libosinfo.Media.create_from_location(location, None)
ret = self._os_loader.get_db().guess_os_from_media(media)
if not (ret and len(ret) > 0 and ret[0]):
return None
osname = ret[0].get_short_id()
if osname == "fedora-unknown":
osname = self.latest_fedora_version()
logging.debug("Detected location=%s as os=fedora-unknown. "
"Converting that to the latest fedora OS version=%s",
location, osname)
return osname
def list_types(self):
approved_types = ["linux", "windows", "bsd", "macos",
"solaris", "other", "generic"]
return approved_types
def list_os(self, typename=None, only_supported=False, sortpref=None):
"""
List all OSes in the DB
:param typename: Only list OSes of this type
:param only_supported: Only list OSses where self.supported == True
:param sortpref: Sort these OSes at the front of the list
"""
sortmap = {}
for name, osobj in self._all_variants.items():
if typename and typename != osobj.get_typename():
continue
if only_supported and not osobj.get_supported():
continue
sortmap[name] = osobj
return _sort(sortmap, sortpref=sortpref,
limit_point_releases=only_supported)
def latest_fedora_version(self):
for osinfo in self.list_os():
if (osinfo.name.startswith("fedora") and
"unknown" not in osinfo.name):
# First fedora* occurrence should be the newest
return osinfo.name
#####################
# OsVariant classes #
#####################
class _OsVariant(object):
def __init__(self, o):
self._os = o
self._family = self._os and self._os.get_family() or None
self.name = self._os and self._os.get_short_id() or "generic"
self.label = self._os and self._os.get_name() or "Generic"
self.codename = self._os and self._os.get_codename() or ""
self.distro = self._os and self._os.get_distro() or ""
self.sortby = self._get_sortby()
self.urldistro = self._get_urldistro()
self._supported = None
########################
# Internal helper APIs #
########################
def _is_related_to(self, related_os_list, os=None,
check_derives=True, check_upgrades=True, check_clones=True):
os = os or self._os
if not os:
return False
if os.get_short_id() in related_os_list:
return True
check_list = []
def _extend(newl):
for obj in newl:
if obj not in check_list:
check_list.append(obj)
if check_derives:
_extend(os.get_related(
libosinfo.ProductRelationship.DERIVES_FROM).get_elements())
if check_clones:
_extend(os.get_related(
libosinfo.ProductRelationship.CLONES).get_elements())
if check_upgrades:
_extend(os.get_related(
libosinfo.ProductRelationship.UPGRADES).get_elements())
for checkobj in check_list:
if (checkobj.get_short_id() in related_os_list or
self._is_related_to(related_os_list, os=checkobj,
check_upgrades=check_upgrades,
check_derives=check_derives,
check_clones=check_clones)):
return True
return False
###############
# Cached APIs #
###############
def _get_sortby(self):
if not self._os:
return "1"
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 Exception:
pass
return "%s-%s" % (self.distro, version)
def _get_supported(self):
if not self._os:
return True
eol_date = self._os.get_eol_date_string()
if eol_date:
return (datetime.datetime.strptime(eol_date, "%Y-%m-%d") >
datetime.datetime.now())
if self.name == "fedora-unknown":
return False
# 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 self._is_related_to(["fedora24", "rhel7.0", "debian6",
"ubuntu13.04", "win8", "win2k12", "mageia5", "centos7.0"],
check_clones=False, check_derives=False):
return True
return False
def _get_urldistro(self):
if not self._os:
return None
urldistro = self.distro
remap = {
"opensuse" : "suse",
"sles" : "suse",
"mes" : "mandriva"
}
if remap.get(urldistro):
return remap[urldistro]
return urldistro
###############
# Public APIs #
###############
def get_supported(self):
if self._supported is None:
self._supported = self._get_supported()
return self._supported
def get_typename(self):
"""
Streamline the family name for use in the virt-manager UI
"""
if not self._os:
return "generic"
if self._family in ['linux']:
return "linux"
if self._family in ['win9x', 'winnt', 'win16']:
return "windows"
if self._family in ['solaris']:
return "solaris"
if self._family in ['openbsd', 'freebsd', 'netbsd']:
return "bsd"
if self._family in ['darwin']:
return "macos"
return "other"
def is_windows(self):
return self.get_typename() == "windows"
def need_old_xen_disable_acpi(self):
return self._is_related_to(["winxp", "win2k"], check_upgrades=False)
def broken_x2apic(self):
# x2apic breaks networking in solaris10
# https://bugs.launchpad.net/bugs/1395217
return self.name in ('solaris10', 'solaris11')
def get_clock(self):
if self.is_windows() or self._family in ['solaris']:
return "localtime"
return "utc"
def supports_virtiommio(self):
return self._is_related_to(["fedora19"])
def default_netmodel(self):
"""
Default non-virtio net-model, since we check for that separately
"""
if not self._os:
return None
fltr = libosinfo.Filter()
fltr.add_constraint("class", "net")
devs = self._os.get_all_devices(fltr)
for idx in range(devs.get_length()):
devname = devs.get_nth(idx).get_name()
if devname in ["pcnet", "ne2k_pci", "rtl8139", "e1000"]:
return devname
return None
def supports_usbtablet(self):
if not self._os:
return False
fltr = libosinfo.Filter()
fltr.add_constraint("class", "input")
fltr.add_constraint("name", "tablet")
devs = self._os.get_all_devices(fltr)
for idx in range(devs.get_length()):
if devs.get_nth(idx).get_bus_type() == "usb":
return True
return False
def supports_virtiodisk(self):
if self._os:
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 False
def supports_virtionet(self):
if self._os:
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 False
def supports_virtiorng(self):
if self._os:
fltr = libosinfo.Filter()
fltr.add_constraint("class", "rng")
devs = self._os.get_all_devices(fltr)
for dev in range(devs.get_length()):
d = devs.get_nth(dev)
if d.get_name() == "virtio-rng":
return True
return False
def supports_qemu_ga(self):
return self._is_related_to(["debian8", "fedora18", "rhel6.0", "sles11sp4"])
def default_videomodel(self, guest):
if guest.os.is_pseries():
return "vga"
if guest.has_spice() and guest.os.is_x86():
if guest.has_gl():
return "virtio"
else:
return "qxl"
if self.is_windows():
return "vga"
return None
def get_recommended_resources(self, guest):
ret = {}
if not self._os:
return ret
def read_resource(resources, minimum, arch):
# If we are reading the "minimum" block, allocate more
# resources.
ram_scale = minimum and 2 or 1
n_cpus_scale = minimum and 2 or 1
storage_scale = minimum and 2 or 1
for i in range(resources.get_length()):
r = resources.get_nth(i)
if r.get_architecture() == arch:
ret["ram"] = r.get_ram() * ram_scale
ret["cpu"] = r.get_cpu()
ret["n-cpus"] = r.get_n_cpus() * n_cpus_scale
ret["storage"] = r.get_storage() * storage_scale
break
# libosinfo may miss the recommended resources block for some OS,
# in this case read first the minimum resources (if present)
# and use them.
read_resource(self._os.get_minimum_resources(), True, "all")
read_resource(self._os.get_minimum_resources(), True, guest.os.arch)
read_resource(self._os.get_recommended_resources(), False, "all")
read_resource(self._os.get_recommended_resources(),
False, guest.os.arch)
# QEMU TCG doesn't gain anything by having extra VCPUs
if guest.type == "qemu":
ret["n-cpus"] = 1
return ret
OSDB = _OSDB()