Skip to content

Commit 061a580

Browse files
feat(update-server): Add bootId field to GET /server/update/health (#7404)
1 parent 466bd00 commit 061a580

File tree

5 files changed

+37
-8
lines changed

5 files changed

+37
-8
lines changed

update-server/otupdate/buildroot/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def get_version(version_file: str) -> Mapping[str, str]:
3434
def get_app(system_version_file: str = None,
3535
config_file_override: str = None,
3636
name_override: str = None,
37+
boot_id_override: str = None,
3738
loop: asyncio.AbstractEventLoop = None) -> web.Application:
3839
""" Build and return the aiohttp.web.Application that runs the server
3940
@@ -44,6 +45,7 @@ def get_app(system_version_file: str = None,
4445

4546
version = get_version(system_version_file)
4647
name = name_override or name_management.get_name()
48+
boot_id = boot_id_override or control.get_boot_id()
4749
config_obj = config.load(config_file_override)
4850

4951
LOG.info("Setup: " + '\n\t'.join([
@@ -69,6 +71,7 @@ def get_app(system_version_file: str = None,
6971
app = web.Application(middlewares=[log_error_middleware])
7072
app[config.CONFIG_VARNAME] = config_obj
7173
app[constants.RESTART_LOCK_NAME] = asyncio.Lock()
74+
app[constants.DEVICE_BOOT_ID_NAME] = boot_id
7275
app[constants.DEVICE_NAME_VARNAME] = name
7376
app.router.add_routes([
7477
web.get('/server/update/health',

update-server/otupdate/buildroot/constants.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,17 @@
88

99
DEVICE_NAME_VARNAME = APP_VARIABLE_PREFIX + 'name'
1010
#: Name for the device
11+
12+
DEVICE_BOOT_ID_NAME = APP_VARIABLE_PREFIX + "boot_id"
13+
#: A random string that changes every time the device boots.
14+
#:
15+
#: Clients can poll this to detect when the OT-2 has rebooted. (Including both
16+
#: graceful reboots, like from clicking the soft "Restart" button, and
17+
#: unexpected reboots, like from interrupting the power supply).
18+
#:
19+
#: There are no guarantees about the returned ID's length or format. Equality
20+
#: comparison with other IDs returned from this endpoint is the only valid
21+
#: thing to do with it.
22+
#:
23+
#: This ID only changes when the whole OT-2 operating system reboots.
24+
#: It doesn't change if some internal process merely crashes and restarts.

update-server/otupdate/buildroot/control.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,15 @@
66
import asyncio
77
import logging
88
import subprocess
9+
from functools import lru_cache
10+
from pathlib import Path
911
from typing import Callable, Coroutine, Mapping
1012

1113
from aiohttp import web
1214

13-
from .constants import (RESTART_LOCK_NAME, DEVICE_NAME_VARNAME)
15+
from .constants import (
16+
RESTART_LOCK_NAME, DEVICE_BOOT_ID_NAME, DEVICE_NAME_VARNAME
17+
)
1418

1519
LOG = logging.getLogger(__name__)
1620

@@ -49,7 +53,8 @@ async def health(request: web.Request) -> web.Response:
4953
'systemVersion': version_dict.get(
5054
'buildroot_version', 'unknown'),
5155
'capabilities': {'buildrootUpdate': '/server/update/begin',
52-
'restart': '/server/restart'}
56+
'restart': '/server/restart'},
57+
'bootId': request.app[DEVICE_BOOT_ID_NAME]
5358
},
5459
headers={'Access-Control-Allow-Origin': '*'}
5560
)
@@ -59,7 +64,12 @@ async def health(request: web.Request) -> web.Response:
5964
def get_serial() -> str:
6065
""" Get the device serial number. """
6166
try:
62-
with open('/var/serial') as vs:
63-
return vs.read().strip()
67+
return Path('/var/serial').read_text().strip()
6468
except OSError:
6569
return 'unknown'
70+
71+
72+
@lru_cache(maxsize=1)
73+
def get_boot_id() -> str:
74+
# See the "/proc Interface" section in man(4) random.
75+
return Path('/proc/sys/kernel/random/boot_id').read_text().strip()

update-server/tests/buildroot/conftest.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,11 @@ async def test_cli(aiohttp_client, loop, otupdate_config, monkeypatch):
123123
Build an app using dummy versions, then build a test client and return it
124124
"""
125125
app = buildroot.get_app(
126-
os.path.join(HERE, "version.json"),
127-
otupdate_config,
128-
'opentrons-test',
129-
loop)
126+
system_version_file=os.path.join(HERE, "version.json"),
127+
config_file_override=otupdate_config,
128+
name_override='opentrons-test',
129+
boot_id_override='dummy-boot-id-abc123',
130+
loop=loop)
130131
client = await loop.create_task(aiohttp_client(app))
131132
return client
132133

update-server/tests/buildroot/test_control.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ async def test_health(test_cli):
1919
assert body['apiServerVersion'] == version_dict['opentrons_api_version']
2020
assert body['smoothieVersion'] == 'unimplemented'
2121
assert body['systemVersion'] == version_dict['buildroot_version']
22+
assert body['bootId'] == 'dummy-boot-id-abc123'
2223

2324

2425
async def test_restart(test_cli, monkeypatch):

0 commit comments

Comments
 (0)