Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 5.13.8 #164

Merged
merged 8 commits into from
Mar 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ endif()

find_package( ecbuild 3.4 REQUIRED HINTS ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../ecbuild /workspace/ecbuild) # Before project()

project( ecflow LANGUAGES CXX VERSION 5.13.7 )
project( ecflow LANGUAGES CXX VERSION 5.13.8 )

# Important: the project version is used, as generated CMake variables, to filter .../ecflow/core/ecflow_version.h.in

Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@


def get_ecflow_version():
version = "5.13.7"
version = "5.13.8"
ecflow_version = version.split(".")
print("Extracted ecflow version '" + str(ecflow_version))
return ecflow_version
Expand Down
12 changes: 11 additions & 1 deletion docs/glossary.rst
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@
- :code:`polling`, the value (in seconds) used to periodically contact the Aviso server
- :code:`auth`, the location to the Aviso authentication credentials file

.. note::

The `listener` parameter is expected to be a valid single line JSON string, enclosed in single quotes.

The value of the properties :code:`url`, :code:`schema`, :code:`polling`,
and :code:`auth` can be composed of :term:`Variables<variable>`. When
these properties are not provided, the following default values are used:
Expand All @@ -92,7 +96,9 @@
can be reloaded (without unqueuing the Task) by issuing an Alter change command with
the value :code:`reload` to the relevant Aviso attribute.

The authentication credentials file is expected to be in JSON format, following the `ECMWF Web API <https://www.ecmwf.int/en/computing/software/ecmwf-web-api>`_:
The authentication credentials file is expected to be in JSON format, following
the `ECMWF Web API <https://www.ecmwf.int/en/computing/software/ecmwf-web-api>`_
(this is conventionally stored in a file located at `$HOME/.ecmwfapirc`):

.. code-block:: json

Expand All @@ -104,6 +110,10 @@

Only the fields :code:`url`, :code:`key`, and :code:`email` are required; any additional fields are ignored.

The Aviso schema file is a JSON file that defines the event listener schema. This is used by both Aviso server
and client (thus, by ecFlow) to define the valid event types and request parameters used when polling for
notifications. The schema file path must be provided to the `schema` option (or via the `ECF_AVISO_SCHEMA` variable).

check point
The check point file is like the :term:`suite definition`, but includes all the state information.

Expand Down
27 changes: 21 additions & 6 deletions docs/python_api/AvisoAttr.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,41 @@ An :term:`aviso` attribute, assigned to a :term:`node`, represents an external t
Although :term:`aviso` attributes can be set at any level (Suite, Family, Task), it only makes sense to assign aviso attributes to tasks, and only one aviso attribute per node is allowed.


Constructor::

AvisoAttr(name, listener, ...)
Constructors::

AvisoAttr(name, listener) (1)
AvisoAttr(name, listener, url)
AvisoAttr(name, listener, url, schema)
AvisoAttr(name, listener, url, schema, polling)
AvisoAttr(name, listener, url, schema, polling, auth)
with:
string name: The Aviso attribute name
string listener: The Aviso listener configuration (in JSON format)
string url: The URL used to contact the Aviso server
string schema: The path to the Aviso schema
string polling: The polling interval used to contact the Aviso server
string auth: The path to the Aviso Authentication credentials

Note: Default values, based on %ECF_AVISO_...% variables, will be used for the calls where
the parameters url, schema, polling, and auth are not provided

We suggest to specify :code:`%ECF_AVISO_***%` variables once (at suite level), and then create the
Aviso attributes passing just the name and the listener definition as per call `(1)`.

.. note:: The `listener` parameter is expected to be a valid single line JSON string, enclosed in single quotes.
As a convenience, missing surrounding single quotes are detected and will automatically be added.

Details regarding the format of `listener` are in the section describing the :term:`aviso` attribute.


Usage:

.. code-block:: python

t1 = Task('t1',
AvisoAttr('name', '{...}', 'http://aviso.com', '60', '/path/to/auth'))
t1 = Task('t1', AvisoAttr('name', "'{...}'"))

t2 = Task('t2')
t2.add_aviso('name', '{...}', 'http://aviso.com', '60', '/path/to/auth')
t2.add_aviso('name', "'{...}'", 'http://aviso.com', '60', '/path/to/auth')

The parameters `url`, `schema`, `polling`, and `auth` are optional

Expand Down
20 changes: 20 additions & 0 deletions docs/release_notes/version_5.13.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,26 @@ Version 5.13 updates
.. role:: jiraissue
:class: hidden

Version 5.13.8
==============

* `Released <https://confluence.ecmwf.int/display/ECFLOW/Releases>`__\ on 2025-03-12

General
-------

- **Fix** correct Aviso notification retrieval after automatic requeueing :jiraissue:`ECFLOW-2010`

Python
------

- **Fix** correct quote handling for ecflow.AvisoAttr listener :jiraissue:`ECFLOW-2011`

Documentation
-------------

- **Improvement** clarify use of schema for ecFlow Aviso attribute :jiraissue:`ECFLOW-2008`
- **Improvement** clarify how to define ecFlow Aviso authentication :jiraissue:`ECFLOW-2008`

Version 5.13.7
==============
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,28 @@ Follow the recommended practice of defining ecFlow :term:`variables<variable>` a
endfamily
endsuite

To enable Aviso authentication, set the `--auth` option (directly or via the `ECF_AVISO_AUTH`
variable) to the path of the JSON file containing the authentication credentials, which follows the
`ECMWF Web API <https://www.ecmwf.int/en/computing/software/ecmwf-web-api>`_. The credentials file
is conventionally located at `$HOME/.ecmwfapirc`, with the following content:

.. code-block:: json

{
"url" : "https://api.ecmwf.int/v1",
"key" : "<your-api-key>",
"email" : "<your-email>"
}

The Aviso schema file is a JSON file that defines the event listener schema. This is used by
both Aviso server and client (thus, by ecFlow) to define the valid event types and request
parameters used when polling for notifications. The schema file path must be provided to the
`--schema` option (or via the `ECF_AVISO_SCHEMA` variable).

The Aviso schema, `event_listener_schema.json`, used by ECMWF is available at `<https://github.com/ecmwf/aviso-deployment/tree/main/schema>`_,
and is specific to the Aviso server being used (access is currently restricted; if necessary, please contact
support to request the files).

Define a Suite with an `Aviso` dependent Task
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
22 changes: 16 additions & 6 deletions docs/ug/user_manual/text_based_suite_definition/external/aviso.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@ notification. The options defining the attribute can be provided in any order.
# --auth %ECF_AVISO_AUTH%
# --polling %ECF_AVISO_POLLING%

Notice that the :code:`--listener` option must be surrounded by single quotes,
and is composed as a single line `JSON`. The `JSON` must define two fields:
.. note::

The `listener` parameter is expected to be a valid single line JSON string, enclosed in single quotes.

The listener must define two fields (as per the `Aviso Listerner <https://pyaviso.readthedocs.io/en/latest/guide/define_my_listener.html>`_ definition):

- :code:`event`, specifies the type of Aviso event
- :code:`request`, specifies a dictionary with the parameters used to check for matches of Aviso notifications
Expand All @@ -34,12 +37,19 @@ The following are some examples:
'{ "event": "mars", "request": { "class": "od", "expver": "0001", "domain": "g", "stream": "abcd", "step": 0 } }'

The Authentication credentials, provided via option :code:`--auth`, are
provided in a `JSON` file with the following content:
provided in a `JSON` file with the content following the
`ECMWF Web API <https://www.ecmwf.int/en/computing/software/ecmwf-web-api>`_
(this is conventionally stored in a file located at `$HOME/.ecmwfapirc`):

.. code-block:: json

{
"url": "http://host.int:1234",
"key": "*******************************************************************",
"email": "[email protected]"
"url" : "https://api.ecmwf.int/v1",
"key" : "<your-api-key>",
"email" : "<your-email>"
}

The Aviso schema file is a JSON file that defines the event listener schema. This is used by
both Aviso server and client (thus, by ecFlow) to define the valid event types and request
parameters used when polling for notifications. The schema file path must be provided to the
`--schema` option (or via the `ECF_AVISO_SCHEMA` variable).
1 change: 1 addition & 0 deletions libs/attribute/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ set(test_srcs
# Sources
test/TestAttributes_main.cpp
test/TestAttrSerialization.cpp
test/TestAvisoAttr.cpp
test/TestCron.cpp
test/TestDateAttr.cpp
test/TestDayAttr.cpp
Expand Down
70 changes: 70 additions & 0 deletions libs/attribute/test/TestAvisoAttr.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright 2009- ECMWF.
*
* This software is licensed under the terms of the Apache Licence version 2.0
* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
* In applying this licence, ECMWF does not waive the privileges and immunities
* granted to it by virtue of its status as an intergovernmental organisation
* nor does it submit to any jurisdiction.
*/

#include <string>

#include <boost/test/unit_test.hpp>

#include "ecflow/node/AvisoAttr.hpp"

BOOST_AUTO_TEST_SUITE(U_Attributes)

BOOST_AUTO_TEST_SUITE(T_AvisoAttr)

BOOST_AUTO_TEST_CASE(can_create_aviso_attribute_with_all_parameters) {

using namespace ecf;

auto aviso = AvisoAttr{nullptr,
"A",
R"({ "event": "mars", "request": { "class": "od"} })",
"http://host:port",
"/path/to/schema",
"60",
0,
"/path/to/auth",
"'this is a reason'"};

BOOST_CHECK_EQUAL(aviso.name(), "A");
BOOST_CHECK_EQUAL(aviso.listener(), R"('{ "event": "mars", "request": { "class": "od"} }')");
BOOST_CHECK_EQUAL(aviso.url(), "http://host:port");
BOOST_CHECK_EQUAL(aviso.schema(), "/path/to/schema");
BOOST_CHECK_EQUAL(aviso.auth(), "/path/to/auth");
BOOST_CHECK_EQUAL(aviso.polling(), "60");
BOOST_CHECK_EQUAL(aviso.reason(), "'this is a reason'");
}

BOOST_AUTO_TEST_CASE(can_create_aviso_attribute_ensuring_single_quotes_when_absent) {

using namespace ecf;

// Notice the absence of single quotes, on both the listener and reason
auto aviso = AvisoAttr{nullptr,
"A",
R"({ "event": "mars", "request": { "class": "od"} })",
"http://host:port",
"/path/to/schema",
"60",
0,
"/path/to/auth",
"this is a reason"};

BOOST_CHECK_EQUAL(aviso.name(), "A");
BOOST_CHECK_EQUAL(aviso.listener(), R"('{ "event": "mars", "request": { "class": "od"} }')");
BOOST_CHECK_EQUAL(aviso.url(), "http://host:port");
BOOST_CHECK_EQUAL(aviso.schema(), "/path/to/schema");
BOOST_CHECK_EQUAL(aviso.auth(), "/path/to/auth");
BOOST_CHECK_EQUAL(aviso.polling(), "60");
BOOST_CHECK_EQUAL(aviso.reason(), "'this is a reason'");
}

BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE_END()
30 changes: 24 additions & 6 deletions libs/node/src/ecflow/node/AvisoAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,28 +21,42 @@

namespace ecf {

namespace implementation {

std::string ensure_single_quotes(const AvisoAttr::listener_t listener) {
using namespace std::string_literals;
if (!listener.empty() && listener.front() == '\'' && listener.back() == '\'') {
return listener;
}
else {
return "'"s + listener + "'"s;
}
}

} // namespace implementation

bool AvisoAttr::is_valid_name(const std::string& name) {
return ecf::Str::valid_name(name);
}

AvisoAttr::AvisoAttr(Node* parent,
name_t name,
listener_t listener,
const listener_t& listener,
url_t url,
schema_t schema,
polling_t polling,
revision_t revision,
auth_t auth,
reason_t reason)
const reason_t& reason)
: parent_{parent},
parent_path_{parent ? parent->absNodePath() : ""},
name_{std::move(name)},
listener_{std::move(listener)},
listener_{implementation::ensure_single_quotes(listener)},
url_{std::move(url)},
schema_{std::move(schema)},
polling_{std::move(polling)},
auth_{std::move(auth)},
reason_{std::move(reason)},
reason_{implementation::ensure_single_quotes(reason)},
revision_{revision},
controller_{nullptr} {
if (!ecf::Str::valid_name(name_)) {
Expand Down Expand Up @@ -112,7 +126,9 @@ bool AvisoAttr::isFree() const {

if (notifications.empty()) {
// No notifications, nothing to do -- task continues to wait
SLOG(D, "AvisoAttr: (path: " << this->path() << ", name: " << name_ << ", listener: " << listener_ << "): no notifications found");
SLOG(D,
"AvisoAttr: (path: " << this->path() << ", name: " << name_ << ", listener: " << listener_
<< "): no notifications found");
return false;
}

Expand Down Expand Up @@ -151,7 +167,9 @@ bool AvisoAttr::isFree() const {

ecf::visit_parents(*parent_, [n = this->state_change_no_](Node& node) { node.set_state_change_no(n); });

SLOG(D, "AvisoAttr: (path: " << this->path() << ", name: " << name_ << ", listener: " << listener_ << ") " << std::string{(is_free ? "" : "no ")} + "notifications found");
SLOG(D,
"AvisoAttr: (path: " << this->path() << ", name: " << name_ << ", listener: " << listener_ << ") "
<< std::string{(is_free ? "" : "no ")} + "notifications found");

return is_free;
}
Expand Down
4 changes: 2 additions & 2 deletions libs/node/src/ecflow/node/AvisoAttr.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,13 @@ class AvisoAttr {
AvisoAttr() = default;
AvisoAttr(Node* parent,
name_t name,
listener_t handle,
const listener_t& handle,
url_t url,
schema_t schema,
polling_t polling,
revision_t revision,
auth_t auth,
reason_t reason);
const reason_t& reason);
AvisoAttr(const AvisoAttr& rhs) = default;

AvisoAttr& operator=(const AvisoAttr& rhs) = default;
Expand Down
Loading
Loading