Add support for retrieving unprocessed data

Change-Id: I3c0070d0c1f5d12e98f914be44f4ed52b01ea043
This commit is contained in:
Dmitry Tantsur 2020-07-28 12:12:38 +02:00
parent 9ecb6e33eb
commit cc7fcf4332
6 changed files with 114 additions and 7 deletions

View File

@ -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
=============================

View File

@ -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``.

View File

@ -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):

View File

@ -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)

View File

@ -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):

View 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.