{% extends 'generic/object.html' %} {% load helpers %} {% load i18n %} {% block title %}{{ object }} - {% trans "Scope Reconciliation" %}{% endblock %} {% block extra_controls %} {% trans "Sync" %} {% endblock extra_controls %} {% block content %}
| {% trans "Include tags" %} | {{ payload.include_tags|join:", "|placeholder }} |
|---|---|
| {% trans "NetBox devices" %} | {{ payload.netbox_device_count }} |
| {% trans "In scope (collected)" %} | {{ payload.forward_in_scope_completed }} |
| {% trans "In scope (SNMP endpoints)" %} | {{ payload.forward_in_scope_endpoints }} |
| {% trans "Tagged but backfilled" %} | {{ payload.forward_tagged_backfilled }} {% if payload.netbox_present_backfilled %} {% blocktrans with count=payload.netbox_present_backfilled %}view {{ count }} tagged{% endblocktrans %} {% trans "why?" %} {% endif %} |
| {% trans "Out of scope (orphans)" %} | {% if payload.netbox_out_of_scope %} {# Straight to the card carrying the cause badges and the full list. #} {{ payload.netbox_out_of_scope }} {% else %} 0 {% endif %} {% include 'forward_netbox/inc/count_trend.html' with trend=out_of_scope_trend %} |
| {% trans "Empty orphan sites" %} | {% if payload.netbox_empty_orphan_site_count %} {{ payload.netbox_empty_orphan_site_count }} {% else %} 0 {% endif %} |
| {% trans "In scope, missing from NetBox" %} | {{ payload.forward_missing_in_netbox }} |
| {% trans "Carry no include tag" %} | {{ payload.unmanaged.untagged_total }} {% if payload.unmanaged.owned_untagged %} {% blocktrans with count=payload.unmanaged.owned_untagged %}{{ count }} created by this sync{% endblocktrans %} {# The cause of this number, and the cleanup for it, are in a #} {# card further down the page - which is the half a customer #} {# reading only the summary never reached. #} {% trans "why? / clean up" %} {% include 'forward_netbox/inc/count_trend.html' with trend=uncovered_trend %} {% endif %} {% if payload.unmanaged.unclaimed %} {% blocktrans with count=payload.unmanaged.unclaimed %}{{ count }} not claimed by this sync{% endblocktrans %} {% trans "why?" %} {% endif %} |
{% if payload.out_of_scope_absence.absent_from_snapshot %} {% blocktrans count counter=payload.out_of_scope_absence.absent_from_snapshot %}{{ counter }} gone from Forward{% plural %}{{ counter }} gone from Forward{% endblocktrans %} {% endif %} {% if payload.out_of_scope_absence.present_untagged %} {% blocktrans count counter=payload.out_of_scope_absence.present_untagged %}{{ counter }} in Forward but untagged{% plural %}{{ counter }} in Forward but untagged{% endblocktrans %} {% endif %} {% if payload.out_of_scope_absence.vendor_excluded %} {% blocktrans count counter=payload.out_of_scope_absence.vendor_excluded %}{{ counter }} custom-command source{% plural %}{{ counter }} custom-command source{% endblocktrans %} {% endif %}
{% if payload.out_of_scope_absence.present_untagged %}{% trans "Devices Forward still has but no longer reports under these tags. A Forward-side tag edit and a narrowed query look identical here — confirm in Forward before pruning." %}
{% endif %} {% if payload.out_of_scope_absence.absent_detail %}{% blocktrans count counter=payload.out_of_scope_absence.absent_still_tagged %}Of those gone from the snapshot, Forward's device configuration still lists {{ counter }} under an include tag:{% plural %}Of those gone from the snapshot, Forward's device configuration still lists {{ counter }} under an include tag:{% endblocktrans %} {% for row in payload.out_of_scope_absence.absent_detail %} {{ row.count }} — {{ row.label }} {% endfor %} {% trans "Forward's UI shows these as tagged; the sync reads the snapshot, which does not carry them. A disabled device stays here until collection is re-enabled or it is pruned." %}
{% endif %} {% endif %} {% comment %} How long the absence has lasted, which is a different question from what kind of absence it is, and the one that decides whether the prune may act yet. {% endcomment %} {% if payload.out_of_scope_quarantine.held %}{% blocktrans count counter=payload.out_of_scope_quarantine.held %}{{ counter }} in quarantine{% plural %}{{ counter }} in quarantine{% endblocktrans %} {% if payload.out_of_scope_quarantine.prune_eligible %} {% blocktrans count counter=payload.out_of_scope_quarantine.prune_eligible %}{{ counter }} prune-eligible{% plural %}{{ counter }} prune-eligible{% endblocktrans %} {% endif %}
{% blocktrans with runs=payload.out_of_scope_quarantine.required_runs hours=payload.out_of_scope_quarantine.required_hours %}A device disabled in Forward disappears exactly as a removed one does, so an absence must persist for {{ runs }} consecutive syncs and {{ hours }} hours before the prune will delete it. Devices that reappear leave quarantine automatically.{% endblocktrans %}
{% endif %}{{ name }}{% blocktrans with shown=payload.out_of_scope_sample|length total=payload.netbox_out_of_scope %}Showing {{ shown }} of {{ total }}.{% endblocktrans %}
{% endif %} {% if payload.netbox_out_of_scope %} {# The red button below deletes every one of these; the sample is 25. #}{% blocktrans with count=payload.netbox_out_of_scope %}List all {{ count }}{% endblocktrans %}
{% endif %} {% else %}{% trans "No out-of-scope devices." %}
{% endif %}| {% trans "Mode" %} | {% trans "Read only" %} |
|---|---|
| {% trans "Platforms with manufacturer" %} | {{ upgrade_reconciliation.platforms.with_manufacturer }} / {{ upgrade_reconciliation.platforms.total }} |
| {% trans "Platforms without manufacturer" %} | {{ upgrade_reconciliation.platforms.without_manufacturer }} |
| {% trans "Stale endpoint DeviceTypes" %} | {% if upgrade_reconciliation.stale_endpoint_device_types.candidate_count %} {{ upgrade_reconciliation.stale_endpoint_device_types.candidate_count }} {% else %} 0 {% endif %} |
| {% trans "DLM status" %} | {{ upgrade_reconciliation.dlm.status }} |
| {% trans "Software versions" %} | {{ upgrade_reconciliation.dlm.software_versions.total }} |
| {% trans "Versions without devices" %} | {{ upgrade_reconciliation.dlm.software_versions.without_devices }} |
| {% trans "Protected versions without devices" %} | {{ upgrade_reconciliation.dlm.software_versions.protected_without_devices }} |
| {% trans "Unreferenced version candidates" %} | {% if upgrade_reconciliation.dlm.software_versions.unreferenced_without_devices %} {{ upgrade_reconciliation.dlm.software_versions.unreferenced_without_devices }} {% else %} 0 {% endif %} |
| {% trans "CVEs" %} | {{ upgrade_reconciliation.dlm.cves.total }} |
| {% trans "CVEs with vulnerabilities" %} | {{ upgrade_reconciliation.dlm.cves.with_vulnerabilities }} |
| {% trans "CVEs with affected software" %} | {{ upgrade_reconciliation.dlm.cves.with_affected_software }} |
| {% trans "Unlinked CVEs" %} | {{ upgrade_reconciliation.dlm.cves.unlinked }} |
{{ item.manufacturer__name }} / {{ item.model }}{{ item.platform__name }} / {{ item.version }}{{ item.platform__name }} / {{ item.version }} ({{ item.protected_by }}){% trans "No post-upgrade review candidates." %}
{% endif %}{% trans "Why these in-scope devices were not freshly collected by Forward. This is a Forward collection-health signal, not a sync error — fix collection in Forward (rotate credentials for AUTHENTICATION_FAILED, check reachability for CONNECTION_TIMEOUT, finish onboarding for INCOMPLETE_SETUP)." %}
{{ reason }} |
{{ count }} |
|---|
{% trans "No backfilled devices in the latest snapshot." %}
{% endif %}{% trans "In NetBox but not freshly collected in the latest snapshot (serving last-known-good data). Days = how stale the served data is." %}
| {% trans "Device" %} | {% trans "Reason" %} | {% trans "Stale" %} |
|---|---|---|
{{ item.name }} |
{{ item.reason }} |
{% if item.stale_days is not None %}{% blocktrans count days=item.stale_days %}{{ days }} day{% plural %}{{ days }} days{% endblocktrans %}{% else %}—{% endif %} |
{% blocktrans with shown=payload.present_backfilled_detail_sample|length total=payload.netbox_present_backfilled %}Showing {{ shown }} of {{ total }}.{% endblocktrans %}
{% endif %} {% if payload.netbox_present_backfilled %}{% blocktrans with count=payload.netbox_present_backfilled %}List all {{ count }}{% endblocktrans %}
{% endif %} {% else %}{% trans "No backfilled devices in NetBox." %}
{% endif %}{% blocktrans with count=catalogue_cleanup.entry_count %}{{ count }} prefix-list, community-list or route-map entries in NetBox belong to definitions that no device inside this sync's scope holds, as of the latest dependency preview. The sync never removes them on its own.{% endblocktrans %}
{{ model }}: {{ count }}{% trans "Removing them re-reads Forward first, and deletes only entries this sync created, that no sync still asserts, and that no route map outside the cleanup still matches on. Anything else is held and counted in the job result." %}
{% if perms.netbox_routing.delete_prefixlist %} {% endif %}{% trans "When Forward relabels a device's site, older versions of this plugin created a second device instead of moving the first. The older copy usually keeps the device's primary IP and history. Merging keeps the older device, moves it to the site the sync's device map reports now, and deletes the copy. This repairs existing pairs only - a current sync no longer creates them." %}
{% if site_relabel_pairs.pair_count and perms.dcim.delete_device %} {% endif %} {% if site_relabel_pairs.last_repair %}{% blocktrans with job=site_relabel_pairs.last_repair.job_pk merged=site_relabel_pairs.last_repair.merged_count failed=site_relabel_pairs.last_repair.failed_count %}Last merge (job #{{ job }}): {{ merged }} merged, {{ failed }} refused.{% endblocktrans %}
{% if site_relabel_pairs.last_repair.routing_rows_released %}{% trans "Routing rows released so the newer copy could be deleted (the next sync rebuilds them on the surviving device):" %} {% for model, count in site_relabel_pairs.last_repair.routing_rows_released %}{{ model }} × {{ count }}{% if not forloop.last %}, {% endif %}{% endfor %}
{% endif %} {% if site_relabel_pairs.last_repair.failed_count %}{% trans "Refused:" %} {% for reason, count in site_relabel_pairs.last_repair.failed_by_reason %}{{ reason }} × {{ count }}{% if not forloop.last %}, {% endif %}{% endfor %} {% if site_relabel_pairs.last_repair.blocking_models %} — {% trans "blocked by" %} {% for model, count in site_relabel_pairs.last_repair.blocking_models %}{{ model }} × {{ count }}{% if not forloop.last %}, {% endif %}{% endfor %} {% endif %}
{% endif %} {% endif %} {% if site_relabel_pairs.held_count %}{% blocktrans count counter=site_relabel_pairs.held_count %}{{ counter }} duplicated name is held - it cannot be proven safe to merge yet:{% plural %}{{ counter }} duplicated names are held - they cannot be proven safe to merge yet:{% endblocktrans %}
{% trans "This sync created these devices, and the current Forward result no longer covers them. A device disabled in Forward looks exactly like this, so they are kept, not pruned — which is why this count grows. Use the tag to list all of them, not just this sample." %}
{% if payload.unmanaged.owned_absence.available %}{% trans "Why:" %} {% if payload.unmanaged.owned_absence.absent_from_snapshot %} {% blocktrans count counter=payload.unmanaged.owned_absence.absent_from_snapshot %}{{ counter }} gone from Forward{% plural %}{{ counter }} gone from Forward{% endblocktrans %} {% endif %} {% if payload.unmanaged.owned_absence.present_untagged %} {% blocktrans count counter=payload.unmanaged.owned_absence.present_untagged %}{{ counter }} in Forward but untagged{% plural %}{{ counter }} in Forward but untagged{% endblocktrans %} {% endif %} {% if payload.unmanaged.owned_absence.vendor_excluded %} {% blocktrans count counter=payload.unmanaged.owned_absence.vendor_excluded %}{{ counter }} custom-command source{% plural %}{{ counter }} custom-command source{% endblocktrans %} {% endif %}
{% if payload.unmanaged.owned_absence.endpoint_detail %}{% trans "Of those Forward still has, these are SNMP endpoints the endpoint scope excludes:" %} {% for row in payload.unmanaged.owned_absence.endpoint_detail %} {{ row.count }} — {{ row.label }} {% endfor %} {% trans "A console server in that list means its endpoint tags match none of the include tags; a generic endpoint or CIMC controller is excluded by design." %}
{% endif %} {% if payload.unmanaged.owned_absence.absent_detail %} {% comment %} "Tagged in Forward but not in NetBox" is what a customer reads off Forward's Device Tags page, which shows the configuration; the sync reads the snapshot. Name the configuration fact so the gap is not filed as a sync bug. {% endcomment %}{% blocktrans count counter=payload.unmanaged.owned_absence.absent_still_tagged %}Of those gone from Forward, its device configuration still lists {{ counter }} under an include tag:{% plural %}Of those gone from Forward, its device configuration still lists {{ counter }} under an include tag:{% endblocktrans %} {% for row in payload.unmanaged.owned_absence.absent_detail %} {{ row.count }} — {{ row.label }} {% endfor %} {% trans "Forward's UI shows these as tagged; the snapshot the sync reads does not carry them, so they cannot be tagged or updated in NetBox. Re-enable collection in Forward to cover a disabled device again." %}
{% endif %} {% elif payload.unmanaged.owned_absence %}{% trans "The Forward census that classifies the cause did not run for this report." %}
{% endif %}{% blocktrans with count=payload.unmanaged.owned_untagged %}List all {{ count }}{% endblocktrans %} {% trans "Filter devices by tag" %}
{# The tag list above is not this sync's count: it is one tag shared #} {# by every sync, so a device another sync uncovered - or one this #} {# sync has since covered again - still carries it and still shows #} {# up there. A customer bulk-deleted from exactly that list reading #} {# "546 uncovered" against a sync whose own card said 107. #}{% trans "The tag list is shared by every sync and kept from earlier runs; a device another sync uncovered, or one this sync has since covered again, still carries it. List all above is this sync's current count." %}
{% comment %} Only the devices Forward no longer reports at all are eligible, so the button counts `absent_from_snapshot` rather than the card's own total. Offering the larger number would promise a deletion the gates refuse, which is how an operator learns to distrust the panel. {% endcomment %} {% if perms.dcim.delete_device %} {% endif %} {# The orphan card has carried this sentence since the quarantine #} {# shipped; the uncovered card never did, so an operator watching a #} {# count that would not move had nothing on the page explaining why. #} {% if payload.unmanaged.owned_quarantine.required_runs is not None %}{% blocktrans with runs=payload.unmanaged.owned_quarantine.required_runs hours=payload.unmanaged.owned_quarantine.required_hours %}A device disabled in Forward disappears exactly as a removed one does, so an absence must persist for {{ runs }} consecutive syncs and {{ hours }} hours before the prune will delete it. Devices that reappear leave quarantine automatically.{% endblocktrans %}
{% endif %}{{ name }}{% blocktrans with shown=payload.unmanaged.owned_untagged_sample|length total=payload.unmanaged.owned_untagged %}Showing {{ shown }} of {{ total }}.{% endblocktrans %}
{% endif %} {% else %}{% trans "Every device this sync created is covered by the current Forward result." %}
{% endif %}{% trans "Devices this sync never created: another source, an operator, or an old SNMP endpoint import. Listed so the count above can be accounted for — this sync makes no claim about them, tags none of them, and never prunes them." %}
{% blocktrans with count=payload.unmanaged.unclaimed %}List all {{ count }}{% endblocktrans %}
{{ name }}{% blocktrans with shown=payload.unmanaged.unclaimed_sample|length total=payload.unmanaged.unclaimed %}Showing {{ shown }} of {{ total }}.{% endblocktrans %}
{% endif %} {% else %}{% trans "Every uncovered device was created by this sync." %}
{% endif %}