Add support for retrieving unprocessed data
Change-Id: I3c0070d0c1f5d12e98f914be44f4ed52b01ea043
This commit is contained in:
parent
9ecb6e33eb
commit
cc7fcf4332
@ -70,6 +70,48 @@ The response will contain introspection data in the form of json string.
|
||||
:language: javascript
|
||||
|
||||
|
||||
Get Unprocessed Introspection data
|
||||
==================================
|
||||
|
||||
.. rest_method:: GET /v1/introspection/{node_id}/data/unprocessed
|
||||
|
||||
Return stored raw (unprocessed) data from introspection.
|
||||
|
||||
.. versionadded:: 1.17
|
||||
Unprocessed introspection data can now be retrieved.
|
||||
|
||||
.. note::
|
||||
We do not provide any backward compatibility guarantees regarding the
|
||||
format and contents of the stored data. Notably, it depends on the ramdisk
|
||||
used and plugins enabled both in the ramdisk and in inspector itself.
|
||||
|
||||
Normal response codes: 200
|
||||
|
||||
Error codes:
|
||||
|
||||
* 400 - bad request
|
||||
* 401, 403 - missing or invalid authentication
|
||||
* 404 - data cannot be found or data storage not configured
|
||||
|
||||
Request
|
||||
-------
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- node_id: node_id
|
||||
|
||||
|
||||
Response
|
||||
--------
|
||||
|
||||
The response will contain introspection data in the form of json string.
|
||||
|
||||
**Example JSON representation of an introspection data:**
|
||||
|
||||
.. literalinclude:: samples/api-v1-data-introspection-response.json
|
||||
:language: javascript
|
||||
|
||||
|
||||
Reapply Introspection on data
|
||||
=============================
|
||||
|
||||
|
@ -134,6 +134,32 @@ details about the inventory key, refer to the
|
||||
:ironic-python-agent-doc:`ironic-python-agent documentation
|
||||
<admin/how_it_works.html#inspection-data>`.
|
||||
|
||||
.. note::
|
||||
We do not provide any backward compatibility guarantees regarding the
|
||||
format and contents of the stored data, other than the ``inventory``.
|
||||
Notably, it depends on the ramdisk
|
||||
used and plugins enabled both in the ramdisk and in inspector itself.
|
||||
|
||||
Get Unprocessed Introspection Data
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``GET /v1/introspection/<Node ID>/data/unprocessed`` get raw (unprocessed) data
|
||||
from introspection.
|
||||
|
||||
Requires X-Auth-Token header with Keystone token for authentication.
|
||||
|
||||
Response:
|
||||
|
||||
* 200 - OK
|
||||
* 400 - bad request
|
||||
* 401, 403 - missing or invalid authentication
|
||||
* 404 - data cannot be found or data storage not configured
|
||||
|
||||
Response body: JSON dictionary with introspection data. For more
|
||||
details about the inventory key, refer to the
|
||||
:ironic-python-agent-doc:`ironic-python-agent documentation
|
||||
<admin/how_it_works.html#inspection-data>`.
|
||||
|
||||
.. note::
|
||||
We do not provide any backward compatibility guarantees regarding the
|
||||
format and contents of the stored data, other than the ``inventory``.
|
||||
@ -403,3 +429,4 @@ Version History
|
||||
in the actions of introspection rules.
|
||||
* **1.15** allows reapply with provided introspection data from request.
|
||||
* **1.16** adds ``scope`` field to introspection rule.
|
||||
* **1.17** adds ``GET /v1/introspection/<node>/data/unprocessed``.
|
||||
|
@ -43,7 +43,7 @@ _wsgi_app = _app.wsgi_app
|
||||
LOG = utils.getProcessingLogger(__name__)
|
||||
|
||||
MINIMUM_API_VERSION = (1, 0)
|
||||
CURRENT_API_VERSION = (1, 16)
|
||||
CURRENT_API_VERSION = (1, 17)
|
||||
DEFAULT_API_VERSION = CURRENT_API_VERSION
|
||||
_LOGGING_EXCLUDED_KEYS = ('logs',)
|
||||
|
||||
@ -386,14 +386,12 @@ def api_introspection_abort(node_id):
|
||||
return _generate_empty_response(202)
|
||||
|
||||
|
||||
@api('/v1/introspection/<node_id>/data', rule="introspection:data",
|
||||
methods=['GET'])
|
||||
def api_introspection_data(node_id):
|
||||
def _get_data(node_id, processed):
|
||||
try:
|
||||
if not uuidutils.is_uuid_like(node_id):
|
||||
node = ir_utils.get_node(node_id, fields=['uuid'])
|
||||
node_id = node.uuid
|
||||
res = process.get_introspection_data(node_id)
|
||||
res = process.get_introspection_data(node_id, processed=processed)
|
||||
return res, 200, {'Content-Type': 'application/json'}
|
||||
except utils.IntrospectionDataStoreDisabled:
|
||||
return error_response(_('Inspector is not configured to store data. '
|
||||
@ -402,6 +400,18 @@ def api_introspection_data(node_id):
|
||||
code=404)
|
||||
|
||||
|
||||
@api('/v1/introspection/<node_id>/data', rule="introspection:data",
|
||||
methods=['GET'])
|
||||
def api_introspection_data(node_id):
|
||||
return _get_data(node_id, True)
|
||||
|
||||
|
||||
@api('/v1/introspection/<node_id>/data/unprocessed', rule="introspection:data",
|
||||
methods=['GET'])
|
||||
def api_introspection_unprocessed_data(node_id):
|
||||
return _get_data(node_id, False)
|
||||
|
||||
|
||||
@api('/v1/introspection/<node_id>/data/unprocessed',
|
||||
rule="introspection:reapply", methods=['POST'])
|
||||
def api_introspection_reapply(node_id):
|
||||
|
@ -177,8 +177,9 @@ class Base(base.NodeTest):
|
||||
def call_get_status(self, uuid, **kwargs):
|
||||
return self.call('get', '/v1/introspection/%s' % uuid, **kwargs).json()
|
||||
|
||||
def call_get_data(self, uuid, **kwargs):
|
||||
return self.call('get', '/v1/introspection/%s/data' % uuid,
|
||||
def call_get_data(self, uuid, processed=True, **kwargs):
|
||||
return self.call('get', '/v1/introspection/%s/data%s'
|
||||
% (uuid, '' if processed else '/unprocessed'),
|
||||
**kwargs).json()
|
||||
|
||||
@_query_string('marker', 'limit')
|
||||
@ -626,6 +627,10 @@ class Test(Base):
|
||||
|
||||
data = self.call_get_data(self.uuid)
|
||||
self.assertEqual(self.data['inventory'], data['inventory'])
|
||||
self.assertIn('all_interfaces', data)
|
||||
raw = self.call_get_data(self.uuid, processed=False)
|
||||
self.assertEqual(self.data['inventory'], raw['inventory'])
|
||||
self.assertNotIn('all_interfaces', raw)
|
||||
|
||||
res = self.call_reapply(self.uuid)
|
||||
self.assertEqual(202, res.status_code)
|
||||
|
@ -371,6 +371,19 @@ class TestApiGetData(BaseAPITest):
|
||||
self.assertEqual(self.introspection_data,
|
||||
json.loads(res.data.decode('utf-8')))
|
||||
|
||||
@mock.patch.object(swift, 'SwiftAPI', autospec=True)
|
||||
def test_get_unprocessed_data_from_swift(self, swift_mock):
|
||||
CONF.set_override('store_data', 'swift', 'processing')
|
||||
swift_conn = swift_mock.return_value
|
||||
swift_conn.get_object.return_value = json.dumps(
|
||||
self.introspection_data)
|
||||
res = self.app.get('/v1/introspection/%s/data/unprocessed' % self.uuid)
|
||||
name = 'inspector_data-%s-UNPROCESSED' % self.uuid
|
||||
swift_conn.get_object.assert_called_once_with(name)
|
||||
self.assertEqual(200, res.status_code)
|
||||
self.assertEqual(self.introspection_data,
|
||||
json.loads(res.data.decode('utf-8')))
|
||||
|
||||
@mock.patch.object(intros_data_plugin, 'DatabaseStore',
|
||||
autospec=True)
|
||||
def test_get_introspection_data_from_db(self, db_mock):
|
||||
@ -389,6 +402,11 @@ class TestApiGetData(BaseAPITest):
|
||||
res = self.app.get('/v1/introspection/%s/data' % self.uuid)
|
||||
self.assertEqual(404, res.status_code)
|
||||
|
||||
def test_unprocessed_data_not_stored(self):
|
||||
CONF.set_override('store_data', 'none', 'processing')
|
||||
res = self.app.get('/v1/introspection/%s/data/unprocessed' % self.uuid)
|
||||
self.assertEqual(404, res.status_code)
|
||||
|
||||
@mock.patch.object(ir_utils, 'get_node', autospec=True)
|
||||
@mock.patch.object(main.process, 'get_introspection_data', autospec=True)
|
||||
def test_with_name(self, process_mock, get_mock):
|
||||
|
5
releasenotes/notes/unprocessed-07842e56eb60e253.yaml
Normal file
5
releasenotes/notes/unprocessed-07842e56eb60e253.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
The new API ``GET /v1/introspection/<node>/data/unprocessed`` allows
|
||||
retrieving raw (unprocessed) data if data store is enabled.
|
Loading…
Reference in New Issue
Block a user