Add api-version to get server versions
Mitaka Cinder added an API to return Versions from the base endpoint URL: http://<url>:8776/ This patch exposes that API for /v3 endpoint microversions 3.0 and above with the command: cinder api-version Implements: blueprint add-get-server-versions Change-Id: Ieb1a56b28188ec17946fe5564b28c165833ffc24
This commit is contained in:
@@ -335,6 +335,14 @@ class Manager(common_base.HookableMixin):
|
|||||||
body = body or {}
|
body = body or {}
|
||||||
return common_base.DictWithMeta(body, resp)
|
return common_base.DictWithMeta(body, resp)
|
||||||
|
|
||||||
|
def _get_with_base_url(self, url, response_key=None):
|
||||||
|
resp, body = self.api.client.get_with_base_url(url)
|
||||||
|
if response_key:
|
||||||
|
return [self.resource_class(self, res, loaded=True)
|
||||||
|
for res in body[response_key] if res]
|
||||||
|
else:
|
||||||
|
return self.resource_class(self, body, loaded=True)
|
||||||
|
|
||||||
|
|
||||||
class ManagerWithFind(six.with_metaclass(abc.ABCMeta, Manager)):
|
class ManagerWithFind(six.with_metaclass(abc.ABCMeta, Manager)):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -151,6 +151,11 @@ class SessionClient(adapter.LegacyJsonAdapter):
|
|||||||
def delete(self, url, **kwargs):
|
def delete(self, url, **kwargs):
|
||||||
return self._cs_request(url, 'DELETE', **kwargs)
|
return self._cs_request(url, 'DELETE', **kwargs)
|
||||||
|
|
||||||
|
def _get_base_url(self):
|
||||||
|
endpoint = self.get_endpoint()
|
||||||
|
base_url = '/'.join(endpoint.split('/')[:3]) + '/'
|
||||||
|
return base_url
|
||||||
|
|
||||||
def get_volume_api_version_from_endpoint(self):
|
def get_volume_api_version_from_endpoint(self):
|
||||||
try:
|
try:
|
||||||
version = get_volume_api_from_url(self.get_endpoint())
|
version = get_volume_api_from_url(self.get_endpoint())
|
||||||
@@ -176,6 +181,16 @@ class SessionClient(adapter.LegacyJsonAdapter):
|
|||||||
raise AttributeError('There is no service catalog for this type of '
|
raise AttributeError('There is no service catalog for this type of '
|
||||||
'auth plugin.')
|
'auth plugin.')
|
||||||
|
|
||||||
|
def _cs_request_base_url(self, url, method, **kwargs):
|
||||||
|
base_url = self._get_base_url(**kwargs)
|
||||||
|
return self._cs_request(
|
||||||
|
base_url + url,
|
||||||
|
method,
|
||||||
|
**kwargs)
|
||||||
|
|
||||||
|
def get_with_base_url(self, url, **kwargs):
|
||||||
|
return self._cs_request_base_url(url, 'GET', **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class HTTPClient(object):
|
class HTTPClient(object):
|
||||||
|
|
||||||
|
|||||||
@@ -79,6 +79,13 @@ class ClientTest(utils.TestCase):
|
|||||||
cinderclient.client.get_volume_api_from_url,
|
cinderclient.client.get_volume_api_from_url,
|
||||||
unknown_url)
|
unknown_url)
|
||||||
|
|
||||||
|
@mock.patch('cinderclient.client.SessionClient.get_endpoint')
|
||||||
|
def test_get_base_url(self, mock_get_endpoint):
|
||||||
|
url = 'http://192.168.122.104:8776/v3/de50d1f33a38415fadfd3e1dea28f4d3'
|
||||||
|
mock_get_endpoint.return_value = url
|
||||||
|
cs = cinderclient.client.SessionClient(self, api_version='3.0')
|
||||||
|
self.assertEqual('http://192.168.122.104:8776/', cs._get_base_url())
|
||||||
|
|
||||||
@mock.patch.object(cinderclient.client, '_log_request_id')
|
@mock.patch.object(cinderclient.client, '_log_request_id')
|
||||||
@mock.patch.object(adapter.Adapter, 'request')
|
@mock.patch.object(adapter.Adapter, 'request')
|
||||||
@mock.patch.object(exceptions, 'from_response')
|
@mock.patch.object(exceptions, 'from_response')
|
||||||
|
|||||||
@@ -249,6 +249,65 @@ def _stub_extend(id, new_size):
|
|||||||
return {'volume_id': '712f4980-5ac1-41e5-9383-390aa7c9f58b'}
|
return {'volume_id': '712f4980-5ac1-41e5-9383-390aa7c9f58b'}
|
||||||
|
|
||||||
|
|
||||||
|
def _stub_server_versions():
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"status": "SUPPORTED",
|
||||||
|
"updated": "2015-07-30T11:33:21Z",
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"href": "http://docs.openstack.org/",
|
||||||
|
"type": "text/html",
|
||||||
|
"rel": "describedby",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"href": "http://localhost:8776/v1/",
|
||||||
|
"rel": "self",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"min_version": "",
|
||||||
|
"version": "",
|
||||||
|
"id": "v1.0",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"status": "SUPPORTED",
|
||||||
|
"updated": "2015-09-30T11:33:21Z",
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"href": "http://docs.openstack.org/",
|
||||||
|
"type": "text/html",
|
||||||
|
"rel": "describedby",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"href": "http://localhost:8776/v2/",
|
||||||
|
"rel": "self",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"min_version": "",
|
||||||
|
"version": "",
|
||||||
|
"id": "v2.0",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"status": "CURRENT",
|
||||||
|
"updated": "2016-04-01T11:33:21Z",
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"href": "http://docs.openstack.org/",
|
||||||
|
"type": "text/html",
|
||||||
|
"rel": "describedby",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"href": "http://localhost:8776/v3/",
|
||||||
|
"rel": "self",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"min_version": "3.0",
|
||||||
|
"version": "3.1",
|
||||||
|
"id": "v3.0",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class FakeClient(fakes.FakeClient, client.Client):
|
class FakeClient(fakes.FakeClient, client.Client):
|
||||||
|
|
||||||
def __init__(self, api_version=None, *args, **kwargs):
|
def __init__(self, api_version=None, *args, **kwargs):
|
||||||
@@ -264,7 +323,7 @@ class FakeClient(fakes.FakeClient, client.Client):
|
|||||||
|
|
||||||
class FakeHTTPClient(base_client.HTTPClient):
|
class FakeHTTPClient(base_client.HTTPClient):
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, version_header=None, **kwargs):
|
||||||
self.username = 'username'
|
self.username = 'username'
|
||||||
self.password = 'password'
|
self.password = 'password'
|
||||||
self.auth_url = 'auth_url'
|
self.auth_url = 'auth_url'
|
||||||
@@ -272,6 +331,7 @@ class FakeHTTPClient(base_client.HTTPClient):
|
|||||||
self.management_url = 'http://10.0.2.15:8776/v2/fake'
|
self.management_url = 'http://10.0.2.15:8776/v2/fake'
|
||||||
self.osapi_max_limit = 1000
|
self.osapi_max_limit = 1000
|
||||||
self.marker = None
|
self.marker = None
|
||||||
|
self.version_header = version_header
|
||||||
|
|
||||||
def _cs_request(self, url, method, **kwargs):
|
def _cs_request(self, url, method, **kwargs):
|
||||||
# Check that certain things are called correctly
|
# Check that certain things are called correctly
|
||||||
@@ -308,6 +368,8 @@ class FakeHTTPClient(base_client.HTTPClient):
|
|||||||
status, headers, body = getattr(self, callback)(**kwargs)
|
status, headers, body = getattr(self, callback)(**kwargs)
|
||||||
# add fake request-id header
|
# add fake request-id header
|
||||||
headers['x-openstack-request-id'] = REQUEST_ID
|
headers['x-openstack-request-id'] = REQUEST_ID
|
||||||
|
if self.version_header:
|
||||||
|
headers['OpenStack-API-version'] = version_header
|
||||||
r = utils.TestResponse({
|
r = utils.TestResponse({
|
||||||
"status_code": status,
|
"status_code": status,
|
||||||
"text": body,
|
"text": body,
|
||||||
@@ -969,6 +1031,10 @@ class FakeHTTPClient(base_client.HTTPClient):
|
|||||||
return (200, {},
|
return (200, {},
|
||||||
{'transfer': _stub_transfer(transfer1, base_uri, tenant_id)})
|
{'transfer': _stub_transfer(transfer1, base_uri, tenant_id)})
|
||||||
|
|
||||||
|
def get_with_base_url(self, url, **kw):
|
||||||
|
server_versions = _stub_server_versions()
|
||||||
|
return (200, {'versions': server_versions})
|
||||||
|
|
||||||
#
|
#
|
||||||
# Services
|
# Services
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -80,3 +80,8 @@ class ServicesTest(utils.TestCase):
|
|||||||
self.assertIsInstance(s, services.Service)
|
self.assertIsInstance(s, services.Service)
|
||||||
self.assertEqual('disabled', s.status)
|
self.assertEqual('disabled', s.status)
|
||||||
self._assert_request_id(s)
|
self._assert_request_id(s)
|
||||||
|
|
||||||
|
def test_api_version(self):
|
||||||
|
client = fakes.FakeClient(version_header='3.0')
|
||||||
|
svs = client.services.server_api_version()
|
||||||
|
[self.assertIsInstance(s, services.Service) for s in svs]
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
"""
|
"""
|
||||||
service interface
|
service interface
|
||||||
"""
|
"""
|
||||||
|
from cinderclient import api_versions
|
||||||
from cinderclient import base
|
from cinderclient import base
|
||||||
|
|
||||||
|
|
||||||
@@ -77,3 +78,16 @@ class ServiceManager(base.ManagerWithFind):
|
|||||||
"""Failover a replicated backend by hostname."""
|
"""Failover a replicated backend by hostname."""
|
||||||
body = {"host": host, "backend_id": backend_id}
|
body = {"host": host, "backend_id": backend_id}
|
||||||
return self._update("/os-services/failover_host", body)
|
return self._update("/os-services/failover_host", body)
|
||||||
|
|
||||||
|
@api_versions.wraps("3.0")
|
||||||
|
def server_api_version(self, url_append=""):
|
||||||
|
"""Returns the API Version supported by the server.
|
||||||
|
|
||||||
|
:param url_append: String to append to url to obtain specific version
|
||||||
|
:return: Returns response obj for a server that supports microversions.
|
||||||
|
Returns an empty list for Liberty and prior Cinder servers.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return self._get_with_base_url(url_append, response_key='versions')
|
||||||
|
except LookupError:
|
||||||
|
return []
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import time
|
|||||||
|
|
||||||
import six
|
import six
|
||||||
|
|
||||||
|
from cinderclient import api_versions
|
||||||
from cinderclient import base
|
from cinderclient import base
|
||||||
from cinderclient import exceptions
|
from cinderclient import exceptions
|
||||||
from cinderclient import utils
|
from cinderclient import utils
|
||||||
@@ -2680,3 +2681,12 @@ def do_thaw_host(cs, args):
|
|||||||
def do_failover_host(cs, args):
|
def do_failover_host(cs, args):
|
||||||
"""Failover a replicating cinder-volume host."""
|
"""Failover a replicating cinder-volume host."""
|
||||||
cs.services.failover_host(args.host, args.backend_id)
|
cs.services.failover_host(args.host, args.backend_id)
|
||||||
|
|
||||||
|
|
||||||
|
@utils.service_type('volumev3')
|
||||||
|
@api_versions.wraps("3.0")
|
||||||
|
def do_api_version(cs, args):
|
||||||
|
"""Display the API version information."""
|
||||||
|
columns = ['ID', 'Status', 'Version', 'Min_version']
|
||||||
|
response = cs.services.server_api_version()
|
||||||
|
utils.print_list(response, columns)
|
||||||
|
|||||||
Reference in New Issue
Block a user