|
1 | 1 | --- |
2 | | -title: Converting an Object Type |
| 2 | +title: How to convert object types |
3 | 3 | --- |
4 | 4 |
|
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'; |
7 | 7 |
|
8 | | -## How to convert an object? |
| 8 | +# How to convert object types |
9 | 9 |
|
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. |
12 | 11 |
|
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 |
15 | 13 |
|
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. |
17 | 15 |
|
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. |
20 | 17 |
|
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 |
24 | 19 |
|
25 | | -# Converting a repository |
| 20 | +Before starting, ensure you have: |
26 | 21 |
|
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 | + |
| 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 | + |
| 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 |
0 commit comments