Merge "Add API Discovery to Ironic Inspector"
This commit is contained in:
commit
6142ba8367
37
HTTP-API.rst
37
HTTP-API.rst
@ -228,6 +228,43 @@ major version and is always ``1`` for now, ``Y`` is a minor version.
|
|||||||
``X-OpenStack-Ironic-Inspector-API-Maximum-Version`` headers with minimum
|
``X-OpenStack-Ironic-Inspector-API-Maximum-Version`` headers with minimum
|
||||||
and maximum API versions supported by the server.
|
and maximum API versions supported by the server.
|
||||||
|
|
||||||
|
API Discovery
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The API supports API discovery. You can query different parts of the API to
|
||||||
|
discover what other endpoints are avaliable.
|
||||||
|
|
||||||
|
* ``GET /`` List API Versions
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
* 200 - OK
|
||||||
|
|
||||||
|
Response body: JSON dictionary containing a list of ``versions``, each
|
||||||
|
version contains:
|
||||||
|
|
||||||
|
* ``status`` Either CURRENT or SUPPORTED
|
||||||
|
* ``id`` The version identifier
|
||||||
|
* ``links`` A list of links to this version endpoint containing:
|
||||||
|
|
||||||
|
* ``href`` The URL
|
||||||
|
* ``rel`` The relationship between the version and the href
|
||||||
|
|
||||||
|
* ``GET /v1`` List API v1 resources
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
* 200 - OK
|
||||||
|
|
||||||
|
Response body: JSON dictionary containing a list of ``resources``, each
|
||||||
|
resource contains:
|
||||||
|
|
||||||
|
* ``name`` The name of this resources
|
||||||
|
* ``links`` A list of link to this resource containing:
|
||||||
|
|
||||||
|
* ``href`` The URL
|
||||||
|
* ``rel`` The relationship between the resource and the href
|
||||||
|
|
||||||
Version History
|
Version History
|
||||||
^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
@ -15,6 +15,8 @@ import eventlet
|
|||||||
eventlet.monkey_patch()
|
eventlet.monkey_patch()
|
||||||
|
|
||||||
import functools
|
import functools
|
||||||
|
import os
|
||||||
|
import re
|
||||||
import ssl
|
import ssl
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@ -108,13 +110,55 @@ def add_version_headers(res):
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
def create_link_object(urls):
|
||||||
|
links = []
|
||||||
|
for url in urls:
|
||||||
|
links.append({"rel": "self",
|
||||||
|
"href": os.path.join(flask.request.url_root, url)})
|
||||||
|
return links
|
||||||
|
|
||||||
|
|
||||||
|
def generate_resource_data(resources):
|
||||||
|
data = []
|
||||||
|
for resource in resources:
|
||||||
|
item = {}
|
||||||
|
item['name'] = str(resource).split('/')[-1]
|
||||||
|
item['links'] = create_link_object([str(resource)[1:]])
|
||||||
|
data.append(item)
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
@app.route('/', methods=['GET'])
|
@app.route('/', methods=['GET'])
|
||||||
@app.route('/v1', methods=['GET'])
|
|
||||||
@convert_exceptions
|
@convert_exceptions
|
||||||
def api_root():
|
def api_root():
|
||||||
# TODO(dtantsur): this endpoint only returns API version now, it's possible
|
versions = [
|
||||||
# we'll return something meaningful in addition later
|
{
|
||||||
return flask.jsonify({})
|
"status": "CURRENT",
|
||||||
|
"id": '%s.%s' % CURRENT_API_VERSION,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
for version in versions:
|
||||||
|
version['links'] = create_link_object(
|
||||||
|
["v%s" % version['id'].split('.')[0]])
|
||||||
|
|
||||||
|
return flask.jsonify(versions=versions)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/<version>', methods=['GET'])
|
||||||
|
@convert_exceptions
|
||||||
|
def version_root(version):
|
||||||
|
pat = re.compile("^\/%s\/[^\/]*?$" % version)
|
||||||
|
|
||||||
|
resources = []
|
||||||
|
for url in app.url_map.iter_rules():
|
||||||
|
if pat.match(str(url)):
|
||||||
|
resources.append(url)
|
||||||
|
|
||||||
|
if not resources:
|
||||||
|
raise utils.Error(_('Version not found.'), code=404)
|
||||||
|
|
||||||
|
return flask.jsonify(resources=generate_resource_data(resources))
|
||||||
|
|
||||||
|
|
||||||
@app.route('/v1/continue', methods=['POST'])
|
@app.route('/v1/continue', methods=['POST'])
|
||||||
@ -126,6 +170,7 @@ def api_continue():
|
|||||||
return flask.jsonify(process.process(data))
|
return flask.jsonify(process.process(data))
|
||||||
|
|
||||||
|
|
||||||
|
# TODO(sambetts) Add API discovery for this endpoint
|
||||||
@app.route('/v1/introspection/<uuid>', methods=['GET', 'POST'])
|
@app.route('/v1/introspection/<uuid>', methods=['GET', 'POST'])
|
||||||
@convert_exceptions
|
@convert_exceptions
|
||||||
def api_introspection(uuid):
|
def api_introspection(uuid):
|
||||||
|
@ -305,11 +305,53 @@ class TestApiVersions(BaseAPITest):
|
|||||||
self.assertEqual('%d.%d' % main.CURRENT_API_VERSION,
|
self.assertEqual('%d.%d' % main.CURRENT_API_VERSION,
|
||||||
res.headers.get(main._MAX_VERSION_HEADER))
|
res.headers.get(main._MAX_VERSION_HEADER))
|
||||||
|
|
||||||
def test_root_endpoints(self):
|
def test_root_endpoint(self):
|
||||||
for endpoint in '/', '/v1':
|
res = self.app.get("/")
|
||||||
|
self.assertEqual(200, res.status_code)
|
||||||
|
self._check_version_present(res)
|
||||||
|
data = res.data.decode('utf-8')
|
||||||
|
json_data = json.loads(data)
|
||||||
|
expected = {"versions": [{
|
||||||
|
"status": "CURRENT", "id": '%s.%s' % main.CURRENT_API_VERSION,
|
||||||
|
"links": [{
|
||||||
|
"rel": "self",
|
||||||
|
"href": ("http://localhost/v%s" %
|
||||||
|
main.CURRENT_API_VERSION[0])
|
||||||
|
}]
|
||||||
|
}]}
|
||||||
|
self.assertEqual(expected, json_data)
|
||||||
|
|
||||||
|
@mock.patch.object(main.app.url_map, "iter_rules", autospec=True)
|
||||||
|
def test_version_endpoint(self, mock_rules):
|
||||||
|
mock_rules.return_value = ["/v1/endpoint1", "/v1/endpoint2/<uuid>",
|
||||||
|
"/v1/endpoint1/<name>",
|
||||||
|
"/v2/endpoint1", "/v1/endpoint3",
|
||||||
|
"/v1/endpoint2/<uuid>/subpoint"]
|
||||||
|
endpoint = "/v1"
|
||||||
res = self.app.get(endpoint)
|
res = self.app.get(endpoint)
|
||||||
self.assertEqual(200, res.status_code)
|
self.assertEqual(200, res.status_code)
|
||||||
self._check_version_present(res)
|
self._check_version_present(res)
|
||||||
|
json_data = json.loads(res.data.decode('utf-8'))
|
||||||
|
expected = {u'resources': [
|
||||||
|
{
|
||||||
|
u'name': u'endpoint1',
|
||||||
|
u'links': [{
|
||||||
|
u'rel': u'self',
|
||||||
|
u'href': u'http://localhost/v1/endpoint1'}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
u'name': u'endpoint3',
|
||||||
|
u'links': [{
|
||||||
|
u'rel': u'self',
|
||||||
|
u'href': u'http://localhost/v1/endpoint3'}]
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
self.assertDictEqual(expected, json_data)
|
||||||
|
|
||||||
|
def test_version_endpoint_invalid(self):
|
||||||
|
endpoint = "/v-1"
|
||||||
|
res = self.app.get(endpoint)
|
||||||
|
self.assertEqual(404, res.status_code)
|
||||||
|
|
||||||
def test_404_unexpected(self):
|
def test_404_unexpected(self):
|
||||||
# API version on unknown pages
|
# API version on unknown pages
|
||||||
|
Loading…
x
Reference in New Issue
Block a user