From 865c6b33c6c044ea07a40fcf2ffe3143d6364893 Mon Sep 17 00:00:00 2001 From: Matias Morales Date: Mon, 2 Dec 2024 15:05:22 -0300 Subject: [PATCH 1/4] Add signal allocation method to requester --- nomad/api/client.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/nomad/api/client.py b/nomad/api/client.py index ebf5991..bd6a814 100644 --- a/nomad/api/client.py +++ b/nomad/api/client.py @@ -304,6 +304,22 @@ def restart_allocation(self, id_): """ return self.request(id_, "restart", method="post").json() + def signal_allocation(self, id_, signal, task=None): + """Send a signal to an allocation or task. + https://www.nomadproject.io/api-docs/allocations#signal-allocation + arguments: + - id_ + - signal (str) + optional_arguments: + - task: (str) Optional, if omitted, the signal will be sent to all tasks in the allocation. + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException + """ + payload = {"Signal": signal, "Task": task} + return self.request(id_, "signal", json=payload, method="post").json() + class gc_allocation(Requester): """ From c381be3545c51d3606ac9f6560edd4ded63ce334 Mon Sep 17 00:00:00 2001 From: Matias Morales Date: Mon, 2 Dec 2024 15:05:58 -0300 Subject: [PATCH 2/4] Add tests for signal allocation --- tests/test_client.py | 45 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/tests/test_client.py b/tests/test_client.py index 84bd076..5330869 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -1,5 +1,6 @@ import pytest import json +import signal import time import os @@ -8,6 +9,21 @@ from flaky import flaky +def get_running_allocation(nomad_setup): + max_iterations = 6 + for _ in range(max_iterations): + try: + return next( + alloc + for alloc in nomad_setup.allocations.get_allocations() + if alloc["ClientStatus"] == "running" + ) + except StopIteration: + # No alloc running + time.sleep(5) + raise ValueError("No allocations running") + + # integration tests requires nomad Vagrant VM or Binary running def test_register_job(nomad_setup): @@ -17,7 +33,6 @@ def test_register_job(nomad_setup): assert "example" in nomad_setup.job max_iterations = 6 - while nomad_setup.job["example"]["Status"] != "running": time.sleep(5) if max_iterations == 0: @@ -70,11 +85,37 @@ def test_read_allocation_stats(nomad_setup): f = nomad_setup.client.allocation.read_allocation_stats(a) +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 9, 1), reason="Not supported in version" +) +def test_signal_allocation(nomad_setup): + alloc_id = get_running_allocation(nomad_setup)["ID"] + nomad_setup.client.allocation.signal_allocation(alloc_id, signal.SIGUSR1.name) + + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 9, 1), reason="Not supported in version" +) +def test_signal_allocation_task(nomad_setup): + allocation = get_running_allocation(nomad_setup) + alloc_id = allocation["ID"] + task = list(allocation["TaskStates"].keys())[0] + nomad_setup.client.allocation.signal_allocation(alloc_id, signal.SIGUSR1.name, task) + + +@pytest.mark.skipif( + tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 9, 1), reason="Not supported in version" +) +def test_signal_allocation_invalid_signal(nomad_setup): + alloc_id = get_running_allocation(nomad_setup)["ID"] + with pytest.raises(nomad.api.exceptions.BaseNomadException, match="invalid signal"): + nomad_setup.client.allocation.signal_allocation(alloc_id, "INVALID-SIGNAL") + + @pytest.mark.skipif( tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 8, 1), reason="Not supported in version" ) def test_gc_all_allocations(nomad_setup): - node_id = nomad_setup.nodes.get_nodes()[0]["ID"] nomad_setup.client.gc_all_allocations.garbage_collect(node_id) nomad_setup.client.gc_all_allocations.garbage_collect() From 2bc7c04b0d193255bb0f256fce9b75d4afb1a630 Mon Sep 17 00:00:00 2001 From: Matias Morales Date: Mon, 2 Dec 2024 15:06:56 -0300 Subject: [PATCH 3/4] Add documentation --- docs/api/allocations.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/docs/api/allocations.md b/docs/api/allocations.md index 4f525af..1e6ac67 100644 --- a/docs/api/allocations.md +++ b/docs/api/allocations.md @@ -18,3 +18,26 @@ allocations = my_nomad.allocations.get_allocations() for allocation in allocations: print (allocation) ``` + +### Signal allocation + +This endpoint sends a signal to an allocation or task. + +https://developer.hashicorp.com/nomad/api-docs/allocations#signal-allocation + +Example: + +``` +import signal +import nomad + +my_nomad = nomad.Nomad(host='192.168.33.10') + +alloc_id = nomad_setup.allocations.get_allocations()[0]["ID"] + +# Send signal to an allocation +my_nomad.client.allocation.signal_allocation(alloc_id, signal.SIGUSR1.name) + +# Send signal to a task in allocation +my_nomad.client.allocation.signal_allocation(alloc_id, signal.SIGUSR1.name, task="my_task") +``` From 92f8928ce50cd2e7d45eee22d2a1c29a6f710962 Mon Sep 17 00:00:00 2001 From: Matias Morales Date: Mon, 2 Dec 2024 15:26:09 -0300 Subject: [PATCH 4/4] Update signal docstring --- nomad/api/client.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/nomad/api/client.py b/nomad/api/client.py index bd6a814..9f4374c 100644 --- a/nomad/api/client.py +++ b/nomad/api/client.py @@ -306,16 +306,16 @@ def restart_allocation(self, id_): def signal_allocation(self, id_, signal, task=None): """Send a signal to an allocation or task. - https://www.nomadproject.io/api-docs/allocations#signal-allocation - arguments: - - id_ - - signal (str) - optional_arguments: - - task: (str) Optional, if omitted, the signal will be sent to all tasks in the allocation. - returns: dict - raises: - - nomad.api.exceptions.BaseNomadException - - nomad.api.exceptions.URLNotFoundNomadException + https://www.nomadproject.io/api-docs/allocations#signal-allocation + arguments: + - id_ + - signal (str) + optional_arguments: + - task: (str) Optional, if omitted, the signal will be sent to all tasks in the allocation. + returns: dict + raises: + - nomad.api.exceptions.BaseNomadException + - nomad.api.exceptions.URLNotFoundNomadException """ payload = {"Signal": signal, "Task": task} return self.request(id_, "signal", json=payload, method="post").json()