Skip to content

netops.inventory — Device Discovery

Subnet scanning and automatic device discovery.


netops.inventory.scan

Scan subnets for network devices using ping sweep and SNMP fingerprinting.

Produces ScanResult objects that can be merged into an existing inventory or exported as a new YAML/JSON inventory file.

CLI usage:

python -m netops.inventory.scan --subnet 10.0.0.0/24
python -m netops.inventory.scan --subnet 10.0.0.0/24 --community public
python -m netops.inventory.scan --subnet 10.0.0.0/24 --output inventory.yaml
python -m netops.inventory.scan --subnet 10.0.0.0/24 --json
python -m netops.inventory.scan --subnet 10.0.0.0/24 --deep-enrich

scan

Subnet scanner — discover devices via SNMP/CDP/LLDP/ping sweep.

Usage: python -m netops.inventory.scan --subnet 10.0.0.0/24 --community public python -m netops.inventory.scan --subnet 10.0.0.0/24 --output fragment.json python -m netops.inventory.scan --subnet 10.0.0.0/24 --merge existing.yaml python -m netops.inventory.scan --csv hosts.csv --user admin python -m netops.inventory.scan --hosts-file ips.txt --user admin

Classes
ScanResult dataclass
ScanResult(host: str, reachable: bool, hostname: str | None = None, sys_descr: str | None = None, sys_obj_id: str | None = None, vendor: str | None = None, location: str | None = None, cdp_neighbors: list[dict] = list(), lldp_neighbors: list[dict] = list(), error: str | None = None, version: str | None = None, model: str | None = None, serial: str | None = None, uptime: str | None = None, image: str | None = None, hardware_revision: str | None = None, total_memory: str | None = None, free_memory: str | None = None, reload_reason: str | None = None, mac_address: str | None = None, config_register: str | None = None, cpu_type: str | None = None, flash_size: str | None = None, domain_name: str | None = None, interface_count: str | None = None)

Scan result for a single host.

Methods:
to_inventory_entry
to_inventory_entry() -> dict

Convert to an inventory device dict (compatible with core.Inventory).

Functions:
ping_host
ping_host(host: str, timeout: int = 1, count: int = 1) -> bool

Return True if host responds to ICMP ping.

ping_sweep
ping_sweep(subnet: str, max_workers: int = 50, timeout: int = 1) -> list[str]

Ping sweep a subnet and return a sorted list of reachable IP address strings.

Args: subnet: CIDR notation subnet (e.g. "10.0.0.0/24"). max_workers: Thread pool size for concurrent pings. timeout: Per-host ping timeout in seconds.

identify_vendor
identify_vendor(sys_descr: str, sys_obj_id: str = '') -> str

Map sysDescr / sysObjectID to a Netmiko-compatible vendor string.

Returns one of: cisco_ios, cisco_xe, cisco_xr, cisco_nxos, nokia_sros, nokia_srl, juniper_junos, arista_eos, brocade_fastiron, brocade_nos, or "unknown".

scan_subnet_async async
scan_subnet_async(subnet: str, community: str = 'public', snmp_port: int = 161, snmp_timeout: int = 2, ping_workers: int = 50, ping_timeout: int = 1, snmp_concurrency: int = 10, skip_ping: bool = False, skip_snmp: bool = False) -> list[ScanResult]

Async implementation of the full subnet scan pipeline.

scan_subnet
scan_subnet(subnet: str, community: str = 'public', snmp_port: int = 161, snmp_timeout: int = 2, ping_workers: int = 50, ping_timeout: int = 1, snmp_concurrency: int = 10, skip_ping: bool = False, skip_snmp: bool = False) -> list[ScanResult]

Full subnet scan: ping sweep → SNMP identification → CDP/LLDP topology.

Args: subnet: CIDR notation subnet (e.g. "10.0.0.0/24"). community: SNMPv2c community string. snmp_port: SNMP UDP port (default 161). snmp_timeout: Per-host SNMP timeout in seconds. ping_workers: Ping sweep thread-pool size. ping_timeout: Per-host ping timeout in seconds. snmp_concurrency: Max simultaneous SNMP sessions. skip_ping: Skip ping sweep and probe all addresses in the subnet. skip_snmp: Skip SNMP — perform a ping-sweep only.

Returns:

list Sorted list of :class:ScanResult objects (one per reachable host).

Requires: pysnmp >= 7.0. Install with pip install 'netops-toolkit[snmp]'.

scan_subnet_through_active_bastion
scan_subnet_through_active_bastion(subnet: str, ssh_port: int = 22, max_workers: int = 50, timeout: int = 3) -> list[ScanResult]

Discover SSH-reachable hosts through the selected workstation bastion.

SSH forwarding transports TCP, not local ICMP or UDP. When a bastion is active, discovery therefore probes each address's SSH port through the shared SOCKS service instead of incorrectly running ping/SNMP on the workstation's local network.

results_to_inventory_fragment
results_to_inventory_fragment(results: list[ScanResult]) -> dict

Convert scan results to an inventory fragment ({"devices": {...}} dict).

The fragment is compatible with :class:netops.core.Inventory and can be written directly as a JSON file or merged into an existing inventory.

merge_inventory
merge_inventory(existing_path: str, fragment: dict) -> dict

Merge a scan fragment into an existing inventory file.

New devices are added. Existing entries are updated only where the current value is None, "unknown", or "" — manually-set values are never overwritten.

Args: existing_path: Path to an existing YAML or JSON inventory file. If the file does not exist, an empty inventory is used as the base. fragment: Inventory fragment produced by :func:results_to_inventory_fragment.

Returns:

dict Merged inventory dict.

deep_enrich
deep_enrich(fragment: dict, username: str, password: str, concurrency: int = 5, timeout: int = 15, port: int | None = None, community_registry: CommunityRegistry | None = None) -> dict

Enrich an inventory fragment with SSH-gathered details.

Connects to each device in the fragment, auto-detects vendor if unknown, and updates vendor, version, model, serial in-place.

Args: fragment: Inventory fragment ({"devices": {...}}). username: SSH username for all devices. password: SSH password for all devices. concurrency: Max parallel SSH sessions. timeout: Per-device connection timeout in seconds. port: Optional SSH port override. community_registry: Optional privileged registry for discovered SNMP communities. Values are never copied into the inventory fragment.

Returns:

dict The enriched fragment (modified in-place and returned).

main
main() -> None

CLI entry point for the network device discovery scanner.