XenAPI: Add versioning for plugins
Because the plugins live on a host seperate to Nova we need an interface to test whether they are the expected version. We can't use pip or other requirement systems as they are cross-machine. Closes bug 1226622 Change-Id: I58ab669061f51bd87071e2cf0d93d33021001309
This commit is contained in:
parent
026edcd686
commit
24fd331b8c
nova
plugins/xenserver/xenapi
@ -239,7 +239,10 @@ class FakeSessionForFirewallTests(FakeSessionForVMTests):
|
|||||||
if '*filter' in lines:
|
if '*filter' in lines:
|
||||||
output = '\n'.join(lines)
|
output = '\n'.join(lines)
|
||||||
ret_str = fake.as_json(out=output, err='')
|
ret_str = fake.as_json(out=output, err='')
|
||||||
return ret_str
|
return ret_str
|
||||||
|
else:
|
||||||
|
return (super(FakeSessionForVMTests, self).
|
||||||
|
host_call_plugin(_1, _2, plugin, method, args))
|
||||||
|
|
||||||
|
|
||||||
def stub_out_vm_methods(stubs):
|
def stub_out_vm_methods(stubs):
|
||||||
|
@ -3957,6 +3957,78 @@ class XenAPISessionTestCase(test.NoDBTestCase):
|
|||||||
session._get_product_version_and_brand()
|
session._get_product_version_and_brand()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_verify_plugin_version_same(self):
|
||||||
|
session = self._get_mock_xapisession({})
|
||||||
|
|
||||||
|
session.PLUGIN_REQUIRED_VERSION = '2.4'
|
||||||
|
|
||||||
|
self.mox.StubOutWithMock(session, 'call_plugin_serialized')
|
||||||
|
session.call_plugin_serialized('nova_plugin_version', 'get_version',
|
||||||
|
).AndReturn("2.4")
|
||||||
|
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
session._verify_plugin_version()
|
||||||
|
|
||||||
|
def test_verify_plugin_version_compatible(self):
|
||||||
|
session = self._get_mock_xapisession({})
|
||||||
|
session.XenAPI = xenapi_fake.FakeXenAPI()
|
||||||
|
|
||||||
|
session.PLUGIN_REQUIRED_VERSION = '2.4'
|
||||||
|
|
||||||
|
self.mox.StubOutWithMock(session, 'call_plugin_serialized')
|
||||||
|
session.call_plugin_serialized('nova_plugin_version', 'get_version',
|
||||||
|
).AndReturn("2.5")
|
||||||
|
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
session._verify_plugin_version()
|
||||||
|
|
||||||
|
def test_verify_plugin_version_bad_maj(self):
|
||||||
|
session = self._get_mock_xapisession({})
|
||||||
|
session.XenAPI = xenapi_fake.FakeXenAPI()
|
||||||
|
|
||||||
|
session.PLUGIN_REQUIRED_VERSION = '2.4'
|
||||||
|
|
||||||
|
self.mox.StubOutWithMock(session, 'call_plugin_serialized')
|
||||||
|
session.call_plugin_serialized('nova_plugin_version', 'get_version',
|
||||||
|
).AndReturn("3.0")
|
||||||
|
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
self.assertRaises(xenapi_fake.Failure, session._verify_plugin_version)
|
||||||
|
|
||||||
|
def test_verify_plugin_version_bad_min(self):
|
||||||
|
session = self._get_mock_xapisession({})
|
||||||
|
session.XenAPI = xenapi_fake.FakeXenAPI()
|
||||||
|
|
||||||
|
session.PLUGIN_REQUIRED_VERSION = '2.4'
|
||||||
|
|
||||||
|
self.mox.StubOutWithMock(session, 'call_plugin_serialized')
|
||||||
|
session.call_plugin_serialized('nova_plugin_version', 'get_version',
|
||||||
|
).AndReturn("2.3")
|
||||||
|
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
self.assertRaises(xenapi_fake.Failure, session._verify_plugin_version)
|
||||||
|
|
||||||
|
def test_verify_current_version_matches(self):
|
||||||
|
session = self._get_mock_xapisession({})
|
||||||
|
|
||||||
|
# Import the plugin to extract its version
|
||||||
|
path = os.path.dirname(__file__)
|
||||||
|
rel_path_elem = "../../../../plugins/xenserver/xenapi/etc/xapi.d/" \
|
||||||
|
"plugins/nova_plugin_version"
|
||||||
|
for elem in rel_path_elem.split('/'):
|
||||||
|
path = os.path.join(path, elem)
|
||||||
|
path = os.path.realpath(path)
|
||||||
|
|
||||||
|
plugin_version = None
|
||||||
|
with open(path) as plugin_file:
|
||||||
|
for line in plugin_file:
|
||||||
|
if "PLUGIN_VERSION = " in line:
|
||||||
|
print line
|
||||||
|
plugin_version = line.strip()[17:].strip('"')
|
||||||
|
|
||||||
|
self.assertEquals(session.PLUGIN_REQUIRED_VERSION,
|
||||||
|
plugin_version)
|
||||||
|
|
||||||
|
|
||||||
class XenAPIFakeTestCase(test.NoDBTestCase):
|
class XenAPIFakeTestCase(test.NoDBTestCase):
|
||||||
def test_query_matches(self):
|
def test_query_matches(self):
|
||||||
|
@ -654,6 +654,12 @@ class XenAPIDriver(driver.ComputeDriver):
|
|||||||
class XenAPISession(object):
|
class XenAPISession(object):
|
||||||
"""The session to invoke XenAPI SDK calls."""
|
"""The session to invoke XenAPI SDK calls."""
|
||||||
|
|
||||||
|
# This is not a config option as it should only ever be
|
||||||
|
# changed in development environments.
|
||||||
|
# MAJOR VERSION: Incompatible changes with the plugins
|
||||||
|
# MINOR VERSION: Compatible changes, new plguins, etc
|
||||||
|
PLUGIN_REQUIRED_VERSION = '1.0'
|
||||||
|
|
||||||
def __init__(self, url, user, pw, virtapi):
|
def __init__(self, url, user, pw, virtapi):
|
||||||
import XenAPI
|
import XenAPI
|
||||||
self.XenAPI = XenAPI
|
self.XenAPI = XenAPI
|
||||||
@ -668,6 +674,22 @@ class XenAPISession(object):
|
|||||||
self._get_product_version_and_brand()
|
self._get_product_version_and_brand()
|
||||||
self._virtapi = virtapi
|
self._virtapi = virtapi
|
||||||
|
|
||||||
|
self._verify_plugin_version()
|
||||||
|
|
||||||
|
def _verify_plugin_version(self):
|
||||||
|
# Verify that we're using the right version of the plugins
|
||||||
|
returned_version = self.call_plugin_serialized(
|
||||||
|
'nova_plugin_version', 'get_version')
|
||||||
|
|
||||||
|
# Can't use vmops.cmp_version because that tolerates differences in
|
||||||
|
# major version
|
||||||
|
req_maj, req_min = self.PLUGIN_REQUIRED_VERSION.split('.')
|
||||||
|
got_maj, got_min = returned_version.split('.')
|
||||||
|
if req_maj != got_maj or req_min > got_min:
|
||||||
|
raise self.XenAPI.Failure(
|
||||||
|
_("Plugin version mismatch (Expected %(exp)s, got %(got)s)") %
|
||||||
|
{'exp': self.PLUGIN_REQUIRED_VERSION, 'got': returned_version})
|
||||||
|
|
||||||
def _create_first_session(self, url, user, pw, exception):
|
def _create_first_session(self, url, user, pw, exception):
|
||||||
try:
|
try:
|
||||||
session = self._create_session(url)
|
session = self._create_session(url)
|
||||||
|
@ -673,6 +673,9 @@ class SessionBase(object):
|
|||||||
raise Failure('Guest does not have a console')
|
raise Failure('Guest does not have a console')
|
||||||
return base64.b64encode(zlib.compress("dom_id: %s" % dom_id))
|
return base64.b64encode(zlib.compress("dom_id: %s" % dom_id))
|
||||||
|
|
||||||
|
def _plugin_nova_plugin_version_get_version(self, method, args):
|
||||||
|
return pickle.dumps("1.0")
|
||||||
|
|
||||||
def host_call_plugin(self, _1, _2, plugin, method, args):
|
def host_call_plugin(self, _1, _2, plugin, method, args):
|
||||||
func = getattr(self, '_plugin_%s_%s' % (plugin, method), None)
|
func = getattr(self, '_plugin_%s_%s' % (plugin, method), None)
|
||||||
if not func:
|
if not func:
|
||||||
|
@ -42,3 +42,4 @@ rm -rf $RPM_BUILD_ROOT
|
|||||||
/etc/xapi.d/plugins/xenhost
|
/etc/xapi.d/plugins/xenhost
|
||||||
/etc/xapi.d/plugins/xenstore.py
|
/etc/xapi.d/plugins/xenstore.py
|
||||||
/etc/xapi.d/plugins/utils.py
|
/etc/xapi.d/plugins/utils.py
|
||||||
|
/etc/xapi.d/plugins/nova_plugin_version
|
||||||
|
33
plugins/xenserver/xenapi/etc/xapi.d/plugins/nova_plugin_version
Executable file
33
plugins/xenserver/xenapi/etc/xapi.d/plugins/nova_plugin_version
Executable file
@ -0,0 +1,33 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
# Copyright (c) 2013 OpenStack Foundation
|
||||||
|
# Copyright (c) 2013 Citrix Systems, 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.
|
||||||
|
|
||||||
|
"""Returns the version of the nova plugins"""
|
||||||
|
|
||||||
|
import utils
|
||||||
|
|
||||||
|
# MAJOR VERSION: Incompatible changes
|
||||||
|
# MINOR VERSION: Compatible changes, new plugins, etc
|
||||||
|
|
||||||
|
# 1.0 - Initial version.
|
||||||
|
PLUGIN_VERSION = "1.0"
|
||||||
|
|
||||||
|
def get_version(session):
|
||||||
|
return PLUGIN_VERSION
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
utils.register_plugin_calls(get_version)
|
Loading…
x
Reference in New Issue
Block a user