From 158743194580ac8d5b1b2cfa9cac52a9c1394357 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Tue, 13 Jun 2023 16:40:33 +0200 Subject: [PATCH] POST /v1/objects: allow array of attrs to undo modifications of --- doc/12-icinga2-api.md | 42 ++++++++++++++++++++++++-- lib/remote/modifyobjecthandler.cpp | 48 +++++++++++++++++++++++++++--- 2 files changed, 83 insertions(+), 7 deletions(-) diff --git a/doc/12-icinga2-api.md b/doc/12-icinga2-api.md index 6b23c607c98..85c9aad867b 100644 --- a/doc/12-icinga2-api.md +++ b/doc/12-icinga2-api.md @@ -890,9 +890,17 @@ curl -k -s -S -i -u root:icinga -H 'Accept: application/json' \ Existing objects must be modified by sending a `POST` request. The following parameters need to be passed inside the JSON body: - Parameters | Type | Description - -----------|------------|--------------------------- - attrs | Dictionary | **Required.** Set specific object attributes for this [object type](09-object-types.md#object-types). +| Parameters | Type | Description | +|----------------|------------|----------------------------------------------------------------------------------------------------------------------------| +| attrs | Dictionary | **Optional.** Set specific object attributes for this [object type](09-object-types.md#object-types). | +| restore\_attrs | Array | **Optional.** Discard modifications of specific object attributes for this [object type](09-object-types.md#object-types). | + +One of the above is required. + +!!! info + + If a particular attribute is given in both sets, + it's first restored and then set to the desired new value. In addition to these parameters a [filter](12-icinga2-api.md#icinga2-api-filters) parameter should be provided. @@ -936,6 +944,34 @@ curl -k -s -S -i -u root:icinga -H 'Accept: application/json' \ } ``` +To undo such modifications to specific object attributes, +list the latter in the `restore_attrs` parameter. E.g.: + +```bash +curl -k -s -S -i -u root:icinga -H 'Accept: application/json' \ + -X POST 'https://localhost:5665/v1/objects/hosts/example.localdomain' \ + -d '{ "restore_attrs": [ "address", "vars.os" ] }, "pretty": true }' +``` + +```json +{ + "results": [ + { + "code": 200.0, + "name": "example.localdomain", + "status": "Attributes updated.", + "type": "Host" + } + ] +} +``` + +Giving `attrs` with the original value would have almost the same effect. +But in this case Icinga would still store that value as a modified attribute, +overriding DSL/Director config (changes). In contrast, `restore_attrs` tells +Icinga to actually forget particular modified attributes, so that changes to +them via Director or plain config are effective again. + ### Deleting Objects You can delete objects created using the API by sending a `DELETE` diff --git a/lib/remote/modifyobjecthandler.cpp b/lib/remote/modifyobjecthandler.cpp index d9a215f5ff5..d6fa98b2e32 100644 --- a/lib/remote/modifyobjecthandler.cpp +++ b/lib/remote/modifyobjecthandler.cpp @@ -64,7 +64,7 @@ bool ModifyObjectHandler::HandleRequest( Value attrsVal = params->Get("attrs"); - if (attrsVal.GetReflectionType() != Dictionary::TypeInstance) { + if (attrsVal.GetReflectionType() != Dictionary::TypeInstance && attrsVal.GetType() != ValueEmpty) { HttpUtility::SendJsonError(response, params, 400, "Invalid type for 'attrs' attribute specified. Dictionary type is required." "Or is this a POST query and you missed adding a 'X-HTTP-Method-Override: GET' header?"); @@ -73,6 +73,23 @@ bool ModifyObjectHandler::HandleRequest( Dictionary::Ptr attrs = attrsVal; + Value restoreAttrsVal = params->Get("restore_attrs"); + + if (restoreAttrsVal.GetReflectionType() != Array::TypeInstance && restoreAttrsVal.GetType() != ValueEmpty) { + HttpUtility::SendJsonError(response, params, 400, + "Invalid type for 'restore_attrs' attribute specified. Array type is required."); + return true; + } + + Array::Ptr restoreAttrs = restoreAttrsVal; + + if (!(attrs || restoreAttrs)) { + HttpUtility::SendJsonError(response, params, 400, + "Missing both 'attrs' and 'restore_attrs'. " + "Or is this a POST query and you missed adding a 'X-HTTP-Method-Override: GET' header?"); + return true; + } + bool verbose = false; if (params) @@ -95,6 +112,26 @@ bool ModifyObjectHandler::HandleRequest( String key; + try { + if (restoreAttrs) { + ObjectLock oLock (restoreAttrs); + + for (auto& attr : restoreAttrs) { + key = attr; + obj->RestoreAttribute(key); + } + } + } catch (const std::exception& ex) { + result1->Set("code", 500); + result1->Set("status", "Attribute '" + key + "' could not be restored: " + DiagnosticInformation(ex, false)); + + if (verbose) + result1->Set("diagnostic_information", DiagnosticInformation(ex)); + + results.push_back(std::move(result1)); + continue; + } + try { if (attrs) { ObjectLock olock(attrs); @@ -103,17 +140,20 @@ bool ModifyObjectHandler::HandleRequest( obj->ModifyAttribute(kv.first, kv.second); } } - - result1->Set("code", 200); - result1->Set("status", "Attributes updated."); } catch (const std::exception& ex) { result1->Set("code", 500); result1->Set("status", "Attribute '" + key + "' could not be set: " + DiagnosticInformation(ex, false)); if (verbose) result1->Set("diagnostic_information", DiagnosticInformation(ex)); + + results.push_back(std::move(result1)); + continue; } + result1->Set("code", 200); + result1->Set("status", "Attributes updated."); + results.push_back(std::move(result1)); }