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") +``` diff --git a/nomad/api/client.py b/nomad/api/client.py index ebf5991..9f4374c 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): """ 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()