{% extends "base.html" %} {% block title %}Discovery · Keywright{% endblock %}{% block body %} {% include "_infrastructure_nav.html" %}

Discovery

Read devices and workloads from Omada and Proxmox, then compare them with your inventory.

Refreshes only collect observations. Review a device to import it or link an existing record, then choose which fields to apply. Suggested matches need review; an observed IP may be a temporary DHCP lease.

Omada controller

Reads all accessible sites, network devices, and clients. Refresh may take up to three minutes.

Proxmox cluster

Choose a cluster node with permission to read its hosts, VMs, and containers. Guest IPs are not included yet.

{% if latest %}

Latest refreshes

{% for run in latest %}{% endfor %}
SourceResultStarted (UTC)Observations
{{ resource_map[run.resource_id].name }}{{ providers[run.provider] }}{{ 'Interrupted' if run.status=='running' and run.started_at < interrupted_before else run.status|capitalize }}{% if run.error %}{{ run.error }}{% endif %}{{ run.started_at.strftime('%Y-%m-%d %H:%M:%S') }}{{ run.count if run.status=='succeeded' else 'Previous observations retained' }}
{% endif %}
{% if rows %}
{% for row in rows %}{% set record=row.record %}{% set item=record.data %}{% endfor %}
Observed device / workloadConnection / hostingObserved addressesPossible inventory matchesSource / freshness
{{ item.name }}{{ kinds[item.kind] }}{% if item.site %} · {{ item.site }}{% endif %}{{ 'Source reports: ' ~ item.status }} {% if row.changes %}
Changed: {{ row.changes|map(attribute='label')|join(', ') }}

Last change {{ record.changed_at.strftime('%Y-%m-%d %H:%M') }} UTC

{% for change in row.changes %}
{{ change.label }}: {{ change.before }} → {{ change.after }}
{% endfor %}
{% endif %}
{{ media[item.medium] }}{% if row.parent %}Hosted on {{ row.parent }}{% endif %}{% if row.attachment %}Connected to {{ row.attachment }}{% endif %}{% if item.port %}{{ item.port }}{% endif %}{% if item.mac %}{{ item.mac }}{% endif %} {% for address in item.addresses %}
{{ address }}
{% else %}Not reported{% endfor %}
{% if row.link %}{{ asset_map[row.link.asset_id].name }}{{ row.review_state }}{% else %}{% for match in row.matches %}
{{ match.asset.name }}{{ match.reasons }}
{% else %}New · no match found{% endfor %}{% if row.matches|length > 1 %}Ambiguous · review before linking{% endif %}{% endif %}
{{ resource_map[record.resource_id].name }}{{ providers[record.provider] }} · {{ record.last_seen.strftime('%Y-%m-%d %H:%M') }} UTC{% if row.missing %}Not seen in latest successful refresh{% elif row.stale %}Observation older than 24 hours{% endif %}

{{ rows|length }} of {{ total_count }} observations · page {{ page }} of {{ total_pages }}. Missing observations do not establish that a device is offline or an address is free.

{% if total_pages > 1 %}
{% if page > 1 %}Previous{% endif %}{% if page < total_pages %}Next{% endif %}
{% endif %} {% else %}

No observations to show

Refresh a source above, or adjust your filters. Existing inventory stays unchanged.

{% endif %} {% endblock %}