doc: Migrate Inspection Rules

Document inspection rules.

Related-Change: https://review.opendev.org/c/openstack/ironic/+/939217
Change-Id: If6d77a2caf873a716ae8d96eea7ee9b3fd3fbe40
This commit is contained in:
cid 2025-03-25 15:57:47 +01:00
parent 5f911ad688
commit 399a6c12d1
13 changed files with 787 additions and 5 deletions

View File

@ -0,0 +1,260 @@
.. -*- rst -*-
===================================
Inspection rules (inspection_rules)
===================================
Inspection Rules consist of conditions that evaluate against inspection data
and actions that run on a node when conditions are met during inspection.
.. versionadded:: 1.96
Inspection Rules API was introduced.
Create Inspection Rule
======================
.. rest_method:: POST /v1/inspection_rules
Creates an inspection rule.
.. versionadded:: 1.96
Inspection Rules API was introduced.
Normal response codes: 201
Error response codes: 400, 401, 403, 409
Request
-------
.. rest_parameters:: parameters.yaml
- uuid: req_uuid
- description: inspection_rule_description
- conditions: inspection_rule_conditions
- actions: inspection_rule_actions
- phase: inspection_rule_phase
- priority: inspection_rule_priority
- sensitive: inspection_rule_sensitive
Request Inspection Rule Condition
---------------------------------
.. rest_parameters:: parameters.yaml
- op: inspection_rule_condition_op
- args: inspection_rule_condition_args
- loop: inspection_rule_condition_loop
- multiple: inspection_rule_condition_multiple
Request Inspection Rule Action
------------------------------
.. rest_parameters:: parameters.yaml
- op: inspection_rule_action_op
- args: inspection_rule_action_args
- loop: inspection_rule_action_loop
Request Example
---------------
.. literalinclude:: samples/inspection-rule-create-request.json
:language: javascript
Response Parameters
-------------------
.. rest_parameters:: parameters.yaml
- uuid: uuid
- description: inspection_rule_description
- conditions: inspection_rule_conditions
- actions: inspection_rule_actions
- phase: inspection_rule_phase
- priority: inspection_rule_priority
- sensitive: inspection_rule_sensitive
- created_at: created_at
- updated_at: updated_at
- links: links
Response Example
----------------
.. literalinclude:: samples/inspection-rule-create-response.json
:language: javascript
List Inspection Rules
=====================
.. rest_method:: GET /v1/inspection_rules
Lists all inspection rules.
.. versionadded:: 1.96
Inspection Rules API was introduced.
Normal response codes: 200
Error response codes: 400, 401, 403, 404
Request
-------
.. rest_parameters:: parameters.yaml
- detail: detail
- phase: req_inspection_rule_phase
Response Parameters
-------------------
.. rest_parameters:: parameters.yaml
- uuid: uuid
- description: inspection_rule_description
- phase: inspection_rule_phase
- priority: inspection_rule_priority
- sensitive: inspection_rule_sensitive
- created_at: created_at
- updated_at: updated_at
- links: links
- conditions: inspection_rule_conditions
- actions: inspection_rule_actions
Response Example
----------------
**Example inspection rule list response:**
.. literalinclude:: samples/inspection-rule-list-response.json
:language: javascript
**Example detailed inspection rule list response:**
.. literalinclude:: samples/inspection-rule-detail-response.json
:language: javascript
Show Inspection Rule Details
============================
.. rest_method:: GET /v1/inspection_rules/{rule_id}
Shows details for an inspection rule.
.. versionadded:: 1.96
Inspection Rules API was introduced.
Normal response codes: 200
Error response codes: 400, 401, 403, 404
Request
-------
.. rest_parameters:: parameters.yaml
- rule_id: inspection_rule_ident
Response Parameters
-------------------
.. rest_parameters:: parameters.yaml
- uuid: uuid
- description: inspection_rule_description
- conditions: inspection_rule_conditions
- actions: inspection_rule_actions
- phase: inspection_rule_phase
- priority: inspection_rule_priority
- sensitive: inspection_rule_sensitive
- created_at: created_at
- updated_at: updated_at
- links: links
Response Example
----------------
.. literalinclude:: samples/inspection-rule-show-response.json
:language: javascript
Update an Inspection Rule
=========================
.. rest_method:: PATCH /v1/inspection_rules/{rule_id}
Update an inspection rule.
.. versionadded:: 1.96
Inspection Rules API was introduced.
Normal response code: 200
Error response codes: 400, 401, 403, 404, 409
Request
-------
The BODY of the PATCH request must be a JSON PATCH document, adhering to
`RFC 6902 <https://tools.ietf.org/html/rfc6902>`_.
.. rest_parameters:: parameters.yaml
- rule_id: inspection_rule_ident
.. literalinclude:: samples/inspection-rule-update-request.json
:language: javascript
Response
--------
.. rest_parameters:: parameters.yaml
- uuid: uuid
- description: inspection_rule_description
- conditions: inspection_rule_conditions
- actions: inspection_rule_actions
- phase: inspection_rule_phase
- priority: inspection_rule_priority
- sensitive: inspection_rule_sensitive
- created_at: created_at
- updated_at: updated_at
- links: links
.. literalinclude:: samples/inspection-rule-update-response.json
:language: javascript
Delete Inspection Rule
======================
.. rest_method:: DELETE /v1/inspection_rules/{rule_id}
Deletes an inspection rule.
.. versionadded:: 1.96
Inspection Rules API was introduced.
Normal response codes: 204
Error response codes: 400, 401, 403, 404
Request
-------
.. rest_parameters:: parameters.yaml
- rule_id: inspection_rule_ident
Delete All Inspection Rules
===========================
.. rest_method:: DELETE /v1/inspection_rules
Deletes all non-built-in inspection rules.
.. versionadded:: 1.96
Inspection Rules API was introduced.
Normal response codes: 204
Error response codes: 400, 401, 403

View File

@ -33,6 +33,7 @@
.. include:: baremetal-api-v1-nodes-history.inc
.. include:: baremetal-api-v1-nodes-inventory.inc
.. include:: baremetal-api-v1-shards.inc
.. include:: baremetal-api-v1-inspection-rules.inc
.. NOTE(dtantsur): keep chassis close to the end since it's semi-deprecated
.. include:: baremetal-api-v1-chassis.inc
.. NOTE(dtantsur): keep misc last, since it covers internal API

View File

@ -1156,6 +1156,106 @@ inspection_finished_at:
in: body
required: true
type: string
inspection_rule_action_args:
description: |
A list (in the sense of Python ``*args``)
or a dict (in the sense of Python ``**kwargs``) with arguments for
the action operator.
in: body
required: true
type: array
inspection_rule_action_loop:
description: |
This is an Ansible-style loop field. It contains a list or dictionary
of items to iterate over for the same action.
in: body
required: false
type: array
inspection_rule_action_op:
description: |
The operator to execute with specified arguments when conditions are met.
in: body
required: true
type: string
inspection_rule_actions:
description: |
A list of actions to run during inspection. An action is a dictionary
or list, with required keys 'op' and 'args', and optional key 'loop'.
in: body
required: true
type: array
inspection_rule_condition_args:
description: |
A list (in the sense of Python ``*args``)
or a dict (in the sense of Python ``**kwargs``) with arguments for
the condition operator.
in: body
required: true
type: array
inspection_rule_condition_loop:
description: |
This is an Ansible-style loop field. It contains a list or dictionary
of items to iterate over for the same condition.
in: body
required: false
type: array
inspection_rule_condition_multiple:
description: |
Determines how the results of all loop iterations are combined, whether
a condition is returned as true if 'any' check passes,
or only when 'all'; the 'first', or the 'last' check is true.
in: body
required: false
type: string
inspection_rule_condition_op:
description: |
The operator to run conditions by, with specified arguments.
in: body
required: true
type: string
inspection_rule_conditions:
description: |
A list of conditions to check before applying the rule. A
condition is a dictionary or list, with required keys 'op' and 'args', and
optional keys 'loop' and 'multiple'.
in: body
required: false
type: array
inspection_rule_description:
description: |
Informational text about this rule.
in: body
required: false
type: string
inspection_rule_ident:
description: |
The UUID of the inspection rule.
in: body
required: false
type: string
inspection_rule_phase:
description: |
Specifies the phase when the rule should run, defaults to 'main'.
in: body
required: false
type: string
inspection_rule_priority:
description: |
A non-negative integer priority for the rule. Specifies the rule's
precedence level during execution. Priorities between 0 and 9999 can be
used by all rules, negative value and values above 10000 are reserved for
built-in rules. The default priority is 0.
in: body
required: false
type: int
inspection_rule_sensitive:
description: |
Indicates whether the rule contains sensitive information. A sensitive
rule will also have the ability to see sensitive fields on inspection
data.
in: body
required: false
type: string
inspection_started_at:
description: |
The UTC date and time when the hardware inspection was started,
@ -1735,6 +1835,12 @@ req_inspect_interface:
in: body
required: false
type: string
req_inspection_rule_phase:
description: |
Specifies the phase when the rule should run, defaults to 'main'.
in: body
required: false
type: string
req_instance_info:
description: |
Information used to customize the deployed image. May include root partition

View File

@ -0,0 +1,34 @@
{
"description": "BMC credentials",
"phase": "main",
"priority": 100,
"sensitive": true,
"conditions": [
{
"op": "contains",
"args": {"value": "{inventory[system_vendor][manufacturer]}", "regex": "(?i)dell"}
},
{
"op": "is-true",
"args": {"value": "{node.auto_discovered}"}
}
],
"actions": [
{
"op": "set-attribute",
"args": {"path": "/driver", "value": "idrac"}
},
{
"op": "set-attribute",
"args": {"path": "driver_info.redfish_address", "value": "https://{inventory[bmc_address]}"}
},
{
"op": "set-attribute",
"args": {"path": "/driver_info/redfish_username", "value": "admin"}
},
{
"op": "set-attribute",
"args": {"path": "/driver_info/redfish_password", "value": "password"}
}
]
}

View File

@ -0,0 +1,21 @@
{
"created_at": "2025-03-18T22:28:48.643434+11:11",
"description": "BMC credentials",
"phase": "main",
"priority": 100,
"sensitive": true,
"actions": null,
"conditions": null,
"links": [
{
"href": "http://10.60.253.180:6385/v1/inspection_rules/783bf33a-a8e3-1e23-a645-1e95a1f95186",
"rel": "self"
},
{
"href": "http://10.60.253.180:6385/inspection_rules/783bf33a-a8e3-1e23-a645-1e95a1f95186",
"rel": "bookmark"
}
],
"updated_at": null,
"uuid": "783bf33a-a8e3-1e23-a645-1e95a1f95186"
}

View File

@ -0,0 +1,43 @@
{
"inspection_rules": [
{
"created_at": "2025-03-14T15:37:29.542187+00:00",
"description": "Set properties on discovered data",
"phase": "main",
"priority": 50,
"sensitive": false,
"conditions": [
{
"op": "is-true",
"args": {"value": "{inventory[cpu][count]}"}
}
],
"actions": [
{
"op": "set-attribute",
"args": {"path": "/properties/cpus", "value": "{inventory[cpu][count]}"}
},
{
"op": "set-attribute",
"args": {"path": "/properties/memory_mb", "value": "{inventory[memory][physical_mb]}"}
},
{
"op": "set-attribute",
"args": {"path": "/properties/cpu_arch", "value": "{inventory[cpu][architecture]}"}
}
],
"links": [
{
"href": "http://10.60.253.180:6385/v1/inspection_rules/75a6c1f7-2de0-47b3-9c54-8e6ef3a27bcd",
"rel": "self"
},
{
"href": "http://10.60.253.180:6385/inspection_rules/75a6c1f7-2de0-47b3-9c54-8e6ef3a27bcd",
"rel": "bookmark"
}
],
"updated_at": null,
"uuid": "783bf33a-a8e3-1e23-a645-1e95a1f95186"
}
]
}

View File

@ -0,0 +1,55 @@
{
"inspection_rules": [
{
"description": "BMC credentials",
"phase": "main",
"priority": 100,
"sensitive": true,
"links": [
{
"href": "http://10.60.253.180:6385/v1/inspection_rules/783bf33a-a8e3-1e23-a645-1e95a1f95186",
"rel": "self"
},
{
"href": "http://10.60.253.180:6385/inspection_rules/783bf33a-a8e3-1e23-a645-1e95a1f95186",
"rel": "bookmark"
}
],
"uuid": "783bf33a-a8e3-1e23-a645-1e95a1f95186"
},
{
"description": "Set properties on discovered data",
"phase": "main",
"priority": 50,
"sensitive": false,
"links": [
{
"href": "http://10.60.253.180:6385/v1/inspection_rules/1f3ee449-08cd-9e3f-e1e5-9cfda674081a",
"rel": "self"
},
{
"href": "http://10.60.253.180:6385/inspection_rules/1f3ee449-08cd-9e3f-e1e5-9cfda674081a",
"rel": "bookmark"
}
],
"uuid": "1f3ee449-08cd-9e3f-e1e5-9cfda674081a"
},
{
"description": "Memory systems",
"phase": "main",
"priority": 0,
"sensitive": false,
"links": [
{
"href": "http://10.60.253.180:6385/v1/inspection_rules/210055f4-7367-ff8d-ae42-f4f9e8e85e8a",
"rel": "self"
},
{
"href": "http://10.60.253.180:6385/inspection_rules/210055f4-7367-ff8d-ae42-f4f9e8e85e8a",
"rel": "bookmark"
}
],
"uuid": "210055f4-7367-ff8d-ae42-f4f9e8e85e8a"
}
]
}

View File

@ -0,0 +1,39 @@
{
"created_at": "2025-03-18T22:28:48.643434+11:11",
"description": "Set properties on discovered data",
"phase": "main",
"priority": 50,
"sensitive": false,
"conditions": [
{
"op": "is-true",
"args": {"value": "{inventory[cpu][count]}"}
}
],
"actions": [
{
"op": "set-attribute",
"args": {"path": "/properties/cpus", "value": "{inventory[cpu][count]}"}
},
{
"op": "set-attribute",
"args": {"path": "/properties/memory_mb", "value": "{inventory[memory][physical_mb]}"}
},
{
"op": "set-attribute",
"args": {"path": "/properties/cpu_arch", "value": "{inventory[cpu][architecture]}"}
}
],
"links": [
{
"href": "http://10.60.253.180:6385/v1/inspection_rules/1f3ee449-08cd-9e3f-e1e5-9cfda674081a",
"rel": "self"
},
{
"href": "http://10.60.253.180:6385/inspection_rules/1f3ee449-08cd-9e3f-e1e5-9cfda674081a",
"rel": "bookmark"
}
],
"updated_at": null,
"uuid": "1f3ee449-08cd-9e3f-e1e5-9cfda674081a"
}

View File

@ -0,0 +1,28 @@
[
{
"path": "/description",
"value": "Updated rule for setting hardware properties",
"op": "replace"
},
{
"path": "/priority",
"value": 75,
"op": "replace"
},
{
"path": "/conditions/0",
"value": {
"op": "is-true",
"args": {"value": "{inventory[cpu][count]}"}
},
"op": "replace"
},
{
"path": "/actions/-",
"value": {
"op": "set-attribute",
"args": {"path": "/properties/local_gb", "value": "{inventory[disks][0][size]}"}
},
"op": "add"
}
]

View File

@ -0,0 +1,43 @@
{
"created_at": "2025-03-23T22:28:48.643434+11:11",
"description": "Updated rule for setting hardware properties",
"phase": "main",
"priority": 75,
"sensitive": false,
"conditions": [
{
"op": "is-true",
"args": {"value": "{inventory[cpu][count]}"}
}
],
"actions": [
{
"op": "set-attribute",
"args": {"path": "/properties/cpus", "value": "{inventory[cpu][count]}"}
},
{
"op": "set-attribute",
"args": {"path": "/properties/memory_mb", "value": "{inventory[memory][physical_mb]}"}
},
{
"op": "set-attribute",
"args": {"path": "/properties/cpu_arch", "value": "{inventory[cpu][architecture]}"}
},
{
"op": "set-attribute",
"args": {"path": "/properties/local_gb", "value": "{inventory[disks][0][size]}"}
}
],
"links": [
{
"href": "http://10.60.253.180:6385/v1/inspection_rules/1f3ee449-08cd-9e3f-e1e5-9cfda674081a",
"rel": "self"
},
{
"href": "http://10.60.253.180:6385/inspection_rules/1f3ee449-08cd-9e3f-e1e5-9cfda674081a",
"rel": "bookmark"
}
],
"uuid": "1f3ee449-08cd-9e3f-e1e5-9cfda674081a",
"updated_at": "2025-03-24T11:42:18.763029+00:00"
}

View File

@ -8,9 +8,7 @@ Overview
Inspection allows Bare Metal service to discover required node properties
once required ``driver_info`` fields (for example, IPMI credentials) are set
by an operator. Inspection will also create the Bare Metal service ports for the
discovered ethernet MACs. Operators will have to manually delete the Bare Metal
service ports for which physical media is not connected. This is required due
to the `bug 1405131 <https://bugs.launchpad.net/ironic/+bug/1405131>`_.
discovered ethernet MACs.
There are three kinds of inspection supported by Bare Metal service:

View File

@ -31,6 +31,161 @@ ironic-inspector_ service.
pxe_filter
migration
Inspection rules have now been migrate into Ironic as of 2025.1 "Epoxy"
release. This does not include support for reapplying inspection on
already stored data, nor does it support the ``"scope"`` field.
The scope field allowed a rule to be applied only to specific nodes with
matching scope value rather than all nodes where conditions are met.
:ironic-inspector-doc:`Inspection rules <user/usage.html#introspection-rules>`
Inspection Rules
----------------
.. _inspection_rules:
An inspection rule consists of conditions to check, and actions to run.
If conditions evaluate to true on the inspection data, then actions are
run on a node.
Ironic provides an API to manage such rules. There are also built-in rules
which are pre-saved and loaded from a YAML file and cannot be CRUD through
the API.
Available conditions and actions are defined by an extendedable set of
plugins.
Refer to the
`Ironic API reference for inspection rules <https://docs.openstack.org/api-ref/baremetal/#inspection_rules-inspection_rules>`_
for information on how to CRUD inspection rules.
Actions & Conditions
~~~~~~~~~~~~~~~~~~~~
Conditions and actions have the same base structure:
* ``op`` - operation: either boolean (conditions) or an action (actions).
* ``args`` - a list (in the sense of Python ``*args``)
or a dict (in the sense of Python ``**kwargs``) with arguments.
Conditions
^^^^^^^^^^
Available conditions include:
* ``is-true(value)`` - Check if value evaluates to boolean True.
This operator supports booleans, non-zero numbers and strings "yes", "true".
* ``is-false(value)`` - Check if value evaluates to boolean False.
Supports booleans, zero, None and strings "no", "false".
* ``is-none(value)`` - Check if value is None.
* ``is-empty(value)`` - Check if value is None or an empty string,
list or a dictionary.
* ``eq/lt/gt(*values, *, force_strings=False)`` - Check if all values are
equal, less/greater than. If force_strings, all values will be converted
to strings first before the check.
* ``in-net(address, subnet)`` - Check if the given address is in the provided
subnet.
* ``contains(value, regex)`` - Check if the value contains the given regular
expression.
* ``matches(value, regex)`` - Check if the value fully matches the given
regular expression.
* ``one-of(value, values)`` - Check if the value is in the provided list.
Similar to contains, but also works for non-string values.
To check for the inverse of any of these conditions, prefix the operator with
an exclamation mark (with an optional space) before the op. E.g.
``eq`` - ``!eq``.
Actions
^^^^^^^
Available actions include:
* ``fail(msg)`` - Fail inspection with the given message.
* ``set-plugin-data(path, value)`` - Set a value in the plugin data.
* ``extend-plugin-data(path, value, *, unique=False)`` - Treat a value in the
plugin data as a list, append to it. If unique is True, do not append if the
item exists.
* ``unset-plugin-data(path)`` - Unset a value in the plugin data.
* ``log(msg, level="info")`` - Write the message to the Ironic logs.
* ``set-attribute(path, value)`` - Set the given path
(in the sense of JSON patch) to the value.
* ``extend-attribute(path, value, *, unique=False)`` - Treat the given path
as a list, append to it.
* ``del-attribute(path)`` - Unset the given path. Fails on invalid node
attributes, but does not fail on missing subdict fields.
* ``set-port-attribute(port_id, path, value)`` - Set value on the port
identified by a MAC or a UUID.
* ``extend-port-attribute(port_id, path, value, *, unique=False)`` - Treat the
given path on the port as a list, append to it.
* ``del-port-attribute(port_id, path)`` - Unset value on the port identified
by a MAC or a UUID.
Loops
^^^^^
Both conditions and actions accept an optional ``loop`` argument of list of
items to iterate over for the same condition or action.
The ``loop`` field supports an Ansible-style loop (for reference, see
`Ansible loops documentation <https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_loops.html>`_
).
In conditions, there's an additional (and optional) ``multiple`` field which is
only applicable when the loop field is present. It determines how the results
of all loop iterations are combined:
* ``any`` (default) - returns ``True`` if any iteration's result is ``True``
* ``all`` - returns ``True`` only if all iterations' results are ``True``
* ``first`` - returns the result of the first iteration only, skipping
remaining iterations if the first is ``True``
* ``last`` - uses only the result from the last iteration, effectively
ignoring previous iterations
For example, this condition check will return true if at any time of the
iteration, the 'system' is any of the models in the ``loop`` list:
.. code-block:: yaml
- op: eq
args: ["{inventory.system.product_name}", "{item}"]
loop: ["HPE ProLiant DL380 Gen10", "PowerEdge R640", "Cisco UCS"]
multiple: any
Whereas in actions, each iteration of the loop executes same action with the
current item value.
Example of setting multiple attributes using loop:
.. code-block:: yaml
- op: set-attribute
args: ["{item[path]}", "{item[value]}"]
loop:
- {path: "/driver_info/ipmi_username", value: "admin"}
- {path: "/driver_info/ipmi_password", value: "password"}
- {path: "/driver_info/ipmi_address", value: "{inventory[bmc_address]}"}
.. note::
Both dot (``"driver_info.ipmi_username"``) and
slash (``"driver_info/ipmi_username"``) notation paths are supported.
Variable Interpolation
^^^^^^^^^^^^^^^^^^^^^^
{"action": "set-attribute", "path": "/driver_info/ipmi_address",
"value": "{data[inventory][bmc_address]}"}
On a rule execution, values enclosed with braces, usually ``value``, ``msg``,
``address``, and ``subnet`` fields in both actions and conditions, will be
treated as replacement fields and formatted to a string using
`python string formatting notation <https://docs.python.org/3/library/string.html#formatspec>`_.
If the value of any of these keys is a dict or list, strings nested at any
level within the structure will be recursively formatted as well::
{"action": "set-attribute", "path": "/properties/root_device",
"value": {"serial": "{data[root_device][serial]}"}}
Configuration
-------------

View File

@ -32,8 +32,7 @@ This list currently includes:
<https://docs.openstack.org/python-ironic-inspector-client/latest/cli/index.html#list-interface-data>`_.
:ironic-inspector-doc:`Inspection rules <user/usage.html#introspection-rules>`
are also currently not implemented but are planned for the 2024.2 release or
later.
have now been implemented as of 2025.1 "Epoxy" release.
New defaults
~~~~~~~~~~~~