raccoon_transport.contract_check ================================ .. py:module:: raccoon_transport.contract_check .. autoapi-nested-parse:: Startup check of the transport contract. Semantics: ``contract/CHECK_SPEC.md``. Every component runs :func:`startup_check` once when it starts. The result goes to a status file (never over the transport, which may be the thing that is broken) and, for ``mismatch`` and ``bundle-fehler``, the component refuses to start. The Pi server reads the status files with :func:`aggregate`. Attributes ---------- .. autoapisummary:: raccoon_transport.contract_check.EXIT_CODE raccoon_transport.contract_check.OK raccoon_transport.contract_check.MISMATCH raccoon_transport.contract_check.DEV_WARNING raccoon_transport.contract_check.BUNDLE_ERROR raccoon_transport.contract_check.SKIPPED Exceptions ---------- .. autoapisummary:: raccoon_transport.contract_check.ContractError Classes ------- .. autoapisummary:: raccoon_transport.contract_check.ComponentCheck raccoon_transport.contract_check.CheckResult Functions --------- .. autoapisummary:: raccoon_transport.contract_check.is_refusing raccoon_transport.contract_check.check raccoon_transport.contract_check.status_dir raccoon_transport.contract_check.write_status raccoon_transport.contract_check.startup_check raccoon_transport.contract_check.exit_if_refused raccoon_transport.contract_check.read_statuses raccoon_transport.contract_check.aggregate raccoon_transport.contract_check.refusal_message Module Contents --------------- .. py:data:: EXIT_CODE :value: 78 .. py:data:: OK :value: 'ok' .. py:data:: MISMATCH :value: 'mismatch' .. py:data:: DEV_WARNING :value: 'dev-warnung' .. py:data:: BUNDLE_ERROR :value: 'bundle-fehler' .. py:data:: SKIPPED :value: 'skipped' .. py:function:: is_refusing(result: Optional[str]) -> bool Everything except ok, dev-warnung and skipped refuses, including the results that a component's own check defines (for example the component version check). .. py:exception:: ContractError(result: CheckResult) Bases: :py:obj:`RuntimeError` The transport contract of this component does not match the bundle. .. py:attribute:: result .. py:class:: ComponentCheck The result of a check that belongs to the component, not to the transport. A component runs its own check (for example "is my version the one in the bundle?") and hands the result to :func:`check` / :func:`startup_check`. The transport knows nothing about what it checks: ``result`` is ``ok``, ``dev-warnung`` or any name that refuses (``version-mismatch``, ...), and ``message`` is shown as it is. It is merged after the transport's own checks (a transport failure always wins) and recorded in the status file. .. py:attribute:: name :type: str .. py:attribute:: result :type: str .. py:attribute:: message :type: str .. py:attribute:: reason :type: Optional[str] :value: None .. py:attribute:: expected :type: Optional[str] :value: None .. py:class:: CheckResult .. py:attribute:: component :type: str .. py:attribute:: component_version :type: str .. py:attribute:: own_hash :type: str .. py:attribute:: own_transport_version :type: str .. py:attribute:: expected_hash :type: Optional[str] .. py:attribute:: expected_transport_version :type: Optional[str] .. py:attribute:: bundle :type: Optional[str] .. py:attribute:: result :type: str .. py:attribute:: reason :type: Optional[str] .. py:attribute:: message :type: str .. py:attribute:: bundle_file :type: str :value: '/etc/raccoon-bundle.json' .. py:attribute:: component_check :type: Optional[ComponentCheck] :value: None .. py:property:: refuse :type: bool .. py:function:: check(component: str, component_version: str, *, component_check: Optional[ComponentCheck] = None, own_hash: Optional[str] = None, own_version: Optional[str] = None, bundle_file: Optional[str] = None, device_marker: Optional[str] = None, force: Optional[bool] = None) -> CheckResult Run the decision of the spec. Reads one file, writes nothing. .. py:function:: status_dir(override: Optional[str] = None) -> pathlib.Path .. py:function:: write_status(result: CheckResult, *, persistent: bool, directory: Optional[str] = None) -> Optional[pathlib.Path] Write ``.json`` atomically. Returns None (and logs) on failure. .. py:function:: startup_check(component: str, component_version: str, *, persistent: bool, enforce: bool = True, status_directory: Optional[str] = None, **kwargs: Any) -> CheckResult Check, record, log. Raises :class:`ContractError` if the component must refuse. .. py:function:: exit_if_refused(result: CheckResult) -> None For long-running services: exit with the reserved code. .. py:function:: read_statuses(directory: Optional[str] = None) -> list[dict[str, Any]] All status files with an ``active`` flag. Unreadable files are reported, not hidden. .. py:function:: aggregate(*, bundle_file: Optional[str] = None, directory: Optional[str] = None, device_marker: Optional[str] = None, force: Optional[bool] = None) -> dict[str, Any] What ``GET /contract`` of the Pi server returns. Off a Raccoon device (laptop, simulation, tests) there is nothing to enforce: the result is ``ok`` with ``on_device`` false. .. py:function:: refusal_message(summary: dict[str, Any]) -> Optional[str] Text for rejecting a run, or None when the run may start.