From bd9ab2d5b55d278e7a5cabb42e8dc7287071855e Mon Sep 17 00:00:00 2001 From: Cole Robinson Date: Sat, 4 Apr 2015 12:04:11 -0400 Subject: [PATCH] osdict: Add toplevel OSDB as API entry point Makes code more readable, and lazy loading simpler. --- tests/misc.py | 8 +- virtManager/create.py | 19 ++- virtinst/__init__.py | 1 + virtinst/distroinstaller.py | 4 +- virtinst/guest.py | 8 +- virtinst/osdict.py | 311 ++++++++++++++++++------------------ virtinst/urlfetcher.py | 12 +- 7 files changed, 187 insertions(+), 176 deletions(-) diff --git a/tests/misc.py b/tests/misc.py index 3bfbb769..a7a6b2c6 100644 --- a/tests/misc.py +++ b/tests/misc.py @@ -124,13 +124,13 @@ class TestMisc(unittest.TestCase): "\n".join([("%s version=%s" % tup) for tup in failures])) def test_libosinfo_aliases_ro(self): - from virtinst import osdict - aliases = getattr(osdict, "_aliases") + from virtinst import OSDB + aliases = getattr(OSDB, "_aliases") if len(aliases) != 40: - raise AssertionError(_("osdict._aliases changed size. It " + raise AssertionError(_("OSDB._aliases changed size. It " "should never be extended, since it is only for back " - "compat with pre-libosinfo osdict.")) + "compat with pre-libosinfo osdict.py")) class TestURI(unittest.TestCase): diff --git a/virtManager/create.py b/virtManager/create.py index d712d3bc..2d144488 100644 --- a/virtManager/create.py +++ b/virtManager/create.py @@ -813,7 +813,7 @@ class vmmCreate(vmmGObjectUI): STABLE_OS_SUPPORT or None) - types = virtinst.osdict.list_os(list_types=True) + types = virtinst.OSDB.list_os(list_types=True) if not filtervars: # Kind of a hack, just show linux + windows by default since # that's all 98% of people care about @@ -821,9 +821,9 @@ class vmmCreate(vmmGObjectUI): else: supportl = [] for t in types: - l = virtinst.osdict.list_os(typename=t.name, - only_supported=True, - filtervars=filtervars) + l = virtinst.OSDB.list_os(typename=t.name, + only_supported=True, + filtervars=filtervars) if l: supportl.append(t.name) @@ -852,9 +852,9 @@ class vmmCreate(vmmGObjectUI): None) preferred = self.config.preferred_distros - variants = virtinst.osdict.list_os(typename=_type, + variants = virtinst.OSDB.list_os(typename=_type, sortpref=preferred) - supportl = virtinst.osdict.list_os(typename=_type, + supportl = virtinst.OSDB.list_os(typename=_type, sortpref=preferred, only_supported=True, filtervars=filtervars) @@ -1653,7 +1653,10 @@ class vmmCreate(vmmGObjectUI): self.addstorage.check_path_search( self, self.conn, path) - res = virtinst.osdict.get_recommended_resources(variant, self.guest) + res = None + osobj = virtinst.OSDB.lookup_os(variant) + if osobj: + res = osobj.get_recommended_resources(self.guest) # Change the default values suggested to the user. ram_size = DEFAULT_MEM @@ -2014,7 +2017,7 @@ class vmmCreate(vmmGObjectUI): distro_type = None distro_var = None if variant: - osclass = virtinst.osdict.lookup_os(variant) + osclass = virtinst.OSDB.lookup_os(variant) distro_type = osclass.typename distro_var = osclass.name diff --git a/virtinst/__init__.py b/virtinst/__init__.py index 0801cbfc..5af60fec 100644 --- a/virtinst/__init__.py +++ b/virtinst/__init__.py @@ -37,6 +37,7 @@ stable_defaults = _cliconfig.stable_defaults from . import util from virtinst import support from virtinst.uri import URISplit +from virtinst.osdict import OSDB from virtinst.osxml import OSXML from virtinst.domainfeatures import DomainFeatures diff --git a/virtinst/distroinstaller.py b/virtinst/distroinstaller.py index 24989e66..b8372806 100644 --- a/virtinst/distroinstaller.py +++ b/virtinst/distroinstaller.py @@ -25,11 +25,11 @@ import tempfile import urlgrabber -from . import osdict from . import urlfetcher from . import util from .devicedisk import VirtualDisk from .installer import Installer +from .osdict import OSDB from .storage import StoragePool, StorageVolume @@ -502,7 +502,7 @@ class DistroInstaller(Installer): logging.debug("Can't detect distro for media on " "remote connection.") else: - distro = osdict.lookup_os_by_media(self.location) + distro = OSDB.lookup_os_by_media(self.location) except: logging.debug("Error attempting to detect distro.", exc_info=True) diff --git a/virtinst/guest.py b/virtinst/guest.py index d0efe5b9..a736bb4c 100644 --- a/virtinst/guest.py +++ b/virtinst/guest.py @@ -26,9 +26,9 @@ import libvirt from virtcli import cliconfig -from . import osdict from . import util from . import support +from .osdict import OSDB from .clock import Clock from .cpu import CPU from .device import VirtualDevice @@ -211,9 +211,9 @@ class Guest(XMLBuilder): ############################### def _set_os_object(self, variant): - obj = osdict.lookup_os(variant) + obj = OSDB.lookup_os(variant) if not obj: - obj = osdict.lookup_os("generic") + obj = OSDB.lookup_os("generic") self.__os_object = obj def _get_os_object(self): if not self.__os_object: @@ -226,7 +226,7 @@ class Guest(XMLBuilder): def _set_os_variant(self, val): if val: val = val.lower() - if osdict.lookup_os(val) is None: + if OSDB.lookup_os(val) is None: raise ValueError( _("Distro '%s' does not exist in our dictionary") % val) diff --git a/virtinst/osdict.py b/virtinst/osdict.py index 38c3496c..d1bc36f6 100644 --- a/virtinst/osdict.py +++ b/virtinst/osdict.py @@ -25,53 +25,9 @@ import re from gi.repository import Libosinfo as libosinfo -# 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", - "vista" : "winvista", - "winxp64" : "winxp", - - "linux" : "generic", - "windows" : "winxp", - "solaris" : "solaris10", - "virtio26": "fedora10", -} -_allvariants = {} - +################### +# Sorting helpers # +################### def _remove_older_point_releases(distro_list): ret = distro_list[:] @@ -161,18 +117,154 @@ def _sort(tosort, sortpref=None, limit_point_releases=False): return retlist -class _OsVariantType(object): +class _OSDB(object): + """ + Entry point for the public API + """ + def __init__(self): + self.__os_loader = None + self.__all_variants = None - def __init__(self, name, label, urldistro, sortby): - self.name = name - self.label = label - self.urldistro = urldistro - self.sortby = sortby + # 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", + "vista" : "winvista", + "winxp64" : "winxp", - def is_type(self): - return self.__class__ == _OsVariantType + "linux" : "generic", + "windows" : "winxp", + "solaris" : "solaris10", + "virtio26": "fedora10", + } + ################# + # Internal APIs # + ################# + + def _make_default_variants(self): + ret = {} + + # Back compat 'types' + for name, label in [ + ("linux", "Linux"), + ("windows", "Windows"), + ("solaris", "Solaris"), + ("unix", "UNIX"), + ("other", "Other")]: + ret[name] = _OsVariantType(name, label, None, None) + + # 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 + ret = self._all_variants.get(key) + if ret is None or ret.is_type(): + return None + return ret + + 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 ret and len(ret) > 0 and ret[0]: + return ret[0].get_short_id() + return None + + def list_os(self, list_types=False, typename=None, + filtervars=None, only_supported=False, + **kwargs): + sortmap = {} + filtervars = filtervars or [] + + for key, osinfo in self._all_variants.items(): + is_type = osinfo.is_type() + if list_types and not is_type: + continue + if not list_types and is_type: + continue + if typename and typename != osinfo.typename: + continue + if filtervars: + filtervars = [self.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 + + kwargs["limit_point_releases"] = only_supported + return _sort(sortmap, **kwargs) + + +##################### +# OsVariant classes # +##################### + def _is_os_related_to(o, related_os_list): if o.get_short_id() in related_os_list: return True @@ -186,6 +278,17 @@ def _is_os_related_to(o, related_os_list): return False +class _OsVariantType(object): + def __init__(self, name, label, urldistro, sortby): + self.name = name + self.label = label + self.urldistro = urldistro + self.sortby = sortby + + def is_type(self): + return self.__class__ == _OsVariantType + + class _OsVariant(_OsVariantType): def __init__(self, o): self._os = o @@ -486,100 +589,4 @@ class _OsVariant(_OsVariantType): return ret - -def _add_type(name, label, urldistro=None, sortby=None): - t = _OsVariantType(name, label, urldistro, sortby) - _allvariants[name] = t - - -def _add_generic_variant(): - v = _OsVariant(None) - _allvariants[v.name] = v - - -_add_type("linux", "Linux") -_add_type("windows", "Windows") -_add_type("solaris", "Solaris") -_add_type("unix", "UNIX") -_add_type("other", "Other") -_add_generic_variant() - - -_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 = _OsVariant(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 or ret.is_type(): - return None - 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(): - is_type = osinfo.is_type() - if list_types and not is_type: - continue - if not list_types and 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 - - kwargs["limit_point_releases"] = only_supported - return _sort(sortmap, **kwargs) - - -def get_recommended_resources(variant, guest): - _load_os_data() - v = _allvariants.get(variant) - if v is None: - return None - - return v.get_recommended_resources(guest) - - -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 +OSDB = _OSDB() diff --git a/virtinst/urlfetcher.py b/virtinst/urlfetcher.py index 4e341e70..38409e34 100644 --- a/virtinst/urlfetcher.py +++ b/virtinst/urlfetcher.py @@ -32,7 +32,7 @@ import urlparse import urlgrabber.grabber as grabber -from . import osdict +from .osdict import OSDB ######################################################################### @@ -326,7 +326,7 @@ def getDistroStore(guest, fetcher): urldistro = None if guest.os_variant: - urldistro = osdict.lookup_os(guest.os_variant).urldistro + urldistro = OSDB.lookup_os(guest.os_variant).urldistro dist = _distroFromTreeinfo(fetcher, arch, _type) if dist: @@ -447,7 +447,7 @@ class Distro(object): self.name)) def _check_osvariant_valid(self, os_variant): - return osdict.lookup_os(os_variant) is not None + return OSDB.lookup_os(os_variant) is not None def get_osdict_info(self): """ @@ -667,7 +667,7 @@ class FedoraDistro(RedHatDistro): Search osdict list, find newest fedora version listed """ ret = None - for osinfo in osdict.list_os(typename="linux"): + for osinfo in OSDB.list_os(typename="linux"): if osinfo.name.startswith("fedora") and "unknown" not in osinfo.name: # First fedora* occurrence should be the newest ret = osinfo.name @@ -866,7 +866,7 @@ class SuseDistro(Distro): def _detect_osdict_from_url(self): root = "opensuse" - oses = [n for n in osdict.list_os() if n.name.startswith(root)] + oses = [n for n in OSDB.list_os() if n.name.startswith(root)] for osobj in oses: codename = osobj.name[len(root):] @@ -941,7 +941,7 @@ class DebianDistro(Distro): def _detect_osdict_from_url(self): root = self.name.lower() - oses = [n for n in osdict.list_os() if n.name.startswith(root)] + oses = [n for n in OSDB.list_os() if n.name.startswith(root)] if self._url_prefix == "daily": return oses[0].name