diff --git a/docs/rest_api.rst b/docs/rest_api.rst index 6299dfa65..055788bed 100644 --- a/docs/rest_api.rst +++ b/docs/rest_api.rst @@ -501,7 +501,9 @@ Obtain the tree of all Suites * - Payload - *empty* * - Response - - See below for details. + - See :ref:`below ` for details. + +.. _response with suite tree: Response with Suite tree """""""""""""""""""""""" @@ -699,7 +701,7 @@ Obtain the tree of a Node * - Payload - *empty* * - Response - - Same as `Suite tree `_ + - Same as :ref:`Suite tree `. Endpoint :code:`/v1/suites/{path}/definition` --------------------------------------------- @@ -943,10 +945,86 @@ Obtain all Node attributes * - Payload - *empty* * - Response - - :code:`{"meters":[...],"variables":[...]}` + - See :ref:`below ` for details * - Example - :code:`curl https://localhost:8080/v1/suites/path/to/node/attributes` +.. _response with node attributes: + +Response with Node attributes +""""""""""""""""""""""""""""" + +The response to a request for node attributes has the following JSON format. +Notice how the node variables are separated from inherited variables. +The inherited variables grouped by ancestor node, each identified by the node name and absolute path. + +.. code-block:: text + + { + "path": "..." + + "meters": [ { ... }, ... ], + "limits": [ { ... }, ... ], + "inlimits": [ { ... }, ... ], + "events": [ { ... }, ... ], + "labels": [ { ... }, ... ], + "dates": [ { ... }, ... ], + "days": [ { ... }, ... ], + "crons": [ { ... }, ... ], + "times": [ { ... }, ... ], + "todays": [ { ... }, ... ], + "repeat": { ... }, + "trigger": { ... }, + "complete": { ... }, + "flag": { ... }, + "late": { ... }, + "zombies": [ { ... }, ... ], + "generics": [ { ... }, ... ], + "queues": [ { ... }, ... ], + "autocancel": { ... }, + "autoarchive": { ... }, + "autorestore": { ... }, + "avisos": [ { ... }, ... ], + "mirrors" : [ { ... }, ... ], + "variables": [ + { + "name": "..." + "value": "...", + "const": true|false + }, + { + "name": "..." + "value": "...", + "generated": true # only present if the variable is generated + "const": true|false + }, + ... + ] + "inherited_variables": [ + { + "name": "......" + "path": "......", + "variables: [ + { + "name": "..." + "value": "...", + "type": "variable", + "const": true|false + }, + { + "name": "..." + "value": "...", + "type": "variable", + "generated": true # only present if the variable is generated + "const": true|false + }, + ... + ] + }, + ... + } + } + Update a Node attribute ^^^^^^^^^^^^^^^^^^^^^^^ @@ -1276,8 +1354,8 @@ Create a new Server attribute * - Response - :code:`{"message":"Attribute added successfully"}` -Obtain a Server attribute -^^^^^^^^^^^^^^^^^^^^^^^^^ +Obtain all Server attributes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. list-table:: :stub-columns: 1 diff --git a/libs/rest/src/ecflow/http/ApiV1Impl.cpp b/libs/rest/src/ecflow/http/ApiV1Impl.cpp index 0e641c933..1ae0cb453 100644 --- a/libs/rest/src/ecflow/http/ApiV1Impl.cpp +++ b/libs/rest/src/ecflow/http/ApiV1Impl.cpp @@ -228,6 +228,24 @@ ojson get_server_attributes() { return j; } +static ojson get_node_variables_array(const Node& node) { + auto container = ojson::array(); + // Collect 'normal' variables + for (const auto& variable : node.variables()) { + ojson object; + to_json(object, variable); + container.push_back(object); + } + // ... and generated variables + for (const auto& variable : node.gen_variables()) { + ojson object; + to_json(object, variable); + object["generated"] = true; + container.push_back(object); + } + return container; +} + ojson get_node_attributes(const std::string& path) { ojson j; @@ -237,7 +255,6 @@ ojson get_node_attributes(const std::string& path) { j["limits"] = node->limits(); j["inlimits"] = node->inlimits(); j["events"] = node->events(); - j["variables"] = node->variables(); j["labels"] = node->labels(); j["dates"] = node->dates(); j["days"] = node->days(); @@ -259,30 +276,26 @@ ojson get_node_attributes(const std::string& path) { j["avisos"] = node->avisos(); j["mirrors"] = node->mirrors(); - { - // Collect 'normal' variables - auto vars = node->variables(); - // ... and generated variables - node->gen_variables(vars); + j["variables"] = get_node_variables_array(*node); - j["variables"] = vars; - } - - apply_to_parents(node->parent(), [&j](const Node* n) { - // Collect 'normal' variables - auto vars = n->variables(); - // ... and generated variables - n->gen_variables(vars); + { + auto inherited = ojson::array(); - j["inherited_variables"][n->name()] = vars; - }); + // Collect 'inherited' variables from parents + apply_to_parents(node->parent(), [&inherited](const Node* n) { + inherited.push_back(ojson::object( + {{"name", n->name()}, {"path", n->absNodePath()}, {"variables", get_node_variables_array(*n)}})); + }); - auto server_variables = get_defs()->server().server_variables(); - auto user_variables = get_defs()->server().user_variables(); + // ... and from server + auto server_variables = get_defs()->server().server_variables(); + auto user_variables = get_defs()->server().user_variables(); + server_variables.insert(server_variables.end(), user_variables.begin(), user_variables.end()); - server_variables.insert(server_variables.end(), user_variables.begin(), user_variables.end()); + inherited.push_back(ojson::object({{"name", "server"}, {"path", "/"}, {"variables", server_variables}})); - j["inherited_variables"]["server"] = server_variables; + j["inherited_variables"] = inherited; + } return j; }