Add method for checking OS version.

This commit is contained in:
Julian Stirling 2026-04-30 14:14:24 +01:00
parent 62d1724db6
commit 5b14f8d820
4 changed files with 64 additions and 0 deletions

View file

@ -5,6 +5,7 @@ the microscope, server, and thing states to the web API.
""" """
import os import os
import re
import socket import socket
import subprocess import subprocess
import time import time
@ -22,6 +23,8 @@ from openflexure_microscope_server.utilities import VersionData, robust_version_
SHUTDOWN_CMD = ["sudo", "shutdown", "-h", "now"] SHUTDOWN_CMD = ["sudo", "shutdown", "-h", "now"]
REBOOT_CMD = ["sudo", "shutdown", "-r", "now"] REBOOT_CMD = ["sudo", "shutdown", "-r", "now"]
OS_VERSION_FILE = "/usr/lib/os-release"
class CommandOutput(BaseModel): class CommandOutput(BaseModel):
"""A pydantic model passing the STDOUT and STDERR from a subprocess over HTTP.""" """A pydantic model passing the STDOUT and STDERR from a subprocess over HTTP."""
@ -81,6 +84,24 @@ class OpenFlexureSystem(lt.Thing):
"""Return True if running on a Raspberry Pi.""" """Return True if running on a Raspberry Pi."""
return os.path.exists("/usr/bin/raspi-config") return os.path.exists("/usr/bin/raspi-config")
@lt.property
def os_version(self) -> Optional[str]:
"""Return the OS version of the Pi. Returns None if not on a Pi."""
if not self.is_raspberrypi:
return None
if not os.path.isfile(OS_VERSION_FILE):
return "unknown"
with open(OS_VERSION_FILE, "r", encoding="utf-8") as os_file:
os_data = os_file.read()
version_match = re.search(r"^VERSION_CODENAME=(.+)$", os_data, re.MULTILINE)
if not version_match:
return "unknown"
return version_match.group(1)
@lt.action @lt.action
def shutdown(self) -> CommandOutput: def shutdown(self) -> CommandOutput:
"""Attempt to shutdown the device.""" """Attempt to shutdown the device."""

View file

@ -0,0 +1,10 @@
PRETTY_NAME="Debian GNU/Linux 13 (trixie)"
NAME="Debian GNU/Linux"
VERSION_ID="13"
VERSION="13 (trixie)"
VERSION_CODENAME=trixie
DEBIAN_VERSION_FULL=13.4
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

View file

@ -0,0 +1 @@
This doesn't contain the data we are looking for.

View file

@ -11,6 +11,11 @@ from labthings_fastapi.testing import create_thing_without_server
from openflexure_microscope_server.things import system from openflexure_microscope_server.things import system
from openflexure_microscope_server.utilities import VersionData, robust_version_strings from openflexure_microscope_server.utilities import VersionData, robust_version_strings
THIS_DIR = os.path.dirname(os.path.abspath(__file__))
FAKE_OS_FILE = os.path.join(THIS_DIR, "assets", "os-release")
BROKEN_OS_FILE = os.path.join(THIS_DIR, "assets", "os-release-broken")
MISSING_OS_FILE = os.path.join(THIS_DIR, "assets", "this-does-not-exist")
@pytest.fixture @pytest.fixture
def system_thing(): def system_thing():
@ -37,6 +42,33 @@ def test_is_raspberry(system_thing):
assert system_thing.is_raspberrypi == _is_raspberrypi() assert system_thing.is_raspberrypi == _is_raspberrypi()
@pytest.mark.parametrize(
("version_file", "expected_result"),
[
(MISSING_OS_FILE, "unknown"),
(FAKE_OS_FILE, "trixie"),
(BROKEN_OS_FILE, "unknown"),
],
)
def test_os_version_pi(version_file, expected_result, system_thing, mocker):
"""Check reading the operating system version from a Pi (mocked!)."""
type(system_thing).is_raspberrypi = mocker.PropertyMock(return_value=True)
mocker.patch(
"openflexure_microscope_server.things.system.OS_VERSION_FILE", version_file
)
assert system_thing.os_version == expected_result
def test_os_version_not_pi(system_thing, mocker):
"""Check reading the operating system when not on a Pi returns None."""
mocker.patch(
"openflexure_microscope_server.things.system.OS_VERSION_FILE", FAKE_OS_FILE
)
type(system_thing).is_raspberrypi = mocker.PropertyMock(return_value=False)
assert system_thing.os_version is None
def test_version_data(system_thing): def test_version_data(system_thing):
"""Check VersionData is returned. """Check VersionData is returned.