Skip to content

Commit ff1f1db

Browse files
authored
Feature: signal allocations (#169)
* Add signal allocation method to requester * Add tests for signal allocation * Add documentation * Update signal docstring
1 parent 1befcb4 commit ff1f1db

File tree

3 files changed

+82
-2
lines changed

3 files changed

+82
-2
lines changed

docs/api/allocations.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,26 @@ allocations = my_nomad.allocations.get_allocations()
1818
for allocation in allocations:
1919
print (allocation)
2020
```
21+
22+
### Signal allocation
23+
24+
This endpoint sends a signal to an allocation or task.
25+
26+
https://developer.hashicorp.com/nomad/api-docs/allocations#signal-allocation
27+
28+
Example:
29+
30+
```
31+
import signal
32+
import nomad
33+
34+
my_nomad = nomad.Nomad(host='192.168.33.10')
35+
36+
alloc_id = nomad_setup.allocations.get_allocations()[0]["ID"]
37+
38+
# Send signal to an allocation
39+
my_nomad.client.allocation.signal_allocation(alloc_id, signal.SIGUSR1.name)
40+
41+
# Send signal to a task in allocation
42+
my_nomad.client.allocation.signal_allocation(alloc_id, signal.SIGUSR1.name, task="my_task")
43+
```

nomad/api/client.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,22 @@ def restart_allocation(self, id_):
304304
"""
305305
return self.request(id_, "restart", method="post").json()
306306

307+
def signal_allocation(self, id_, signal, task=None):
308+
"""Send a signal to an allocation or task.
309+
https://www.nomadproject.io/api-docs/allocations#signal-allocation
310+
arguments:
311+
- id_
312+
- signal (str)
313+
optional_arguments:
314+
- task: (str) Optional, if omitted, the signal will be sent to all tasks in the allocation.
315+
returns: dict
316+
raises:
317+
- nomad.api.exceptions.BaseNomadException
318+
- nomad.api.exceptions.URLNotFoundNomadException
319+
"""
320+
payload = {"Signal": signal, "Task": task}
321+
return self.request(id_, "signal", json=payload, method="post").json()
322+
307323

308324
class gc_allocation(Requester):
309325
"""

tests/test_client.py

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import pytest
22
import json
3+
import signal
34
import time
45
import os
56

@@ -8,6 +9,21 @@
89
from flaky import flaky
910

1011

12+
def get_running_allocation(nomad_setup):
13+
max_iterations = 6
14+
for _ in range(max_iterations):
15+
try:
16+
return next(
17+
alloc
18+
for alloc in nomad_setup.allocations.get_allocations()
19+
if alloc["ClientStatus"] == "running"
20+
)
21+
except StopIteration:
22+
# No alloc running
23+
time.sleep(5)
24+
raise ValueError("No allocations running")
25+
26+
1127
# integration tests requires nomad Vagrant VM or Binary running
1228
def test_register_job(nomad_setup):
1329

@@ -17,7 +33,6 @@ def test_register_job(nomad_setup):
1733
assert "example" in nomad_setup.job
1834

1935
max_iterations = 6
20-
2136
while nomad_setup.job["example"]["Status"] != "running":
2237
time.sleep(5)
2338
if max_iterations == 0:
@@ -70,11 +85,37 @@ def test_read_allocation_stats(nomad_setup):
7085
f = nomad_setup.client.allocation.read_allocation_stats(a)
7186

7287

88+
@pytest.mark.skipif(
89+
tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 9, 1), reason="Not supported in version"
90+
)
91+
def test_signal_allocation(nomad_setup):
92+
alloc_id = get_running_allocation(nomad_setup)["ID"]
93+
nomad_setup.client.allocation.signal_allocation(alloc_id, signal.SIGUSR1.name)
94+
95+
96+
@pytest.mark.skipif(
97+
tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 9, 1), reason="Not supported in version"
98+
)
99+
def test_signal_allocation_task(nomad_setup):
100+
allocation = get_running_allocation(nomad_setup)
101+
alloc_id = allocation["ID"]
102+
task = list(allocation["TaskStates"].keys())[0]
103+
nomad_setup.client.allocation.signal_allocation(alloc_id, signal.SIGUSR1.name, task)
104+
105+
106+
@pytest.mark.skipif(
107+
tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 9, 1), reason="Not supported in version"
108+
)
109+
def test_signal_allocation_invalid_signal(nomad_setup):
110+
alloc_id = get_running_allocation(nomad_setup)["ID"]
111+
with pytest.raises(nomad.api.exceptions.BaseNomadException, match="invalid signal"):
112+
nomad_setup.client.allocation.signal_allocation(alloc_id, "INVALID-SIGNAL")
113+
114+
73115
@pytest.mark.skipif(
74116
tuple(int(i) for i in os.environ.get("NOMAD_VERSION").split(".")) < (0, 8, 1), reason="Not supported in version"
75117
)
76118
def test_gc_all_allocations(nomad_setup):
77-
78119
node_id = nomad_setup.nodes.get_nodes()[0]["ID"]
79120
nomad_setup.client.gc_all_allocations.garbage_collect(node_id)
80121
nomad_setup.client.gc_all_allocations.garbage_collect()

0 commit comments

Comments
 (0)