{% extends "layout.html" %} {% from "_partials/page_description.html" import page_description %} {% block title %}{{ machine.mac }} - pixie{% endblock %} {% block subnav %} {% endblock %} {% block content %} {{ page_description('pc-display-horizontal', 'Everything pixie knows about one target: telemetry, current binding, inventory the live env posts back, and events scoped to this MAC. Editing the binding changes what pixie serves on this target\'s next PXE; labels and inventory are stored independently of the binding.') }} {# Bind failure surfaced from POST /ui/machines/bind (e.g. an overlay alias held single-writer by another machine). The message is the caught exception text, passed back via the ?bind_error= redirect; Jinja auto-escapes it. Nothing rendered on the happy path. #} {% if bind_error %} {% endif %}

{{ machine.mac }}

{% set _bm = boot_mode_meta_map.get(machine.boot_mode) %} {{ _bm.short if _bm else machine.boot_mode }}
Image content sha
{% if machine.image_content_sha256 %} {{ machine.image_content_sha256 }} {% else %} (unbound) {% endif %}
{# Flash status: when + which image was last written, and a Re-flash re-arm. Surfaced for the flash modes (and for any machine that has ever been flashed) so the operator can inspect the last flash and re-trigger one without juggling boot modes. #} {% if machine.boot_mode in ('pixie-flash-once', 'pixie-flash-always') or machine.flashed_at %}
Flash status
{% if machine.flashed_at %} Flashed {{ machine.flashed_image_sha256[:12] if machine.flashed_image_sha256 else '(no image)' }} at {{ machine.flashed_at | fmt_ts }} {% if machine.boot_mode == 'pixie-flash-once' %} {% if machine.flashed_image_sha256 == machine.image_content_sha256 %}
One-shot complete: the next PXE boots the flashed disk (no re-flash). Re-flash to write the bound image again.
{% else %}
Bound image changed since this flash; the next PXE flashes the new image.
{% endif %}
{% elif machine.boot_mode == 'pixie-flash-always' %}
Re-flashes on every PXE boot.
{% endif %} {% else %} Not flashed yet; flashes on the next PXE boot. {% endif %}
{% endif %}
Labels
{# Labels are metadata (search / filter / grouping) and have no effect on the plan render. Edit them here on their own form; the bind form below does NOT touch labels, so a boot-mode flip cannot clobber tags an operator set up ahead of time. #}
Comma-separated. Alnum-leading; a-z / 0-9 / space / . _ -; max 64 chars per tag, 16 tags per machine. Blank clears.
Discovered at
{{ machine.discovered_at | fmt_ts }}
Last seen
{{ machine.last_seen_at | fmt_ts }}
Last seen IP
{% if machine.last_seen_ip %}{{ machine.last_seen_ip }} {% else %}-{% endif %}

Edit binding

Unsaved changes
{# ---- Boot-mode radio-card picker ------------------------ Six cards in a 3-across grid. The underlying ```` is visually hidden but keeps the form serialisation + keyboard accessibility that a plain click-a-card widget would drop. The label wraps both the radio and the visual card so anywhere on the card selects the mode. #}
{% for mode_value, meta in boot_mode_meta %}
{% endfor %}
{# ---- Image picker --------------------------------- #}
{% set entry_shas = bindable_entries | map(attribute='content_sha256') | list %} {% if not bindable_entries %} {% endif %}
{# ---- Target disk picker --------------------------- #}
{% set disks = (machine.inventory or {}).get("disks") or [] %} {% if disks %}
The live env matches this SERIAL against the current disks at flash time; a swapped or renumbered drive refuses the flash rather than risking the wrong disk.
{% else %}
No inventory on file yet. Pick Discover inventory above, power-cycle this target, and its disks will populate here.
{% endif %}
{# ---- Per-machine extra kernel cmdline ------------------- Overrides the deploy-wide PIXIE_LIVE_ENV_EXTRA_CMDLINE for THIS machine. Blank falls back to the global; a non-blank value fully replaces (does not concatenate) so an operator can pin a hardware quirk to one target without every other machine seeing the same tokens. Consumed by the nbdboot + pixie-live-env templates. #}
Tokens appended verbatim to the kernel cmdline for this machine only. A non-blank value fully overrides the deploy-wide PIXIE_LIVE_ENV_EXTRA_CMDLINE. Blank falls back to the global (currently effective: {% if global_live_env_extra_cmdline %} {{ global_live_env_extra_cmdline }} {% else %}none{% endif %}). Whitespace-separated; single line. Known-good values per hardware in docs/hardware-quirks.md.
{# ---- Overlay picker (nbdboot-overlay only) ------------- Select an EXISTING overlay; this form never creates one (overlays are made on the Overlays page, just as images are fetched on the Catalog page). Selecting an overlay IMPLIES its base image, so there is no image picker for this mode. Overlays free or held by THIS machine are selectable; one held by ANOTHER machine is single-writer-locked and shown disabled (with the holder MAC). #}
{% if not overlay_aliases %} No overlays yet. Create one on the Overlays page, then select it here. {% else %} Attaching an overlay binds this machine to the overlay's base image; writes land on its qcow2 and survive reboots. An overlay is single-writer: at most one machine holds it at a time. Create and delete overlays on the Overlays page. See boot-modes docs. {% endif %}
{# ---- Preview panel -------------------------------------- Plain-English description of what will happen on the next PXE from this target. Updated by JS on any input change. Sits ABOVE the flash-guard hint so an operator scanning the form always knows what "Save" will do before they're asked whether they can Save. #}
On the next PXE from this target
{{ initial_bind_preview }}
{# ---- Flash-mode guard hint ------------------------------ Client-side echo of the server-side 422 guard: the JS disables Save + surfaces this hint when the picked boot_mode is pixie-flash-{once,always} AND either no inventory is on file OR no target_disk_serial is picked. The server rejects the same combination regardless. #}
No changes to save.

Inventory

{% if machine.inventory %} Recorded at {{ machine.inventory_at | fmt_ts }}
{% endif %}

Posted by the live env's pixie CLI on boot (lsblk + lshw); best-effort render, raw JSON below.

{% if machine.inventory %} {# Best-effort render of the machine hardware summary. The raw payload posted by the live env's ``pixie`` CLI is ``{"lshw": , "disks": []}``; the ``inv`` context var (built by ``pixie.web._inventory.normalise_inventory`` at render time) walks the lshw tree into the system/cpu/memory/nics shape rendered below. Each block is guarded so a partial payload still renders the sections that DID come through. Raw lshw JSON sits collapsed at the bottom as the always-available fallback for anything the summary render doesn't cover. #} {# ---- Hardware summary (compact) ------------------------ System + CPU + memory folded into one dense definition grid instead of three stacked full-width cards with oversized stat numbers. One scannable line per subsystem; the per-DIMM slot map is kept (it reads at a glance) and every number that used to sit in a display-6 block now lives inline or in the slot tooltips. #} {% set system = inv.system %} {% set cpu = inv.cpu %} {% set memory = inv.memory %} {% if system or cpu.sockets or memory.total_bytes %}
{% if system %}
System
{% if system.get("vendor") or system.get("model") %} {{ system.get("vendor") }} {{ system.get("model") }} {% endif %} {% if system.get("serial") %} · SN {{ system.get("serial") }}{% endif %} {% if system.get("firmware") %} · BIOS {{ system.get("firmware") }}{% if system.get("firmware_vendor") %} ({{ system.get("firmware_vendor") }}){% endif %}{% endif %}
{% endif %} {% if cpu.sockets %}
CPU
{% for socket in cpu.sockets %} {{ socket.model or "Unknown CPU" }} {% if socket.arch %}{{ socket.arch }}{% endif %} {% if cpu.sockets|length > 1 %}Socket {{ socket.slot or loop.index0 }}{% endif %} — {{ socket.cores or "?" }} cores / {{ socket.threads or "?" }} threads{% if socket.mhz_current %} @ {{ socket.mhz_current | humanize_hz }}{% endif %}{% if socket.mhz_max %} (max {{ socket.mhz_max | humanize_hz }}){% endif %}{% if socket.vendor %} · {{ socket.vendor }}{% endif %}
{% endfor %} {% if cpu.sockets|length > 1 and cpu.total_cores %}
{{ cpu.sockets|length }} sockets · {{ cpu.total_cores }} cores / {{ cpu.total_threads }} threads total
{% endif %} {% endif %} {% if memory.total_bytes %}
Memory
{{ memory.total_bytes | humanize_bytes }} {% if memory.slots_total %} · {{ memory.slots_populated }} / {{ memory.slots_total }} slots populated{% endif %} {% if memory.dominant_type %} · {{ memory.dominant_type }}{% endif %} {% if memory.dominant_speed_hz %} @ {{ (memory.dominant_speed_hz / 1000000) | round | int }} MHz{% endif %} {% if memory.dimms %}
{% for d in memory.dimms %} {% if d.empty %} {% else %} {% endif %} {% endfor %}
{% endif %}
{% endif %} {% endif %} {% set nics = inv.nics %} {% if nics %}

Network ({{ nics|length }})

{% for n in nics %} {% endfor %}
Interface MAC Vendor / Driver Link
{{ n.get("name") or "-" }} {{ n.get("mac") or "-" }} {{ n.get("vendor") or "-" }} {% if n.get("driver") %}
{{ n.get("driver") }}{% endif %}
{% if n.get("speed") %}{{ n.get("speed") }}{% else %}-{% endif %}
{% endif %} {% set disks = inv.disks %} {% if disks %}

Disks ({{ disks|length }})

{% for d in disks %} {% endfor %}
Path Size Vendor / Model Serial Transport
{{ d.get("path") or "-" }} {{ d.get("size") or "-" }} {{ d.get("vendor") or "-" }} {% if d.get("model") %}
{{ d.get("model") }}{% endif %}
{{ d.get("serial") or "-" }} {{ d.get("tran") or "-" }}
{% else %}

No disks in the posted inventory.

{% endif %} {% if machine.inventory.get("lshw") %}
Raw lshw JSON
{{ machine.inventory.get("lshw") | tojson(indent=2) }}
{% endif %} {% else %}

No inventory has been posted for this machine yet. The live env's pixie CLI posts one on boot; check the target's PXE reach to pixie.

{% endif %}

Recent events

All events
{% if events %}
{% for e in events %} {% endfor %}
When Kind Summary
{{ e.ts | fmt_ts }} {{ e.kind }} {{ e.summary or "" }}
{% else %}

No events recorded for this machine yet.

{% endif %}
{% endblock %}