Merge "Add api-call
action for ironic inspection rule"
This commit is contained in:
@ -11,6 +11,9 @@
|
||||
# under the License.
|
||||
|
||||
import abc
|
||||
import requests
|
||||
from requests.adapters import HTTPAdapter
|
||||
from urllib3.util.retry import Retry
|
||||
|
||||
from oslo_log import log
|
||||
|
||||
@ -39,6 +42,7 @@ ACTIONS = {
|
||||
"set-port-attribute": "SetPortAttributeAction",
|
||||
"extend-port-attribute": "ExtendPortAttributeAction",
|
||||
"del-port-attribute": "DelPortAttributeAction",
|
||||
"api-call": "CallAPIHookAction",
|
||||
}
|
||||
|
||||
|
||||
@ -416,3 +420,46 @@ class DelPortAttributeAction(ActionBase):
|
||||
'path': path, 'port_id': port_id, 'exc': str(exc)}
|
||||
LOG.error(msg)
|
||||
raise exception.RuleActionExecutionFailure(reason=msg)
|
||||
|
||||
|
||||
class CallAPIHookAction(ActionBase):
|
||||
FORMATTED_ARGS = ['url']
|
||||
OPTIONAL_PARAMS = [
|
||||
'headers', 'proxies', 'timeout', 'retries', 'backoff_factor'
|
||||
]
|
||||
|
||||
def __call__(self, task, url, headers=None, proxies=None,
|
||||
timeout=5, retries=3, backoff_factor=0.3):
|
||||
try:
|
||||
timeout = float(timeout)
|
||||
if timeout <= 0:
|
||||
raise ValueError("timeout must be greater than zero")
|
||||
retries = int(retries)
|
||||
backoff_factor = float(backoff_factor)
|
||||
retry_strategy = Retry(
|
||||
total=retries,
|
||||
backoff_factor=backoff_factor,
|
||||
status_forcelist=[429, 500, 502, 503, 504],
|
||||
allowed_methods=["GET"],
|
||||
raise_on_status=False
|
||||
)
|
||||
adapter = HTTPAdapter(max_retries=retry_strategy)
|
||||
session = requests.Session()
|
||||
session.mount("http://", adapter)
|
||||
session.mount("https://", adapter)
|
||||
request_kwargs = {}
|
||||
if headers:
|
||||
request_kwargs['headers'] = headers
|
||||
if proxies:
|
||||
request_kwargs['proxies'] = proxies
|
||||
response = session.get(url, timeout=timeout, **request_kwargs)
|
||||
response.raise_for_status()
|
||||
except ValueError as exc:
|
||||
msg = _("Invalid parameter: %s") % exc
|
||||
LOG.error(msg)
|
||||
raise exception.RuleActionExecutionFailure(reason=msg)
|
||||
except requests.exceptions.RequestException as exc:
|
||||
msg = _("Request to %(url)s failed: %(exc)s") % {
|
||||
'url': url, 'exc': exc}
|
||||
LOG.error(msg)
|
||||
raise exception.RuleActionExecutionFailure(reason=msg)
|
||||
|
@ -776,6 +776,27 @@ class TestActions(TestInspectionRules):
|
||||
self.assertEqual('192.168.1.100',
|
||||
task.node.driver_info['ipmi_address'])
|
||||
|
||||
@mock.patch(
|
||||
'ironic.common.inspection_rules.actions.requests.Session',
|
||||
autospec=True)
|
||||
def test_call_api_hook_action_success(self, mock_session):
|
||||
"""Test CallAPIHookAction successfully calls an API."""
|
||||
mock_session_instance = mock_session.return_value
|
||||
mock_response = mock.Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.raise_for_status.return_value = None
|
||||
mock_session_instance.get.return_value = mock_response
|
||||
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
action = inspection_rules.actions.CallAPIHookAction()
|
||||
test_url = 'http://example.com/simple_hook'
|
||||
action(task, url=test_url)
|
||||
mock_session_instance.mount.assert_any_call("http://", mock.ANY)
|
||||
mock_session_instance.mount.assert_any_call("https://", mock.ANY)
|
||||
mock_session_instance.get.assert_called_once_with(
|
||||
test_url, timeout=5)
|
||||
mock_response.raise_for_status.assert_called_once()
|
||||
|
||||
|
||||
class TestShallowMask(TestInspectionRules):
|
||||
def setUp(self):
|
||||
|
@ -0,0 +1,36 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Added a new 'api-call' action plugin for Ironic inspection rules.
|
||||
|
||||
This action allows triggering an HTTP GET request to a given URL when a
|
||||
rule matches successfully during node inspection. It is useful for
|
||||
integrating with external systems such as webhooks, alerting, or
|
||||
automation tools.
|
||||
|
||||
The following options are supported:
|
||||
|
||||
* url (required): The HTTP endpoint to call
|
||||
* timeout (optional, default: 5): Timeout in seconds
|
||||
* retries (optional, default: 3): Number of retries on failure
|
||||
* backoff_factor (optional, default: 0.3): Delay factor for retry attempts
|
||||
* headers, proxies (optional): Additional request configuration
|
||||
|
||||
Retry applies to status codes 429, 500, 502, 503, and 504.
|
||||
|
||||
Example rule::
|
||||
|
||||
[
|
||||
{
|
||||
"description": "Trigger webhook after node inspection",
|
||||
"actions": [
|
||||
{
|
||||
"action": "api-call",
|
||||
"url": "http://example.com/hook",
|
||||
"timeout": 10,
|
||||
"retries": 5,
|
||||
"backoff_factor": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
Reference in New Issue
Block a user