Skip to main content

How to Configure Schema Mappings

This guide shows you how to configure schema mappings to control how Infrahub data translates into Nornir inventory properties. Schema mappings are the bridge between your Infrahub data model and Nornir's expected host attributes.

What you'll accomplish

By following this guide, you'll be able to:

  • Map Infrahub node attributes to Nornir host properties
  • Handle nested relationships and complex data structures
  • Create custom mappings for specialized use cases
  • Debug and troubleshoot mapping issues

Prerequisites

  • Working Nornir-Infrahub installation
  • Understanding of your Infrahub schema (see example schema in Getting Started)
  • Access to Infrahub GraphQL explorer (for testing queries)

Understanding schema mappings

Schema mappings define how to extract values from Infrahub nodes and assign them to Nornir host properties. Each mapping consists of:

  • name: The Nornir property to set (i.e., "hostname", "platform")
  • mapping: The path to the value in the Infrahub node (i.e., "primary_address.address")

Step 1: Identify required Nornir properties

First, determine which Nornir properties your automation tasks need:

PropertyPurposeCommon Mapping Source
hostnameIP/FQDN for connectionsDevice primary address
platformDevice OS typePlatform or OS attribute
usernameAuthentication userCredential or static value
passwordAuthentication passwordCredential or static value
portConnection portInterface or static value
dataCustom dataAny Infrahub attributes

Step 2: Explore your Infrahub schema

Use the Infrahub GraphQL explorer to understand available attributes. Based on the example schema from the Getting Started guide, you can query:

query {
InfraDevice {
edges {
node {
name {
value
}
primary_address {
node {
address {
value
}
}
}
platform {
node {
name {
value
}
nornir_platform {
value
}
}
}
site {
node {
name {
value
}
}
}
role {
node {
name {
value
}
}
}
}
}
}
}

This helps you identify the exact paths to your data based on your schema structure.

Step 3: Configure basic mappings

Basic attribute mapping

For direct attributes on the node:

schema_mappings:
- name: "hostname"
mapping: "name" # Maps device name to hostname

Nested relationship mapping

For attributes through relationships (based on the example schema):

schema_mappings:
- name: "hostname"
mapping: "primary_address.address" # Traverses to InfraIPAddress node
- name: "platform"
mapping: "platform.nornir_platform" # Traverses to InfraPlatform node

Multiple level nesting

For deeply nested data:

schema_mappings:
- name: "location"
mapping: "site.location.name" # Multiple relationships

Step 4: Handle complex mappings

IP address handling

Infrahub stores IP addresses as interface objects. The integration automatically extracts the IP:

schema_mappings:
- name: "hostname"
mapping: "primary_address.address" # Automatically converts IPHost to string

Handling missing attributes

When a mapping fails (for example, relationship doesn't exist), it's silently skipped:

schema_mappings:
- name: "hostname"
mapping: "primary_address.address" # Skipped if primary_address is not set
- name: "management_ip"
mapping: "primary_address.address" # Only sets hostname if relationship exists

Note: The plugin does not support fallback mappings. Each mapping is independent.

Custom data mappings

Additional attributes from Infrahub nodes are stored in the host's data dictionary:

def example_task(task):
# Access the Infrahub node data
infrahub_node = task.host.data["InfrahubNode"]

# Access node attributes directly
if hasattr(infrahub_node, 'serial_number'):
serial = infrahub_node.serial_number.value
print(f"Device {task.host.name} serial: {serial}")

Note: Custom schema mappings create Nornir host properties for standard attributes like hostname and platform. Additional node data is accessible through the InfrahubNode object.

Step 5: Configure group mappings

Group mappings create dynamic Nornir groups from Infrahub relationships:

group_mappings:
- "site.name" # Creates groups like "site__chicago"
- "role.name" # Creates groups like "role__spine"
- "platform.name" # Creates groups like "platform__eos"

Groups are automatically prefixed with the relationship name to avoid conflicts.

Step 6: Test your mappings

Create a test script to verify mappings:

from nornir import InitNornir
import json

def test_mappings():
nr = InitNornir(config_file="config.yaml")

# Check a specific host
if "router1" in nr.inventory.hosts:
host = nr.inventory.hosts["router1"]
print(f"Host: {host.name}")
print(f"Hostname: {host.hostname}")
print(f"Platform: {host.platform}")
print(f"Groups: {[g.name for g in host.groups]}")
print(f"Data: {json.dumps(host.data, indent=2)}")

# List all groups
print("\nAll groups:")
for group in nr.inventory.groups:
print(f" - {group}")

if __name__ == "__main__":
test_mappings()

Validation

Check mapping success

After configuration, verify:

  1. All hosts have required properties set
  2. Groups are created as expected
  3. No mapping errors in logs

Common validation commands

# Check all hosts have hostname
for host in nr.inventory.hosts.values():
assert host.hostname is not None, f"{host.name} missing hostname"

# Verify platform mappings
platforms = {h.platform for h in nr.inventory.hosts.values()}
print(f"Discovered platforms: {platforms}")

# Check group membership
for group in nr.inventory.groups.values():
print(f"{group.name}: {len(group.hosts)} hosts")

Advanced usage

Using mapping results in tasks

Access mapped data in your tasks:

def device_info(task):
# Access standard properties
print(f"Connecting to {task.host.hostname}")
print(f"Platform: {task.host.platform}")

# Access custom mapped attributes
if hasattr(task.host, 'serial_number'):
print(f"Serial: {task.host.serial_number}")

# Access Infrahub node
node = task.host.data["InfrahubNode"]
print(f"Infrahub ID: {node.id}")

Dynamic mapping based on node type

For environments with multiple device types:

# Router-specific mappings
host_node:
kind: "InfraRouter"

schema_mappings:
- name: "hostname"
mapping: "loopback0.address"
- name: "platform"
mapping: "platform.nornir_platform"

# Switch-specific mappings (different config file)
host_node:
kind: "InfraSwitch"

schema_mappings:
- name: "hostname"
mapping: "management_ip.address"
- name: "platform"
mapping: "platform.nornir_platform"

Troubleshooting mapping failures

If mappings fail silently:

  1. Enable debug logging:
import logging
logging.basicConfig(level=logging.DEBUG)
  1. Check the Infrahub GraphQL query:
# Add to your script
print(nr.inventory.hosts["device1"].data["InfrahubNode"]._raw_data)
  1. Verify relationship cardinality:
  • Single relationships: mapping: "platform.name"
  • Many relationships not supported directly