Skip to content

Commit 6269987

Browse files
authored
Convert Object Docs (#7453)
* feat(docs): update object conversion guide and sidebar integration * feat(tests): add screenshot functionality for object conversion tests and include new images * Alter formatting * fix(tests): remove unnecessary blank line in object conversion test
1 parent d64c2b3 commit 6269987

File tree

6 files changed

+332
-18
lines changed

6 files changed

+332
-18
lines changed
Lines changed: 222 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,233 @@
11
---
2-
title: Converting an Object Type
2+
title: How to convert object types
33
---
44

5-
It may happen that you created an object with a type A, and would like to convert it to a similar type B. Infrahub offers a way to convert an object type,
6-
without having to manually deleting and recreating it.
5+
import Tabs from '@theme/Tabs';
6+
import TabItem from '@theme/TabItem';
77

8-
## How to convert an object?
8+
# How to convert object types
99

10-
Currently, mutation `ConvertObjectType` is the only way to convert an object type. It will soon be possible to do it from both the web application and the SDK.
11-
Converting an object requires that any mandatory field present in the destination schema type to be specified. Note that equivalent fields, if not specified, are automatically filled in:
10+
This guide shows how to convert an existing object from one type to another without having to manually delete and recreate it. This is useful when you need to change an object's schema type while preserving its data and relationships.
1211

13-
- Two attribute fields in two distinct schemas are considered to be equivalent if they have both the same name and value type.
14-
- Two relationship fields in two distinct schemas are considered to be equivalent if they have the same name, peer schema type, and cardinality.
12+
## Introduction
1513

16-
# Case of agnostic object having branch aware attributes
14+
Object type conversion allows you to transform an object from one schema type to another compatible type. For example, you might need to convert a Layer 3 interface to a Layer 2 interface, or change a read-only repository to a read-write repository.
1715

18-
For technical reasons, converting an agnostic object having branch aware attribute would remove values of these attributes on the non-conversion branches.
19-
Therefore, converting such an object has some current limitations:
16+
The conversion process automatically maps equivalent fields between the source and destination types, and allows you to specify values for any mandatory fields that don't have equivalent mappings.
2017

21-
- Conversion is only allowed on the default branch (usually `main`).
22-
- Doing such a conversion would automatically put other branches in a `NEED_REBASE` state. No write-operation can be performed on a branch with this state until it is rebased.
23-
- Branch aware attributes values on other branches are lost (these attributes no longer exist on those branches).
18+
## Prerequisites
2419

25-
# Converting a repository
20+
Before starting, ensure you have:
2621

27-
It is possible to convert a read-only repository to a read-write repository and vice versa. As they are both agnostic objects having branch aware attributes (`commit`),
28-
they follow above restrictions on converting agnostic objects having branch aware attributes.
22+
- An existing object that you want to convert
23+
- Access to Infrahub through the web interface, GraphQL API, or Python SDK
24+
- Understanding of both the source and destination schema types
25+
- Values ready for any mandatory fields in the destination type that don't exist in the source type
26+
27+
## Step 1: Identify equivalent fields
28+
29+
Infrahub automatically identifies equivalent fields between source and destination types based on these criteria:
30+
31+
- **Attribute fields** are equivalent if they have the same name and value type
32+
- **Relationship fields** are equivalent if they have the same name, peer schema type, and cardinality
33+
34+
Fields that match these criteria will be automatically mapped during conversion.
35+
36+
## Step 2: Convert the object type
37+
38+
<Tabs>
39+
<TabItem value="web" label="Web Interface" default>
40+
41+
Navigate to the object you want to convert and select **Convert object type** from the actions dropdown menu.
42+
43+
![Convert Object Button](../media/object_convert_button.png)
44+
45+
Infrahub displays a mapping interface showing how fields from the source type will map to the destination type. The interface automatically maps equivalent fields and highlights any mandatory fields that require values.
46+
47+
![Convert Object](../media/object_convert_mapping.png)
48+
49+
Review the field mappings and provide values for any mandatory fields that don't have automatic mappings. Click **Convert** to complete the process.
50+
51+
</TabItem>
52+
53+
<TabItem value="graphql" label="GraphQL">
54+
55+
First, query the field mapping between source and destination types to understand what values you need to provide:
56+
57+
```graphql
58+
query GetMapping {
59+
FieldsMappingTypeConversion(
60+
source_kind: "InfraInterfaceL3"
61+
target_kind: "InfraInterfaceL2"
62+
) {
63+
mapping
64+
}
65+
}
66+
```
67+
68+
The response shows the mapping between source and destination fields, indicating which fields are mandatory and which have automatic mappings:
69+
70+
```json
71+
{
72+
"data": {
73+
"FieldsMappingTypeConversion": {
74+
"mapping": {
75+
"lacp_priority": {
76+
"is_mandatory": false,
77+
"source_field_name": "lacp_priority",
78+
"relationship_cardinality": null
79+
},
80+
"l2_mode": {
81+
"is_mandatory": true,
82+
"source_field_name": null,
83+
"relationship_cardinality": null
84+
},
85+
"name": {
86+
"is_mandatory": true,
87+
"source_field_name": "name",
88+
"relationship_cardinality": null
89+
},
90+
"device": {
91+
"is_mandatory": true,
92+
"source_field_name": "device",
93+
"relationship_cardinality": "one"
94+
}
95+
// Additional fields omitted for brevity
96+
}
97+
}
98+
}
99+
}
100+
```
101+
102+
Use this mapping information to build the conversion mutation, providing values for mandatory fields that don't have source mappings:
103+
104+
```graphql
105+
mutation ConvertType {
106+
ConvertObjectType(
107+
data: {
108+
node_id: "18703746-7b3b-442e-3027-10657106d6f9"
109+
target_kind: "InfraInterfaceL2"
110+
fields_mapping: {
111+
device: {
112+
source_field: "device"
113+
},
114+
l2_mode: {
115+
data: {
116+
attribute_value: "Access"
117+
}
118+
},
119+
name: {
120+
source_field: "name"
121+
},
122+
connected_endpoint: {
123+
source_field: "connected_endpoint"
124+
},
125+
lag: {
126+
use_default_value: true
127+
},
128+
untagged_vlan: {
129+
use_default_value: true
130+
},
131+
tagged_vlan: {
132+
use_default_value: true
133+
}
134+
// Additional field mappings as needed
135+
}
136+
}
137+
) {
138+
node
139+
__typename
140+
}
141+
}
142+
```
143+
144+
</TabItem>
145+
<TabItem value="sdk" label="Python SDK">
146+
147+
Use the Python SDK to convert an object type by first retrieving the object and then calling the conversion method:
148+
149+
```python
150+
from infrahub_sdk import InfrahubClientSync
151+
from infrahub_sdk.convert_object_type import ConversionFieldInput, ConversionFieldValue
152+
153+
client = InfrahubClientSync(address="http://localhost:8000")
154+
155+
# Get the object to convert
156+
interface = client.get(
157+
kind="InfraInterfaceL3",
158+
name__value="Ethernet1",
159+
device__name__value="ord1-edge2"
160+
)
161+
162+
# Define field mappings for the conversion
163+
fields_mapping = {
164+
"device": ConversionFieldInput(source_field="device"),
165+
"l2_mode": ConversionFieldInput(
166+
data=ConversionFieldValue(attribute_value="Access")
167+
),
168+
"name": ConversionFieldInput(source_field="name"),
169+
"connected_endpoint": ConversionFieldInput(source_field="connected_endpoint"),
170+
"speed": ConversionFieldInput(source_field="speed"),
171+
"lag": ConversionFieldInput(use_default_value=True),
172+
"untagged_vlan": ConversionFieldInput(use_default_value=True),
173+
"tagged_vlan": ConversionFieldInput(use_default_value=True),
174+
# Add additional mappings as needed
175+
}
176+
177+
# Perform the conversion
178+
new_interface = client.convert_object_type(
179+
node_id=interface.id,
180+
target_kind="InfraInterfaceL2",
181+
branch=client.default_branch,
182+
fields_mapping=fields_mapping,
183+
)
184+
185+
print(f"Conversion successful. New interface kind: {new_interface.get_kind()}")
186+
```
187+
188+
</TabItem>
189+
</Tabs>
190+
191+
## Step 3: Verify the conversion
192+
193+
After converting the object, verify that the conversion was successful:
194+
195+
1. **Check the object type**: Confirm that the object now shows the correct destination type
196+
2. **Verify field values**: Ensure that all data was transferred correctly and new mandatory fields have appropriate values
197+
3. **Test relationships**: Confirm that relationships to other objects are still intact and functioning properly
198+
199+
:::success
200+
If the conversion completed without errors, your object has been successfully converted to the new type with all compatible data preserved.
201+
:::
202+
203+
## Advanced usage
204+
205+
### Converting objects with branch-aware attributes
206+
207+
Objects that have branch-aware attributes require special consideration during conversion:
208+
209+
:::warning
210+
Converting objects with branch-aware attributes has important limitations that affect other branches in your repository.
211+
:::
212+
213+
**Limitations:**
214+
215+
- Conversion is only allowed on the default branch (usually `main`)
216+
- Other branches will automatically enter a `NEED_REBASE` state after conversion
217+
- Branch-aware attribute values on non-conversion branches will be lost
218+
- No write operations can be performed on affected branches until they are rebased
219+
220+
### Handling mandatory fields without source mappings
221+
222+
When the destination type has mandatory fields that don't exist in the source type, you must provide values:
223+
224+
- **Use explicit values**: Provide specific attribute values or relationship targets
225+
- **Use default values**: Allow Infrahub to use schema-defined defaults where available
226+
- **Use computed values**: Let relationship fields use computed defaults when appropriate
227+
228+
## Related resources
229+
230+
- [Object conversion topic](../topics/object-conversion) - Understanding the concepts behind object conversion
231+
- [Schema management guide](./create-schema) - Creating and modifying schema types
232+
233+
git checkout -b atg-20251020-infp-258
114 KB
Loading
108 KB
Loading
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
---
2+
title: Object conversion
3+
---
4+
5+
# Object conversion
6+
7+
Object conversion in Infrahub provides a powerful mechanism to transform existing objects from one schema type to another without losing data or breaking relationships. This capability addresses the common infrastructure management challenge of evolving data models while preserving existing configurations and connections.
8+
9+
## Introduction
10+
11+
In dynamic infrastructure environments, the need to change an object's type often arises as requirements evolve. Traditional approaches typically require deleting the original object and manually recreating it with the new type, leading to data loss and broken relationships. Infrahub's object conversion feature eliminates this friction by providing a seamless transformation process.
12+
13+
## How object conversion works
14+
15+
### Field mapping and equivalence
16+
17+
Object conversion operates on the principle of field equivalence between source and destination schema types. The system automatically identifies compatible fields using specific criteria:
18+
19+
**Attribute field equivalence:**
20+
21+
- Fields must have identical names
22+
- Fields must have compatible value types
23+
- Data validation rules are preserved during conversion
24+
25+
**Relationship field equivalence:**
26+
27+
- Fields must have identical names
28+
- Fields must reference the same peer schema type
29+
- Cardinality constraints (one-to-one, one-to-many) must match
30+
31+
### Automatic mapping process
32+
33+
When initiating a conversion, Infrahub performs these steps:
34+
35+
1. **Schema analysis**: Compares source and destination schema definitions to identify equivalent fields
36+
2. **Compatibility check**: Validates that the conversion is technically feasible
37+
3. **Mandatory field identification**: Highlights destination fields that require explicit values
38+
4. **Data transformation**: Executes the conversion while preserving data integrity
39+
40+
### Handling non-equivalent fields
41+
42+
Not all fields between schema types will have direct equivalents. The conversion process handles these scenarios:
43+
44+
**Missing source fields:**
45+
46+
- Destination fields without source equivalents must be manually specified
47+
- Mandatory destination fields require explicit values or use of defaults
48+
- Optional fields can leverage schema-defined default values
49+
50+
**Surplus source fields:**
51+
52+
- Source fields without destination equivalents are gracefully ignored
53+
- Data from these fields is not transferred but doesn't impede conversion
54+
- Historical data remains accessible through version control
55+
56+
## Design considerations and constraints
57+
58+
### Version control integration
59+
60+
Object conversion integrates deeply with Infrahub's Git-like branching model, but this creates important constraints:
61+
62+
**Branch-aware attributes:**
63+
64+
Objects containing branch-aware attributes (fields that can have different values across branches) require special handling. These conversions:
65+
66+
- Must occur on the default branch to maintain data consistency
67+
- Trigger automatic rebase requirements for other branches
68+
- May result in data loss on non-conversion branches
69+
70+
**Commit preservation:**
71+
The conversion process maintains object history and commit lineage, ensuring auditability and rollback capabilities.
72+
73+
### Data integrity safeguards
74+
75+
Several mechanisms protect data integrity during conversion:
76+
77+
**Validation enforcement:**
78+
79+
- All destination schema constraints are validated before conversion
80+
- Referential integrity for relationships is maintained
81+
- Data type compatibility is strictly enforced
82+
83+
**Atomic operations:**
84+
85+
- Conversions execute as atomic transactions
86+
- Failures result in complete rollback with no partial state
87+
- Concurrent modifications are handled through Infrahub's conflict resolution
88+
89+
## Common use cases
90+
91+
### Infrastructure evolution
92+
93+
**Network interface type changes:**
94+
Converting between Layer 2 and Layer 3 interfaces as network designs evolve, preserving device associations and configuration parameters while adapting to new operational requirements.
95+
96+
**Repository access model changes:**
97+
Transforming read-only repositories to read-write repositories when teams gain modification privileges, maintaining Git integration while expanding access controls.
98+
99+
## Related concepts
100+
101+
Object conversion intersects with several other Infrahub concepts:
102+
103+
- **[Schema management](./schema)**: Understanding how schema types define conversion possibilities
104+
- **[Version control](./version-control)**: How conversions interact with branch and merge operations
105+
- **[Metadata](./metadata)**: How object metadata is preserved during conversion
106+
- **[GraphQL](./graphql)**: The API mechanisms that enable conversion operations

docs/sidebars.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ const sidebars: SidebarsConfig = {
247247
'topics/metadata',
248248
'topics/groups',
249249
'topics/graphql',
250+
'topics/object-conversion',
250251
'topics/resource-manager',
251252
'topics/object-template',
252253
'topics/profiles',

frontend/app/tests/e2e/objects/convert/object-convert.spec.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { expect, test } from "@playwright/test";
22

33
import { ACCOUNT_STATE_PATH } from "../../../constants";
4-
import { generateRandomBranchName } from "../../../utils";
4+
import { generateRandomBranchName, saveScreenshotForDocs } from "../../../utils";
55
import { createBranchAPI, deleteBranchAPI } from "../../utils/graphql";
66

77
test.describe("Object details - convert", () => {
@@ -22,6 +22,7 @@ test.describe("Object details - convert", () => {
2222
await page.goto(`/objects/InfraInterface?branch=${BRANCH_NAME}`);
2323
await page.getByRole("link", { name: "atl1-edge1, Ethernet1", exact: true }).click();
2424
await page.getByTestId("object-details-button").click();
25+
await saveScreenshotForDocs(page, "object_convert_button");
2526
await page.getByRole("menuitem", { name: "Convert object type" }).click();
2627
await expect(page.getByText("SOURCE")).toBeVisible();
2728
await expect(page.getByText("NameEthernet1")).toBeVisible();
@@ -35,6 +36,7 @@ test.describe("Object details - convert", () => {
3536
await expect(
3637
page.getByRole("combobox").filter({ hasText: "atl1-edge1• Device" })
3738
).toBeVisible();
39+
await saveScreenshotForDocs(page, "object_convert_mapping");
3840
await page.getByRole("combobox").filter({ hasText: "atl1-edge1• Device" }).click();
3941

4042
await expect(page.getByRole("option", { name: "atl1-edge1 Matched Device" })).toBeVisible();

0 commit comments

Comments
 (0)