virt: introduce libosinfo library to set hardware policy

Introducing a new library to retrieve information from libosinfo database.

Libosinfo database provides information about an optimal hardware configuration
for the guest instances, based on their Operating Systems.
Using this library it will be easier for the end user to boot a guest instance
with an optimal configuration by just providing the guest's OS name.

The following are the acceptable attributes:

 * 'short-id' - the short name of the OS
    eg fedora21, winxp

 * 'id' - the unique URI identifier of the OS
    eg http://fedoraproject.org/fedora/21, http://microsoft.com/win/xp

DocImpact
Partially Implements blueprint libvirt-hardware-policy-from-libosinfo

Change-Id: I35564d6280883e912030236fc23f233d19f56d38
This commit is contained in:
Vladik Romanovsky 2015-01-22 16:06:16 -05:00 committed by Vladik Romanovsky
parent 806113e4f4
commit e8c3196b7e
3 changed files with 171 additions and 0 deletions

View File

@ -2054,3 +2054,8 @@ class RealtimeMaskNotFoundOrInvalid(Invalid):
msg_fmt = _("Realtime policy needs vCPU(s) mask configured with at least "
"1 RT vCPU and 1 ordinary vCPU. See hw:cpu_realtime_mask "
"or hw_cpu_realtime_mask")
class OsInfoNotFound(NotFound):
msg_fmt = _("No configuration information found for operating system "
"%(os_name)s")

View File

@ -0,0 +1,53 @@
# 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.
import mock
from nova import exception
from nova import test
from nova.virt import osinfo
class LibvirtOsInfoTest(test.NoDBTestCase):
def setUp(self):
super(LibvirtOsInfoTest, self).setUp()
osinfo.libosinfo = mock.Mock()
def test_get_os(self):
filter_mock = mock.Mock()
osinfo.libosinfo = mock.Mock()
osinfo.libosinfo.Filter.new.return_value = filter_mock
osinfo_mock = mock.Mock()
filtered_list = osinfo_mock.new_filtered
filtered_list.return_value.get_length.return_value = 1
os_info_db = osinfo._OsInfoDatabase.get_instance()
os_info_db.oslist = osinfo_mock
os_info_db.get_os('test33')
filter_mock.add_constraint.assert_called_once_with('short-id',
'test33')
self.assertTrue(filtered_list.return_value.get_nth.called)
def test_get_os_fails(self):
filter_mock = mock.Mock()
osinfo.libosinfo = mock.Mock()
osinfo.libosinfo.Filter.return_value.new.return_value = filter_mock
osinfo_mock = mock.Mock()
filtered = osinfo_mock.new_filtered.return_value
filtered.get_length.return_value = 0
os_info_db = osinfo._OsInfoDatabase.get_instance()
os_info_db.oslist = osinfo_mock
self.assertRaises(exception.OsInfoNotFound,
os_info_db.get_os,
'test33')

113
nova/virt/osinfo.py Normal file
View File

@ -0,0 +1,113 @@
# 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.i18n import _, _LE
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
if libosinfo is None:
try:
libosinfo = importutils.import_module(
'gi.repository.Libosinfo')
except ImportError as exp:
raise exception.NovaException(
_("Cannot load Libosinfo: (%s)") % exp)
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 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)
filttered = self.oslist.new_filtered(fltr)
list_len = filttered.get_length()
if not list_len:
raise exception.OsInfoNotFound(os_name=os_name)
return filttered.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):
try:
return _OsInfoDatabase.get_instance().get_os(os_name)
except exception.NovaException as e:
LOG.error(_LE("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():
return devs.get_nth(0).get_name()
@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():
return devs.get_nth(0).get_name()