Groups organize related objects into collections for easier management, bulk operations, and access control. Use them to group devices by location, role, or any other criteria.
Group Types
Infrahub provides two types of groups:
| Type | Description | Use Case |
|---|
| Standard Group | Static membership defined manually | Production devices, critical infrastructure |
| Dynamic Group | Membership based on query filters | All routers, devices in Atlanta, etc. |
Creating Standard Groups
Standard groups have fixed membership that you manage manually.
- Navigate to Groups
- Click Add Group
- Set group properties:
- Name: Descriptive name (e.g., “Production Routers”)
- Description: Purpose of the group
- Label: Optional display label
- Add members:
- Click Add Members
- Select objects to include
- Click Save
- Click Save
mutation {
CoreStandardGroupCreate(
data: {
name: { value: "production-routers" }
description: { value: "Production edge routers" }
label: { value: "Production Routers" }
members: [
{ id: "<device-1-uuid>" },
{ id: "<device-2-uuid>" },
{ id: "<device-3-uuid>" }
]
}
) {
ok
object {
id
display_label
members {
count
}
}
}
}
from infrahub_sdk import InfrahubClient
client = InfrahubClient()
# Fetch devices to add as members
devices = await client.all(
kind="InfraDevice",
role__name__value="edge-router"
)
# Create group with members
group = await client.create(
kind="CoreStandardGroup",
name="production-routers",
description="Production edge routers",
label="Production Routers",
members=[device.id for device in devices]
)
await group.save()
print(f"Created group with {len(devices)} members")
Creating Dynamic Groups
Dynamic groups automatically include objects matching filter criteria.
Dynamic groups are currently in development. The API may change.
- Navigate to Groups
- Click Add Group
- Select Dynamic Group
- Set:
- Name: Group name
- Description: Purpose
- Object Type: Kind to filter (e.g.,
InfraDevice)
- Filters: Criteria for membership
- Attribute filters (e.g.,
status = active)
- Relationship filters (e.g.,
site = Atlanta)
- Click Save
Members are automatically added/removed as objects match the filters.mutation {
CoreDynamicGroupCreate(
data: {
name: { value: "atlanta-devices" }
description: { value: "All devices in Atlanta" }
object_kind: { value: "InfraDevice" }
filters: {
site__name__value: "atl1"
status__value: "active"
}
}
) {
ok
object {
id
members {
count
}
}
}
}
The filters structure matches GraphQL query filter syntax.from infrahub_sdk import InfrahubClient
client = InfrahubClient()
group = await client.create(
kind="CoreDynamicGroup",
name="atlanta-devices",
description="All devices in Atlanta",
object_kind="InfraDevice",
filters={
"site__name__value": "atl1",
"status__value": "active"
}
)
await group.save()
# Query members (auto-populated)
members = await group.members.fetch()
print(f"Group has {len(members)} members")
Managing Group Membership
Adding Members
- Open the group detail page
- Click Members tab
- Click Add Members
- Select objects to add
- Click Save
mutation {
CoreStandardGroupUpdate(
data: {
id: "<group-uuid>"
members: [
{ id: "<existing-member-1>" },
{ id: "<existing-member-2>" },
{ id: "<new-member-uuid>" } # Add this member
]
}
) {
ok
}
}
Include all existing members plus new ones. Omitted members are removed.from infrahub_sdk import InfrahubClient
client = InfrahubClient()
# Fetch the group
group = await client.get(
kind="CoreStandardGroup",
name__value="production-routers"
)
# Fetch existing members
current_members = await group.members.fetch()
member_ids = [m.id for m in current_members]
# Add new member
new_device = await client.get(
kind="InfraDevice",
name__value="router-04"
)
member_ids.append(new_device.id)
# Update group
group.members = member_ids
await group.save()
Removing Members
- Open the group detail page
- Click Members tab
- Select members to remove
- Click Remove
- Confirm removal
mutation {
CoreStandardGroupUpdate(
data: {
id: "<group-uuid>"
members: [
{ id: "<keep-member-1>" },
{ id: "<keep-member-2>" }
# Omit members to remove
]
}
) {
ok
}
}
group = await client.get(
kind="CoreStandardGroup",
id="<group-uuid>"
)
current_members = await group.members.fetch()
# Remove specific device
member_ids = [
m.id for m in current_members
if m.name.value != "router-to-remove"
]
group.members = member_ids
await group.save()
Querying Groups
Get All Groups
query {
CoreStandardGroup {
edges {
node {
id
name { value }
description { value }
members {
count
edges {
node {
id
display_label
}
}
}
}
}
}
}
Get Group Members
query {
CoreStandardGroup(name__value: "production-routers") {
edges {
node {
members {
edges {
node {
... on InfraDevice {
id
name { value }
site {
node {
name { value }
}
}
}
}
}
}
}
}
}
}
Find Groups for an Object
query {
InfraDevice(name__value: "router-01") {
edges {
node {
member_of_groups {
edges {
node {
name { value }
description { value }
}
}
}
}
}
}
}
Group Actions
Groups support actions that run on all members.
Creating Group Actions
mutation {
CoreGroupActionCreate(
data: {
name: { value: "backup-configs" }
description: { value: "Backup device configurations" }
group: { id: "<group-uuid>" }
action_type: { value: "transformation" }
transformation: { id: "<transformation-uuid>" }
}
) {
ok
object {
id
}
}
}
When triggered, the action runs the transformation for each group member.
Triggering Group Actions
mutation {
CoreGroupActionRun(
data: {
id: "<action-uuid>"
}
) {
ok
task_id
}
}
The action executes asynchronously. Track progress using the returned task_id.
Group Permissions
Groups integrate with Infrahub’s permission system for access control.
Grant Group Access
mutation {
CoreAccountGroupCreate(
data: {
name: { value: "network-admins" }
members: [
{ id: "<account-1-uuid>" },
{ id: "<account-2-uuid>" }
]
permissions: [
{
object_group: { id: "<object-group-uuid>" }
permission: { value: "read_write" }
}
]
}
) {
ok
}
}
Members of network-admins can now read/write objects in the specified object group.
Use Cases
Geographic Grouping
Group devices by location:
# Atlanta devices
atl_group = await client.create(
kind="CoreStandardGroup",
name="atlanta-infrastructure",
members=[d.id for d in await client.all(
kind="InfraDevice",
site__name__value="atl1"
)]
)
Role-Based Grouping
Group devices by function:
# Edge routers
edge_group = await client.create(
kind="CoreStandardGroup",
name="edge-routers",
members=[d.id for d in await client.all(
kind="InfraDevice",
role__name__value="edge-router"
)]
)
Maintenance Windows
Group devices with shared maintenance schedules:
# Weekly maintenance group
maint_group = await client.create(
kind="CoreStandardGroup",
name="sunday-maintenance",
description="Devices with Sunday maintenance window"
)
Compliance Grouping
Group devices by compliance requirements:
# PCI-DSS scope
pci_group = await client.create(
kind="CoreStandardGroup",
name="pci-dss-scope",
description="Devices in PCI-DSS scope"
)
Best Practices
- Use descriptive names: Make group purpose clear from the name
- Document purpose: Use
description to explain membership criteria
- Prefer dynamic groups: Automatically maintain membership when possible
- Avoid overlapping groups: Clear boundaries reduce confusion
- Limit group size: Very large groups (1000+ members) may impact performance
- Use groups for permissions: Easier than managing individual object access
- Review membership: Periodically audit group membership for accuracy
Next Steps