# Copyright 2015 Red Hat, Inc # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from oslo_log import log as logging from oslo_utils import importutils from nova import exception from nova.objects import fields libosinfo = None LOG = logging.getLogger(__name__) # TODO(vladikr) The current implementation will serve only as a temporary # solution, due to it's dependency on the libosinfo gobject library. # In the future it will be replaced by a pure python library or by a direct # parsing of the libosinfo XML files. However, it will be possible only when # libosinfo project will declare the XML structure to be a stable ABI. class _OsInfoDatabase(object): _instance = None def __init__(self): global libosinfo try: if libosinfo is None: libosinfo = importutils.import_module( 'gi.repository.Libosinfo') except ImportError as exp: LOG.info("Cannot load Libosinfo: (%s)", exp) else: self.loader = libosinfo.Loader() self.loader.process_default_path() self.db = self.loader.get_db() self.oslist = self.db.get_os_list() @classmethod def get_instance(cls): """Get libosinfo connection """ if cls._instance is None: cls._instance = _OsInfoDatabase() return cls._instance def get_os(self, os_name): """Retrieve OS object based on id, unique URI identifier of the OS :param os_name: id - the unique operating systemidentifier e.g. http://fedoraproject.org/fedora/21, http://microsoft.com/win/xp, or a short-id - the short name of the OS e.g. fedora21, winxp :returns: The operation system object Libosinfo.Os :raise exception.OsInfoNotFound: If os hasn't been found """ if libosinfo is None: return if not os_name: raise exception.OsInfoNotFound(os_name='Empty') fltr = libosinfo.Filter.new() flt_field = 'id' if os_name.startswith('http') else 'short-id' fltr.add_constraint(flt_field, os_name) filtered = self.oslist.new_filtered(fltr) list_len = filtered.get_length() if not list_len: raise exception.OsInfoNotFound(os_name=os_name) return filtered.get_nth(0) class OsInfo(object): """OS Information Structure """ def __init__(self, os_name): self._os_obj = self._get_os_obj(os_name) def _get_os_obj(self, os_name): if os_name is not None: try: return _OsInfoDatabase.get_instance().get_os(os_name) except exception.NovaException as e: LOG.warning("Cannot find OS information - Reason: (%s)", e) @property def network_model(self): if self._os_obj is not None: fltr = libosinfo.Filter() fltr.add_constraint("class", "net") devs = self._os_obj.get_all_devices(fltr) if devs.get_length(): net_model = devs.get_nth(0).get_name() # convert to valid libvirt values if net_model in ['virtio-net', 'virtio1.0-net']: return 'virtio' # ignore any invalid ones if net_model in fields.VIFModel.ALL: return net_model @property def disk_model(self): if self._os_obj is not None: fltr = libosinfo.Filter() fltr.add_constraint("class", "block") devs = self._os_obj.get_all_devices(fltr) if devs.get_length(): disk_model = devs.get_nth(0).get_name() # convert to valid libvirt values if disk_model in ['virtio-block', 'virtio1.0-block']: return 'virtio' # ignore any invalid ones if disk_model in fields.DiskBus.ALL: return disk_model class HardwareProperties(object): def __init__(self, image_meta): """:param image_meta: ImageMeta object """ self.img_props = image_meta.properties os_key = self.img_props.get('os_distro') self.os_info_obj = OsInfo(os_key) @property def network_model(self): return self.img_props.get('hw_vif_model', self.os_info_obj.network_model) @property def disk_model(self): return self.img_props.get('hw_disk_bus', self.os_info_obj.disk_model)