Skip to content

Commit f5ee201

Browse files
allenrobelclaude
andcommitted
Add bulk create and delete support to LoopbackInterfaceOrchestrator
Leverage NDBaseOrchestrator bulk infrastructure from PR #223 to reduce API calls. create_bulk groups interfaces by switch and sends one POST per switch instead of one per interface. delete_bulk queues all removals for deferred execution via remove_pending/deploy_pending. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 5cf894f commit f5ee201

File tree

1 file changed

+57
-1
lines changed

1 file changed

+57
-1
lines changed

plugins/module_utils/orchestrators/loopback_interface.py

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020

2121
from __future__ import annotations
2222

23-
from typing import ClassVar, Optional, Type
23+
from collections import defaultdict
24+
from typing import ClassVar, List, Optional, Type
2425

2526
from ansible_collections.cisco.nd.plugins.module_utils.endpoints.base import NDEndpointBaseModel
2627
from ansible_collections.cisco.nd.plugins.module_utils.endpoints.v1.manage.manage_interfaces import (
@@ -76,12 +77,16 @@ class LoopbackInterfaceOrchestrator(NDBaseOrchestrator[LoopbackInterfaceModel]):
7677
"""
7778

7879
model_class: ClassVar[Type[NDBaseModel]] = LoopbackInterfaceModel
80+
supports_bulk_create: ClassVar[bool] = True
81+
supports_bulk_delete: ClassVar[bool] = True
7982

8083
create_endpoint: Type[NDEndpointBaseModel] = EpManageInterfacesPost
8184
update_endpoint: Type[NDEndpointBaseModel] = EpManageInterfacesPut
8285
delete_endpoint: Type[NDEndpointBaseModel] = NDEndpointBaseModel # unused; delete() uses bulk remove
8386
query_one_endpoint: Type[NDEndpointBaseModel] = EpManageInterfacesGet
8487
query_all_endpoint: Type[NDEndpointBaseModel] = EpManageInterfacesListGet
88+
create_bulk_endpoint: Type[NDEndpointBaseModel] = EpManageInterfacesPost
89+
delete_bulk_endpoint: Type[NDEndpointBaseModel] = EpManageInterfacesRemove
8590

8691
deploy: bool = True
8792

@@ -338,6 +343,57 @@ def delete(self, model_instance: LoopbackInterfaceModel, **kwargs) -> None:
338343
self._queue_remove(model_instance.interface_name, switch_id)
339344
self._queue_deploy(model_instance.interface_name, switch_id)
340345

346+
def create_bulk(self, model_instances: List[LoopbackInterfaceModel], **kwargs) -> ResponseType:
347+
"""
348+
# Summary
349+
350+
Create multiple loopback interfaces in bulk. Groups interfaces by switch and sends one POST per switch with all
351+
interfaces in the `interfaces` array, reducing API calls from N to one-per-switch. Queues deploys for all created
352+
interfaces for later bulk execution via `deploy_pending`.
353+
354+
## Raises
355+
356+
### RuntimeError
357+
358+
- If any create API request fails.
359+
"""
360+
try:
361+
groups: dict[str, list[tuple[str, dict]]] = defaultdict(list)
362+
for model_instance in model_instances:
363+
switch_id = self._resolve_switch_id(model_instance.switch_ip)
364+
payload = model_instance.to_payload()
365+
payload["switchId"] = switch_id
366+
groups[switch_id].append((model_instance.interface_name, payload))
367+
368+
results = []
369+
for switch_id, items in groups.items():
370+
api_endpoint = self._configure_endpoint(self.create_bulk_endpoint(), switch_sn=switch_id)
371+
request_body = {"interfaces": [payload for _, payload in items]}
372+
result = self.sender.request(path=api_endpoint.path, method=api_endpoint.verb, data=request_body)
373+
results.append(result)
374+
for interface_name, _ in items:
375+
self._queue_deploy(interface_name, switch_id)
376+
return results
377+
except Exception as e:
378+
raise RuntimeError(f"Bulk create failed: {e}") from e
379+
380+
def delete_bulk(self, model_instances: List[LoopbackInterfaceModel], **kwargs) -> None:
381+
"""
382+
# Summary
383+
384+
Queue multiple loopback interfaces for deferred bulk removal and deployment. Each interface is queued for removal
385+
via `remove_pending` and deployment via `deploy_pending`. No API calls are made until those methods are called
386+
after `manage_state` completes.
387+
388+
## Raises
389+
390+
None
391+
"""
392+
for model_instance in model_instances:
393+
switch_id = self._resolve_switch_id(model_instance.switch_ip)
394+
self._queue_remove(model_instance.interface_name, switch_id)
395+
self._queue_deploy(model_instance.interface_name, switch_id)
396+
341397
def query_one(self, model_instance: LoopbackInterfaceModel, **kwargs) -> ResponseType:
342398
"""
343399
# Summary

0 commit comments

Comments
 (0)