Documentation Index Fetch the complete documentation index at: https://mintlify.com/OpsMill/infrahub/llms.txt
Use this file to discover all available pages before exploring further.
The Infrahub Python SDK provides powerful methods to query and retrieve infrastructure data.
Basic Queries
Get a Single Object by ID
Retrieve an object using its unique identifier:
from infrahub_sdk import InfrahubClient
client = InfrahubClient()
device = await client.get(
kind = "InfraDevice" ,
id = "abc-123-def-456"
)
print ( f "Device: { device.name.value } " )
print ( f "Serial: { device.serial_number.value } " )
Get All Objects of a Kind
Retrieve all objects of a specific type:
devices = await client.all( kind = "InfraDevice" )
print ( f "Total devices: { len (devices) } " )
for device in devices:
print ( f " - { device.name.value } " )
Get with Specific Attributes
Retrieve an object with specific attribute values:
# Get by name (if unique)
device = await client.get(
kind = "InfraDevice" ,
name__value = "router-01" # Use attribute filters
)
Including Relationships
Fetch related data in a single query:
device = await client.get(
kind = "InfraDevice" ,
id = "device-id" ,
include = [ "location" , "tags" ] # Include relationships
)
# Access related data
print ( f "Location: { device.location.name.value } " )
print ( f "Tags: { [tag.name.value for tag in device.tags] } " )
Include Nested Relationships
device = await client.get(
kind = "InfraDevice" ,
id = "device-id" ,
include = [
"location" ,
"location__parent" , # Nested relationship
"tags"
]
)
print ( f "Location: { device.location.name.value } " )
if device.location.parent:
print ( f "Parent Location: { device.location.parent.name.value } " )
Include All Relationships
# Include all direct relationships
device = await client.get(
kind = "InfraDevice" ,
id = "device-id" ,
include = "all"
)
Property Mode
Retrieve additional property information:
device = await client.get(
kind = "InfraDevice" ,
id = "device-id" ,
property = True # Include property metadata
)
# Access property metadata
print ( f "Name: { device.name.value } " )
print ( f "Name updated at: { device.name.updated_at } " )
print ( f "Name is from profile: { device.name.is_from_profile } " )
print ( f "Name source: { device.name.source } " )
Property mode includes metadata like:
updated_at: When the attribute was last modified
is_from_profile: Whether the value comes from a profile
source: The source of the attribute value
owner: Who owns/set the value
Filtering Results
Filter by Attribute Values
While the SDK doesn’t provide built-in filtering on all(), you can filter in Python:
all_devices = await client.all( kind = "InfraDevice" )
# Filter by attribute
routers = [
device for device in all_devices
if device.device_type.value == "router"
]
# Filter by name pattern
prod_devices = [
device for device in all_devices
if "prod" in device.name.value.lower()
]
Custom GraphQL Queries
For complex filtering, use custom GraphQL queries:
query = """
query GetDevicesByType($device_type: String!) {
InfraDevice(device_type__value: $device_type) {
edges {
node {
id
name {
value
}
serial_number {
value
}
}
}
}
}
"""
variables = { "device_type" : "router" }
result = await client.execute_graphql(
query = query,
variables = variables
)
devices = result[ "InfraDevice" ][ "edges" ]
for device in devices:
print (device[ "node" ][ "name" ][ "value" ])
Accessing Attributes
Basic Attribute Access
Attributes are accessed with .value:
device = await client.get( kind = "InfraDevice" , id = "device-id" )
# Read attribute values
name = device.name.value
serial = device.serial_number.value
height = device.height.value # Integer/Number
is_active = device.is_active.value # Boolean
Attribute Types
Different attribute kinds:
# Text
device.name.value # str
# Number
device.height.value # int
# Boolean
device.is_active.value # bool
# DateTime
device.commissioned_at.value # datetime object
# JSON
device.metadata.value # dict or list
# IPAddress
device.ip_address.value # str (IP address)
Accessing Relationships
Single Cardinality Relationships
Relationships with cardinality “one”:
device = await client.get(
kind = "InfraDevice" ,
id = "device-id" ,
include = [ "location" ]
)
# Access the related object's ID
location_id = device.location.id
# Access the related object's attributes (if included)
location_name = device.location.name.value
Multiple Cardinality Relationships
Relationships with cardinality “many”:
device = await client.get(
kind = "InfraDevice" ,
id = "device-id" ,
include = [ "tags" ]
)
# Iterate over related objects
for tag in device.tags:
print ( f "Tag: { tag.name.value } " )
# Get list of IDs
tag_ids = device.tags.peer_ids # List of UUIDs
# Count related objects
tag_count = len (device.tags)
device = await client.get(
kind = "InfraDevice" ,
id = "device-id" ,
include = [ "location" ],
property = True
)
# Access relationship properties
print ( f "Location ID: { device.location.id } " )
print ( f "Location updated: { device.location.updated_at } " )
print ( f "From profile: { device.location.is_from_profile } " )
Querying on Branches
Query on a Specific Branch
# Query on main branch (default)
device = await client.get(
kind = "InfraDevice" ,
id = "device-id"
)
# Query on a different branch
device_on_branch = await client.get(
kind = "InfraDevice" ,
id = "device-id" ,
branch = "feature-branch"
)
Compare Across Branches
# Get object on main branch
main_device = await client.get(
kind = "InfraDevice" ,
id = "device-id" ,
branch = "main"
)
# Get same object on feature branch
feature_device = await client.get(
kind = "InfraDevice" ,
id = "device-id" ,
branch = "feature-update"
)
# Compare values
if main_device.name.value != feature_device.name.value:
print ( f "Name changed: { main_device.name.value } -> { feature_device.name.value } " )
Handling Missing Data
Check for None Values
device = await client.get( kind = "InfraDevice" , id = "device-id" )
# Optional attributes may be None
if device.description.value is None :
print ( "No description set" )
else :
print ( f "Description: { device.description.value } " )
Handle Missing Relationships
device = await client.get(
kind = "InfraDevice" ,
id = "device-id" ,
include = [ "location" ]
)
# Check if relationship exists
if device.location:
print ( f "Location: { device.location.name.value } " )
else :
print ( "No location assigned" )
Try-Except for Not Found
from infrahub_sdk.exceptions import NodeNotFoundError
try :
device = await client.get(
kind = "InfraDevice" ,
id = "nonexistent-id"
)
except NodeNotFoundError:
print ( "Device not found" )
Querying Schema
# Fetch schema for specific namespaces
await client.schema.fetch( namespaces = [ "Infra" , "Network" ])
# Get schema for a specific kind
device_schema = await client.schema.get(
kind = "InfraDevice" ,
branch = "main"
)
print ( f "Schema name: { device_schema.name } " )
print ( f "Namespace: { device_schema.namespace } " )
print ( f "Attributes: { [attr.name for attr in device_schema.attributes] } " )
Check Schema Sync Status
# Wait for schema to converge
await client.schema.wait_until_converged( branch = "main" )
# Check if schema is in sync
is_synced = await client.schema.in_sync()
if is_synced:
print ( "Schema is synchronized" )
else :
print ( "Schema update in progress" )
Batch Queries
Query multiple objects efficiently:
device_ids = [ "id-1" , "id-2" , "id-3" ]
# Query all devices
devices = []
for device_id in device_ids:
device = await client.get( kind = "InfraDevice" , id = device_id)
devices.append(device)
Limit Included Relationships
Only include what you need:
# Include only required relationships
device = await client.get(
kind = "InfraDevice" ,
id = "device-id" ,
include = [ "location" ] # Don't include unnecessary relationships
)
For large datasets, use pagination (see Pagination guide ):
# Instead of loading all objects
# all_devices = await client.all(kind="InfraDevice") # May be slow
# Use pagination for large datasets
offset = 0
limit = 100
while True :
batch = await client.execute_graphql(
query = """query GetDevices($offset: Int!, $limit: Int!) {
InfraDevice(offset: $offset, limit: $limit) {
edges { node { id name { value } } }
}
}""" ,
variables = { "offset" : offset, "limit" : limit}
)
devices = batch[ "InfraDevice" ][ "edges" ]
if not devices:
break
for device in devices:
print (device[ "node" ][ "name" ][ "value" ])
offset += limit
Common Query Patterns
Get Object with Full Context
device = await client.get(
kind = "InfraDevice" ,
id = "device-id" ,
include = [ "location" , "tags" , "manufacturer" ],
property = True
)
Search by Attribute Value
all_devices = await client.all( kind = "InfraDevice" )
target_device = next (
(d for d in all_devices if d.serial_number.value == "SN12345" ),
None
)
if target_device:
print ( f "Found: { target_device.name.value } " )
Count Objects
devices = await client.all( kind = "InfraDevice" )
total = len (devices)
active = sum ( 1 for d in devices if d.is_active.value)
inactive = total - active
print ( f "Total: { total } , Active: { active } , Inactive: { inactive } " )
Next Steps
Creating Objects Learn how to create new infrastructure objects
Updating Objects Update existing objects and attributes
Relationships Work with object relationships
Pagination Handle large datasets with pagination