diff --git a/os_vif/__init__.py b/os_vif/__init__.py index 2dac7383..fdcc5e3e 100644 --- a/os_vif/__init__.py +++ b/os_vif/__init__.py @@ -109,3 +109,23 @@ def unplug(vif, instance_info): LOG.error(_LE("Failed to unplug vif %(vif)s. Got error: %(err)s"), vif=vif, err=err) raise os_vif.exception.UnplugException(vif=vif, err=err) + + +def host_info(): + """ + Get information about the host platform configuration to be + provided to the network manager. This will include information + about what plugins are installed in the host + + :returns: a os_vif.host_info.HostInfo class instance + """ + + if _EXT_MANAGER is None: + raise os_vif.exception.LibraryNotInitialized() + + plugins = [ + _EXT_MANAGER[name].obj.describe() + for name in _EXT_MANAGER.names() + ] + + return os_vif.objects.host_info.HostInfo(plugin_info=plugins) diff --git a/os_vif/exception.py b/os_vif/exception.py index 6f648dc2..c9d085d3 100644 --- a/os_vif/exception.py +++ b/os_vif/exception.py @@ -51,6 +51,15 @@ class NoMatchingPlugin(ExceptionBase): msg_fmt = _("No VIF plugin was found with the name %(plugin_name)s") +class NoMatchingVIFClass(ExceptionBase): + msg_fmt = _("No VIF class was found with the name %(vif_name)s") + + +class NoSupportedVIFVersion(ExceptionBase): + msg_fmt = _("VIF class %(vif_name)s versions %(got_versions)s " + "do not satisfy min=%(min_version)s max=%(max_version)s") + + class PlugException(ExceptionBase): msg_fmt = _("Failed to plug VIF %(vif)s. Got error: %(err)s") diff --git a/os_vif/objects/__init__.py b/os_vif/objects/__init__.py index 70eb4c3c..63293466 100644 --- a/os_vif/objects/__init__.py +++ b/os_vif/objects/__init__.py @@ -13,6 +13,7 @@ def register_all(): __import__('os_vif.objects.fixed_ip') + __import__('os_vif.objects.host_info') __import__('os_vif.objects.instance_info') __import__('os_vif.objects.network') __import__('os_vif.objects.route') diff --git a/os_vif/objects/host_info.py b/os_vif/objects/host_info.py new file mode 100644 index 00000000..50a6a8a5 --- /dev/null +++ b/os_vif/objects/host_info.py @@ -0,0 +1,119 @@ +# 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_versionedobjects import base +from oslo_versionedobjects import fields + +from os_vif import exception +from os_vif.objects import base as osv_base + + +@base.VersionedObjectRegistry.register +class HostVIFInfo(osv_base.VersionedObject, base.ComparableVersionedObject): + """ + Class describing a VIF class and its supported versions + """ + + VERSION = "1.0" + + fields = { + # object name of the subclass of os_vif.objects.vif.VIF + "vif_object_name": fields.StringField(), + + # String representing the earliest version of @name + # that the plugin understands + "min_version": fields.StringField(), + + # String representing the latest version of @name + # that the plugin understands + "max_version": fields.StringField(), + } + + def get_common_version(self): + def _vers_tuple(ver): + return tuple([int(x) for x in ver.split(".")]) + + reg = base.VersionedObjectRegistry.obj_classes() + + if self.name not in reg: + raise exception.NoMatchingVIFClass(vif_name=self.name) + + gotvers = [] + for regobj in reg[self.name]: + gotvers.append(regobj.VERSION) + got = _vers_tuple(regobj.VERSION) + minwant = _vers_tuple(self.min_version) + maxwant = _vers_tuple(self.max_version) + + if got >= minwant and got <= maxwant: + return regobj.VERSION + + raise exception.NoSupportedVIFVersion(vif_name=self.name, + got_versions=",".join(gotvers), + min_version=self.min_version, + max_version=self.max_version) + + +@base.VersionedObjectRegistry.register +class HostPluginInfo(osv_base.VersionedObject, + base.ComparableVersionedObject): + """ + Class describing a plugin and its supported VIF classes + """ + + VERSION = "1.0" + + fields = { + # name of the plugin + "plugin_name": fields.StringField(), + + # list of HostVIFInfo instances supported by the plugin + "vif_info": fields.ListOfObjectsField("HostVIFInfo"), + } + + def has_vif(self, name): + for vif in self.vif_info: + if vif.name == name: + return True + return False + + def get_vif(self, name): + for vif in self.vif_info: + if vif.name == name: + return vif + + raise exception.NoMatchingVIFClass(vif_name=name) + + +@base.VersionedObjectRegistry.register +class HostInfo(osv_base.VersionedObject, base.ComparableVersionedObject): + """ + Class describing a host host and its supported plugin classes + """ + + fields = { + # list of HostPluginInfo instances supported by the host host + "plugin_info": fields.ListOfObjectsField("HostPluginInfo"), + } + + def has_plugin(self, name): + for plugin in self.plugin_info: + if name == plugin.name: + return True + return False + + def get_plugin(self, name): + for plugin in self.plugin_info: + if name == plugin.name: + return plugin + + raise exception.NoMatchingPlugin(plugin_name=name) diff --git a/os_vif/plugin.py b/os_vif/plugin.py index b4346301..0c988832 100644 --- a/os_vif/plugin.py +++ b/os_vif/plugin.py @@ -18,41 +18,6 @@ import six CONF = cfg.CONF -class PluginVIFInfo(object): - """ - Class describing the plugin and the versions of VIF object it understands. - """ - - def __init__(self, vif_class, min_version, max_version): - """ - Constructs the PluginInfo object. - - :param vif_class: subclass of os_vif.objects.vif.VIF that is supported - :param min_version: String representing the earliest version of - @vif_class that the plugin understands. - :param_max_version: String representing the latest version of - @vif_class that the plugin understands. - """ - self.vif_class = vif_class - self.min_version = min_version - self.max_version = max_version - - -class PluginInfo(object): - """ - Class describing the plugin and the versions of VIF object it understands. - """ - - def __init__(self, vif_info): - """ - Constructs the PluginInfo object. - - :param vif_info: list of PluginVIFInfo instances supported by the - plugin - """ - self.vif_info = vif_info - - @six.add_metaclass(abc.ABCMeta) class PluginBase(object): """Base class for all VIF plugins.""" @@ -75,7 +40,7 @@ class PluginBase(object): Return an object that describes the plugin's supported vif types and the earliest/latest known VIF object versions. - :returns: A `os_vif.plugin.PluginInfo` instance + :returns: A `os_vif.host_info.HostPluginInfo` instance """ @abc.abstractmethod diff --git a/os_vif/tests/test_host_info.py b/os_vif/tests/test_host_info.py new file mode 100644 index 00000000..e05ec7bc --- /dev/null +++ b/os_vif/tests/test_host_info.py @@ -0,0 +1,51 @@ +# 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 os_vif import objects +from os_vif.tests import base + + +class TestHostInfo(base.TestCase): + + def test_serialization(self): + ciorig = objects.host_info.HostInfo( + plugin_info=[ + objects.host_info.HostPluginInfo( + plugin_name="linux_brige", + vif_info=[ + objects.host_info.HostVIFInfo( + vif_object_name="VIFBridge", + min_version="1.0", + max_version="3.0" + ), + ]), + objects.host_info.HostPluginInfo( + plugin_name="ovs", + vif_info=[ + objects.host_info.HostVIFInfo( + vif_object_name="VIFBridge", + min_version="2.0", + max_version="7.0" + ), + objects.host_info.HostVIFInfo( + vif_object_name="VIFOpenVSwitch", + min_version="1.0", + max_version="2.0" + ), + ]) + ]) + + json = ciorig.obj_to_primitive() + + cinew = objects.host_info.HostInfo.obj_from_primitive(json) + + self.assertEqual(ciorig, cinew) diff --git a/os_vif/tests/test_vif.py b/os_vif/tests/test_vif.py index 0ca7acd2..29e34d58 100644 --- a/os_vif/tests/test_vif.py +++ b/os_vif/tests/test_vif.py @@ -95,6 +95,9 @@ class TestVIFS(base.TestCase): port_profile=prof) object_data = { + 'HostInfo': '1.0-4dba5ce236ea2dc559de8764995dd247', + 'HostPluginInfo': '1.0-5204e579864981c9891ecb5d1c9329f2', + 'HostVIFInfo': '1.0-9866583de62ae23cc868ce45f402da6d', 'FixedIP': '1.0-d1a0ec7e7b6ce021a784c54d44cce009', 'FixedIPList': '1.0-15ecf022a68ddbb8c2a6739cfc9f8f5e', 'InstanceInfo': '1.0-84104d3435046b1a282ac8265ec2a976', diff --git a/vif_plug_linux_bridge/linux_bridge.py b/vif_plug_linux_bridge/linux_bridge.py index 2c77ef91..05f02ad6 100644 --- a/vif_plug_linux_bridge/linux_bridge.py +++ b/vif_plug_linux_bridge/linux_bridge.py @@ -81,11 +81,13 @@ class LinuxBridgePlugin(plugin.PluginBase): linux_net.configure(ipm) def describe(self): - return plugin.PluginInfo( - [ - plugin.PluginVIFInfo( - objects.vif.VIFBridge, - "1.0", "1.0") + return objects.host_info.HostPluginInfo( + plugin_name="linux_bridge", + vif_info=[ + objects.host_info.HostVIFInfo( + vif_object_name=objects.vif.VIFBridge.__name__, + min_version="1.0", + max_version="1.0") ]) def plug(self, vif, instance_info): diff --git a/vif_plug_ovs/ovs.py b/vif_plug_ovs/ovs.py index e73f8bb1..ec656b0d 100644 --- a/vif_plug_ovs/ovs.py +++ b/vif_plug_ovs/ovs.py @@ -25,11 +25,13 @@ class OvsBridgePlugin(plugin.PluginBase): """An OVS VIF type that uses a standard Linux bridge for integration.""" def describe(self): - return plugin.PluginInfo( - [ - plugin.PluginVIFInfo( - objects.vif.VIFOpenVSwitch, - "1.0", "1.0") + return objects.host_info.HostPluginInfo( + plugin_name="ovs", + vif_info=[ + objects.host_info.HostVIFInfo( + vif_object_name=objects.vif.VIFOpenVSwitch.__name__, + min_version="1.0", + max_version="1.0") ]) def plug(self, vif, instance_info): diff --git a/vif_plug_ovs/ovs_hybrid.py b/vif_plug_ovs/ovs_hybrid.py index 5d202628..a903b09f 100644 --- a/vif_plug_ovs/ovs_hybrid.py +++ b/vif_plug_ovs/ovs_hybrid.py @@ -57,11 +57,13 @@ class OvsHybridPlugin(plugin.PluginBase): ("qvo%s" % iface_id)[:OvsHybridPlugin.NIC_NAME_LEN]) def describe(self): - return plugin.PluginInfo( - [ - plugin.PluginVIFInfo( - objects.vif.VIFBridge, - "1.0", "1.0") + return objects.host_info.HostPluginInfo( + plugin_name="ovs_hybrid", + vif_info=[ + objects.host_info.HostVIFInfo( + vif_object_name=objects.vif.VIFBridge.__name__, + min_version="1.0", + max_version="1.0") ]) def plug(self, vif, instance_info):