Skip to main content

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