Browse Source

Merge "Add support for retrieving unprocessed data"

changes/33/744733/1
Zuul 1 week ago
committed by Gerrit Code Review
parent
commit
7ff52c732b
6 changed files with 114 additions and 7 deletions
  1. +42
    -0
      api-ref/source/introspection-api-v1-introspection-management.inc
  2. +27
    -0
      doc/source/user/http-api.rst
  3. +15
    -5
      ironic_inspector/main.py
  4. +7
    -2
      ironic_inspector/test/functional.py
  5. +18
    -0
      ironic_inspector/test/unit/test_main.py
  6. +5
    -0
      releasenotes/notes/unprocessed-07842e56eb60e253.yaml

+ 42
- 0
api-ref/source/introspection-api-v1-introspection-management.inc 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
=============================



+ 27
- 0
doc/source/user/http-api.rst 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``.

+ 15
- 5
ironic_inspector/main.py 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):


+ 7
- 2
ironic_inspector/test/functional.py 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)


+ 18
- 0
ironic_inspector/test/unit/test_main.py 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):


+ 5
- 0
releasenotes/notes/unprocessed-07842e56eb60e253.yaml 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.

Loading…
Cancel
Save