Netbox Sync MAC Addresses Task¤
task api name:
sync_mac_addresses
The Netbox Sync MAC Addresses Task synchronizes interface MAC addresses from live network devices into NetBox. The task collects current MAC address state from devices, compares it against existing NetBox MAC address objects, and applies create or update operations to bring NetBox into alignment.
How It Works¤
The task follows a three-step pipeline:
- Collect live state — Run a Nornir
parse_ttpjob against the target devices to collect live MAC addresses per interface. - Fetch NetBox state — Retrieve existing MAC address objects from NetBox for the discovered MACs.
- Reconcile — Compare live versus NetBox state and apply changes:
- Create — MAC not present in NetBox at all: create a new MAC address object assigned to the correct interface.
- Update — MAC exists in NetBox but has no
assigned_object(unassigned): assign it to the correct interface. - In sync — MAC already assigned to the correct interface: no action needed.
- Error — MAC exists in NetBox and is assigned to a different interface: report a conflict error without modifying the record.
Output¤
Both dry-run and live-run return the same structure, keyed by device name:
{
"<device>": {
"created": ["aa:bb:cc:dd:ee:01", "aa:bb:cc:dd:ee:02"],
"updated": ["aa:bb:cc:dd:ee:03"],
"in_sync": ["aa:bb:cc:dd:ee:04"]
}
}
In dry-run mode (dry_run=True) the lists reflect what would happen — no changes are written to NetBox.
With Review — Pass with_review=True to use interactive NFCLI workflow. Sync task displays its preview, and waits for approval before applying changes. Declining at that point will return dry-run result.
Note
When both dry-run and with_review are True, dry-run logic ignored.
In live-run mode (dry_run=False, default) the lists reflect what was actually done.
Conflict errors (MAC assigned to a different interface) are reported in res["errors"] and do not appear in any action list.
Filtering¤
MAC address collection can be scoped using glob patterns so that only a subset of interfaces and MACs is considered:
filter_by_name— match interface names, e.g."Loopback*"or"Ethernet[1-4]"filter_by_description— match interface descriptions, e.g."uplink*"or"p2p*"filter_by_mac— match MAC address strings, e.g."aa:bb:cc:*"
All filters are applied before the reconciliation step. Interfaces or MACs that do not match are completely ignored — they are neither created nor updated.
Special Handling¤
Duplicate MAC Handling¤
NetBox permits multiple MAC address records with the same MAC value. The task handles this safely:
- If a MAC exists in NetBox with an assigned interface that matches the live data — reported as
in_sync. - If a MAC exists in NetBox with an assigned interface that differs from the live data — reported as a conflict error; the record is not modified.
- If a MAC exists in NetBox but is unassigned — the record is updated to point at the correct interface.
- If both an assigned (conflicting) and an unassigned copy of the same MAC exist in NetBox, the assigned (conflicting) entry takes precedence and a conflict error is raised.
Deletion Behavior¤
By default, all discovered live MAC addresses are managed by this task. MACs present in NetBox but absent from live devices are left untouched. There is no explicit deletion mechanism — instead, unused MAC records are managed through standard NetBox administrative procedures.
Branching Support¤
The task is branch-aware and can push changes into a NetBox branch. The Netbox Branching Plugin must be installed. Specify the branch parameter; the branch is created automatically if it does not already exist.
Examples¤
Sync MAC addresses for a list of devices:
nf#netbox sync mac-addresses devices ceos-spine-1 ceos-spine-2
Preview changes without writing to NetBox (dry run):
nf#netbox sync mac-addresses devices ceos-spine-1 dry-run
Restrict sync to Ethernet interfaces only:
nf#netbox sync mac-addresses devices ceos-spine-1 filter-by-name "Ethernet*"
Restrict sync to interfaces whose description matches a glob pattern:
nf#netbox sync mac-addresses devices ceos-spine-1 filter-by-description "uplink*"
Restrict sync to a specific MAC prefix:
nf#netbox sync mac-addresses devices ceos-spine-1 filter-by-mac "aa:bb:cc:*"
Sync MAC addresses into a NetBox branch:
nf#netbox sync mac-addresses devices ceos-spine-1 ceos-spine-2 branch sprint-42-macs
Sync using Nornir host filters instead of explicit device names:
nf#netbox sync mac-addresses FC spine
from norfab.core.nfapi import NorFab
nf = NorFab(inventory="./inventory.yaml")
nf.start()
client = nf.make_client()
# sync MAC addresses for specific devices
result = client.run_job(
"netbox",
"sync_mac_addresses",
workers="any",
kwargs={
"devices": ["ceos-spine-1", "ceos-spine-2"],
},
)
# dry run — preview creates/updates without writing
result = client.run_job(
"netbox",
"sync_mac_addresses",
workers="any",
kwargs={
"devices": ["ceos-spine-1", "ceos-spine-2"],
"dry_run": True,
},
)
# restrict sync to Ethernet interfaces only
result = client.run_job(
"netbox",
"sync_mac_addresses",
workers="any",
kwargs={
"devices": ["ceos-spine-1"],
"filter_by_name": "Ethernet*",
},
)
# restrict sync to interfaces with a specific description pattern
result = client.run_job(
"netbox",
"sync_mac_addresses",
workers="any",
kwargs={
"devices": ["ceos-spine-1"],
"filter_by_description": "uplink*",
},
)
# restrict sync to a specific MAC prefix
result = client.run_job(
"netbox",
"sync_mac_addresses",
workers="any",
kwargs={
"devices": ["ceos-spine-1"],
"filter_by_mac": "aa:bb:cc:*",
},
)
# sync into a NetBox branch
result = client.run_job(
"netbox",
"sync_mac_addresses",
workers="any",
kwargs={
"devices": ["ceos-spine-1", "ceos-spine-2"],
"branch": "sprint-42-macs",
},
)
# use Nornir host filters instead of explicit device names
result = client.run_job(
"netbox",
"sync_mac_addresses",
workers="any",
kwargs={
"FC": "spine",
},
)
nf.destroy()
NORFAB Netbox Sync MAC Addresses Command Shell Reference¤
NorFab shell supports these command options for the sync_mac_addresses task:
nf# man tree netbox.sync.mac-addresses
root
└── netbox: Netbox service
└── sync: Sync Netbox data
└── mac-addresses: Sync device MAC addresses with NetBox
├── timeout: Job timeout in seconds
├── workers: Filter worker to target, default 'any'
├── verbose-result: Control output details, default 'False'
├── progress: Display progress events, default 'True'
├── instance: Netbox instance name to target
├── dry-run: Return reconciliation plan without pushing changes to NetBox
├── devices: List of NetBox device names to sync
├── filter-by-name: Glob pattern to restrict sync by interface name, e.g. 'Ethernet*'
├── filter-by-description: Glob pattern to restrict sync by interface description
├── filter-by-mac: Glob pattern to restrict sync by MAC address, e.g. 'aa:bb:*'
├── branch: Branching plugin branch name to push changes into
├── FO: Filter Nornir hosts using Filter Object
├── FB: Filter Nornir hosts by name using Glob Patterns
├── FH: Filter Nornir hosts by hostname
├── FC: Filter Nornir hosts by name containment
├── FR: Filter Nornir hosts by name using Regular Expressions
├── FG: Filter Nornir hosts by group
├── FP: Filter Nornir hosts by hostname using IP Prefix
├── FL: Filter Nornir hosts by names list
├── FM: Filter Nornir hosts by platform
└── FN: Negate the Nornir host filter match
nf#
Python API Reference¤
Synchronize MAC addresses from live devices into NetBox.
The task follows a three-step pipeline:
- Collect live state: Run a Nornir
parse_ttpget interfaces job against devices to collect live MAC addresses per interface. - Fetch NetBox state: Retrieve existing MAC address objects from NetBox.
- Reconcile: Create new MAC address objects or update existing unassigned ones to point at the correct interface.
Dry-run mode (dry_run=True): returns the reconciliation plan without
making any changes. Result is keyed by device name::
{
"<device>": {
"created": ["aa:bb:cc:dd:ee:01", ...],
"updated": ["aa:bb:cc:dd:ee:02", ...],
"in_sync": ["aa:bb:cc:dd:ee:03", ...]
}
}
Live-run mode (dry_run=False, default): applies changes and returns
the same structure showing what was done.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
job
|
Job
|
NorFab Job object containing relevant metadata. |
required |
instance
|
str
|
The NetBox instance name to use. |
None
|
dry_run
|
bool
|
If True, no changes will be made to NetBox. |
False
|
with_review
|
bool
|
Preview changes, ask for review, then apply them. |
False
|
timeout
|
int
|
Timeout in seconds for the Nornir parse_ttp job. |
600
|
devices
|
list
|
List of device names to sync. |
None
|
branch
|
str
|
NetBox branch name to use. |
None
|
filter_by_name
|
str
|
Glob pattern to restrict which interfaces
are included by name, e.g. |
None
|
filter_by_description
|
str
|
Glob pattern to restrict which
interfaces are included by description, e.g. |
None
|
filter_by_mac
|
str
|
Glob pattern to restrict which MAC addresses
are included, e.g. |
None
|
**kwargs
|
Any
|
Additional Nornir host filter keyword arguments passed to
|
{}
|
Returns:
| Name | Type | Description |
|---|---|---|
Result |
Result
|
Per-device action summary with |
Source code in norfab\workers\netbox_worker\interfaces_tasks.py
1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 | |