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.
Mutations in the Infrahub SDK allow you to create, update, and delete objects in your infrastructure data model.
Creating Objects
Basic Create
Create a new object:
from infrahub_sdk import InfrahubClient
client = InfrahubClient()
# Create the object
device = await client.create(
kind = "InfraDevice" ,
name = "router-01" ,
description = "Edge router in NYC" ,
status = "active"
)
# Save to Infrahub
await device.save()
print ( f "Created device with ID: { device.id } " )
Remember to call save() after creating an object. The create() method only initializes the object locally.
Create with Relationships
Create objects with related entities:
# Get related objects first
site = await client.get( kind = "InfraSite" , name__value = "NYC" )
role = await client.get( kind = "BuiltinRole" , name__value = "edge" )
# Create device with relationships
device = await client.create(
kind = "InfraDevice" ,
name = "router-02" ,
site = site,
role = role,
status = "active"
)
await device.save()
Create in a Branch
Create objects in a specific branch:
device = await client.create(
branch = "feature-new-devices" ,
kind = "InfraDevice" ,
name = "router-03" ,
status = "active"
)
await device.save()
Create with Protected Values
Mark attribute values as protected:
device = await client.create(
kind = "InfraDevice" ,
name = {
"value" : "router-04" ,
"is_protected" : True # Protect from changes
},
status = "active"
)
await device.save()
Create with Source Tracking
Track the source of attribute values:
# Get source account
account = await client.get( kind = "CoreAccount" , name = "admin" )
device = await client.create(
kind = "InfraDevice" ,
name = {
"value" : "router-05" ,
"source" : account.id # Track who set this value
},
status = "active"
)
await device.save()
Updating Objects
Basic Update
Update an existing object:
# Get the object
device = await client.get(
kind = "InfraDevice" ,
name__value = "router-01"
)
if device:
# Update attributes
device.description.value = "Updated description"
device.status.value = "maintenance"
# Save changes
await device.save()
print ( f "Updated { device.name.value } " )
Update Multiple Attributes
Update several attributes at once:
device = await client.get( kind = "InfraDevice" , id = "abc-123" )
if device:
device.name.value = "router-01-updated"
device.description.value = "Updated router"
device.status.value = "active"
await device.save()
Update Relationships
Change relationships to other objects:
device = await client.get( kind = "InfraDevice" , id = "abc-123" )
# Get new related objects
new_site = await client.get( kind = "InfraSite" , name__value = "LAX" )
new_role = await client.get( kind = "BuiltinRole" , name__value = "core" )
if device:
# Update relationships
device.site.peer = new_site
device.role.peer = new_role
await device.save()
Update in a Branch
Make updates in a specific branch:
device = await client.get(
branch = "feature-updates" ,
kind = "InfraDevice" ,
id = "abc-123"
)
if device:
device.status.value = "maintenance"
await device.save()
Protect Attributes
Protect attribute values from changes:
device = await client.get( kind = "InfraDevice" , id = "abc-123" )
if device:
device.name.value = "router-01-prod"
device.name.is_protected = True # Protect from future changes
await device.save()
Deleting Objects
Basic Delete
Delete an object:
# Get the object
device = await client.get(
kind = "InfraDevice" ,
name__value = "router-test"
)
if device:
# Delete it
await client.delete( node = device)
print ( f "Deleted { device.name.value } " )
Delete by ID
Delete using object ID:
device = await client.get( kind = "InfraDevice" , id = "abc-123" )
if device:
await client.delete( node = device)
Delete in a Branch
Delete objects in a specific branch:
device = await client.get(
branch = "feature-cleanup" ,
kind = "InfraDevice" ,
id = "abc-123"
)
if device:
await client.delete( node = device)
Working with Many Relationships
Add to Many Relationship
Add items to a many relationship:
device = await client.get( kind = "InfraDevice" , id = "abc-123" )
tag1 = await client.get( kind = "BuiltinTag" , name__value = "production" )
tag2 = await client.get( kind = "BuiltinTag" , name__value = "critical" )
if device:
# Add tags (many relationship)
device.tags.peers = [tag1, tag2]
await device.save()
Update Many Relationship
Replace all items in a many relationship:
device = await client.get( kind = "InfraDevice" , id = "abc-123" )
# Get new tags
new_tags = await client.filters(
kind = "BuiltinTag" ,
name__value__in = [ "production" , "network" , "edge" ]
)
if device:
# Replace all tags
device.tags.peers = new_tags
await device.save()
Remove from Many Relationship
Remove specific items:
device = await client.get( kind = "InfraDevice" , id = "abc-123" )
if device:
# Get current tags
current_tags = await device.tags.fetch()
# Filter out tags to remove
new_tags = [tag for tag in current_tags if tag.name.value != "old-tag" ]
# Update
device.tags.peers = new_tags
await device.save()
GraphQL Mutations
Custom Mutations
Build custom GraphQL mutations:
from infrahub_sdk.graphql import Mutation
# Define a custom mutation
mutation = Mutation(
mutation = {
"InfraDeviceCreate" : {
"__args" : {
"data" : {
"name" : { "value" : "router-06" },
"status" : { "value" : "active" }
}
},
"object" : {
"id" : None ,
"name" : { "value" : None }
}
}
}
)
# Execute the mutation
result = await client.execute_graphql( query = mutation.render_query())
Upsert Pattern
Create or update based on existence:
async def upsert_device ( name : str , ** attributes ):
client = InfrahubClient()
# Try to get existing
device = await client.get(
kind = "InfraDevice" ,
name__value = name
)
if device:
# Update existing
for attr, value in attributes.items():
setattr ( getattr (device, attr), 'value' , value)
else :
# Create new
device = await client.create(
kind = "InfraDevice" ,
name = name,
** attributes
)
await device.save()
return device
# Usage
device = await upsert_device(
name = "router-01" ,
status = "active" ,
description = "Updated or created"
)
Bulk Operations
Create Multiple Objects
Create many objects efficiently:
# Create a batch
batch = await client.create_batch()
# Add multiple creates
for i in range ( 10 ):
device = await client.create(
kind = "InfraDevice" ,
name = f "router- { i :02d} " ,
status = "active"
)
batch.add( task = device.save, node = device)
# Execute all at once
async for node, result in batch.execute():
print ( f "Created: { node.name.value } " )
See Batch Operations for more details.
Update Multiple Objects
Update many objects in bulk:
# Get devices to update
devices = await client.filters(
kind = "InfraDevice" ,
status__value = "provisioning"
)
# Create batch
batch = await client.create_batch()
# Update each
for device in devices:
device.status.value = "active"
batch.add( task = device.save, node = device)
# Execute
async for node, result in batch.execute():
print ( f "Updated: { node.name.value } " )
Delete Multiple Objects
Delete many objects:
# Get objects to delete
old_devices = await client.filters(
kind = "InfraDevice" ,
status__value = "obsolete"
)
# Delete each
for device in old_devices:
await client.delete( node = device)
print ( f "Deleted: { device.name.value } " )
Validation
Handle Validation Errors
Catch validation errors during save:
from infrahub_sdk.exceptions import GraphQLError
try :
device = await client.create(
kind = "InfraDevice" ,
name = "" , # Invalid: empty name
status = "active"
)
await device.save()
except GraphQLError as e:
print ( f "Validation error: { e.message } " )
# Handle the error
Uniqueness Constraints
Handle uniqueness constraint violations:
try :
device = await client.create(
kind = "InfraDevice" ,
name = "router-01" , # Name already exists
status = "active"
)
await device.save()
except GraphQLError as e:
if "unique" in e.message.lower():
print ( "Device with this name already exists" )
else :
raise
Transaction Patterns
Rollback on Failure
Use branches for transaction-like behavior:
async def safe_multi_create ():
client = InfrahubClient()
# Create a temporary branch
branch = await client.branch.create(
branch_name = "temp-transaction" ,
description = "Temporary transaction branch"
)
try :
# Create objects in the branch
device1 = await client.create(
branch = "temp-transaction" ,
kind = "InfraDevice" ,
name = "router-01"
)
await device1.save()
device2 = await client.create(
branch = "temp-transaction" ,
kind = "InfraDevice" ,
name = "router-02"
)
await device2.save()
# If successful, merge to main
await client.branch.merge( branch_name = "temp-transaction" )
except Exception as e:
# On error, delete the branch (rollback)
await client.branch.delete( branch_name = "temp-transaction" )
raise e
Examples
Create Site and Devices
async def setup_site ( site_name : str , device_count : int ):
client = InfrahubClient()
# Create site
site = await client.create(
kind = "InfraSite" ,
name = site_name,
description = f " { site_name } datacenter"
)
await site.save()
print ( f "Created site: { site.name.value } " )
# Create devices
batch = await client.create_batch()
for i in range ( 1 , device_count + 1 ):
device = await client.create(
kind = "InfraDevice" ,
name = f " { site_name.lower() } -router- { i :02d} " ,
site = site,
status = "active"
)
batch.add( task = device.save, node = device)
async for node, result in batch.execute():
print ( f "Created device: { node.name.value } " )
# Usage
await setup_site( "NYC" , 5 )
Update Device Status
async def set_maintenance_mode ( device_name : str ):
client = InfrahubClient()
device = await client.get(
kind = "InfraDevice" ,
name__value = device_name
)
if device:
# Update status
device.status.value = "maintenance"
# Add maintenance tag
maint_tag = await client.get(
kind = "BuiltinTag" ,
name__value = "maintenance"
)
if maint_tag:
current_tags = await device.tags.fetch()
device.tags.peers = current_tags + [maint_tag]
await device.save()
print ( f "Set { device_name } to maintenance mode" )
# Usage
await set_maintenance_mode( "router-01" )
Decommission Device
async def decommission_device ( device_id : str ):
client = InfrahubClient()
device = await client.get( kind = "InfraDevice" , id = device_id)
if device:
# Update status
device.status.value = "obsolete"
await device.save()
# Wait for confirmation
print ( f "Device { device.name.value } marked as obsolete" )
# Delete after marking obsolete
await client.delete( node = device)
print ( f "Deleted device { device.name.value } " )
# Usage
await decommission_device( "abc-123" )
Error Handling
Common Patterns
from infrahub_sdk.exceptions import (
GraphQLError,
ValidationError,
Error
)
async def safe_create_device ( name : str , ** kwargs ):
client = InfrahubClient()
try :
device = await client.create(
kind = "InfraDevice" ,
name = name,
** kwargs
)
await device.save()
return device
except GraphQLError as e:
if "unique" in e.message.lower():
print ( f "Device { name } already exists" )
# Return existing device
return await client.get(
kind = "InfraDevice" ,
name__value = name
)
else :
print ( f "GraphQL error: { e.message } " )
raise
except Error as e:
print ( f "SDK error: { e.message } " )
raise
Next Steps
Batch Operations Learn efficient bulk operations
Queries Query data from Infrahub