Skip to content

Commit d371735

Browse files
committed
fix sequential load
1 parent c2253a9 commit d371735

File tree

4 files changed

+47
-10
lines changed

4 files changed

+47
-10
lines changed

docs/docs/concepts.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ The demo uses composable building blocks to construct complex network architectu
4444

4545
### Composition model
4646

47-
```
47+
```tree
4848
Topology Design
4949
├─ Device Templates (spine, leaf, border-leaf)
5050
├─ Connectivity Patterns (fabric peering)
@@ -256,7 +256,7 @@ Artifacts are the final outputs that deploy to devices. The demo generates confi
256256
257257
### Artifact generation flow
258258
259-
```
259+
```text
260260
GraphQL Query → Transform → Template → Artifact
261261
```
262262

@@ -391,7 +391,7 @@ This allows generators to create infrastructure in parallel.
391391

392392
Resource pools support hierarchy for delegation:
393393

394-
```
394+
```tree
395395
Root Pool (10.0.0.0/8)
396396
├─ Region 1 (10.0.0.0/16)
397397
│ ├─ DC-1 (10.0.0.0/20)

docs/docs/developer-guide.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ This guide provides a technical deep-dive into how the Infrahub demo works under
88

99
The demo follows Infrahub's SDK pattern with five core component types working together:
1010

11-
```
11+
```text
1212
Schemas → Data → Generators → Transforms → Configurations
1313
1414
Checks (Validation)
@@ -385,7 +385,7 @@ Bootstrap data provides initial objects like locations, platforms, and device ty
385385

386386
### Bootstrap structure
387387

388-
```
388+
```tree
389389
objects/bootstrap/
390390
├── 01_organizations.yml # Organizations
391391
├── 02_asn_pools.yml # BGP ASN pools

generators/common.py

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,21 +76,23 @@ async def _create_in_batch(
7676
self,
7777
kind: str,
7878
data_list: list,
79+
allow_upsert: bool = False,
7980
) -> None:
8081
"""
8182
Create objects of a specific kind and store in local store.
8283
8384
Args:
8485
kind: The kind of object to create.
8586
data_list: List of data dictionaries for creation.
87+
allow_upsert: Whether to allow upsert operations. Use False for new devices to prevent race conditions.
8688
"""
8789
batch = await self.client.create_batch()
8890
for data in data_list:
8991
try:
9092
obj = await self.client.create(
9193
kind=kind, data=data.get("payload"), branch=self.branch
9294
)
93-
batch.add(task=obj.save, allow_upsert=True, node=obj)
95+
batch.add(task=obj.save, allow_upsert=allow_upsert, node=obj)
9496
if data.get("store_key"):
9597
self.client.store.set(
9698
key=data.get("store_key"), node=obj, branch=self.branch
@@ -110,6 +112,40 @@ async def _create_in_batch(
110112
except ValidationError as exc:
111113
self.log.debug(f"- Creation failed due to {exc}")
112114

115+
async def _create_sequentially(
116+
self,
117+
kind: str,
118+
data_list: list,
119+
) -> None:
120+
"""
121+
Create objects sequentially (one at a time) with upsert enabled.
122+
This prevents race conditions while maintaining idempotency.
123+
124+
Args:
125+
kind: The kind of object to create.
126+
data_list: List of data dictionaries for creation.
127+
"""
128+
for data in data_list:
129+
try:
130+
obj = await self.client.create(
131+
kind=kind, data=data.get("payload"), branch=self.branch
132+
)
133+
await obj.save(allow_upsert=True)
134+
if data.get("store_key"):
135+
self.client.store.set(
136+
key=data.get("store_key"), node=obj, branch=self.branch
137+
)
138+
object_reference = (
139+
" ".join(obj.hfid) if obj.hfid else obj.display_label
140+
)
141+
self.log.info(
142+
f"- Created [{obj.get_kind()}] {object_reference}"
143+
if object_reference
144+
else f"- Created [{obj.get_kind()}]"
145+
)
146+
except (GraphQLError, ValidationError) as exc:
147+
self.log.debug(f"- Creation failed due to {exc}")
148+
113149
async def _create(self, kind: str, data: dict) -> None:
114150
"""
115151
Create an object of a specific kind and store in local store.
@@ -214,6 +250,7 @@ async def create_address_pools(self, subnets: list[dict]) -> None:
214250
}
215251
for pool in subnets
216252
],
253+
allow_upsert=True,
217254
)
218255

219256
async def create_split_loopback_pools(self, technical_subnet_obj: Any) -> None:
@@ -382,7 +419,7 @@ async def create_devices(self) -> None:
382419
("DcimVirtualDevice", virtual_devices),
383420
]:
384421
if devices:
385-
await self._create_in_batch(kind=kind, data_list=devices)
422+
await self._create_sequentially(kind=kind, data_list=devices)
386423

387424
self.devices = [
388425
self.client.store.get_by_hfid(f"DcimGenericDevice__{device[0]}")

scripts/bootstrap.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ uv run infrahubctl object load objects/bootstrap/ --branch $BRANCH
1313
echo "Load security data"
1414
uv run infrahubctl object load objects/security/ --branch $BRANCH
1515

16-
# echo "Add demo repository"
17-
# uv run infrahubctl repository add DEMO https://github.com/opsmill/infrahub-demo.git --ref main --read-only
16+
echo "Add demo repository"
17+
uv run infrahubctl repository add DEMO https://github.com/opsmill/infrahub-demo.git --ref main --read-only
1818

1919
echo "Add event actions"
20-
sleep 30
20+
sleep 60
2121
uv run infrahubctl object load objects/events/ --branch $BRANCH
2222

0 commit comments

Comments
 (0)