mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-09-02 16:15:15 +03:00
feat: Jinja2 template support in device_config_send
- Add optional 'template' param with Jinja2 syntax - Each device entry can use 'vars' dict instead of 'config_commands' - Template rendered per device, merged with existing commands - Rendering errors returned inline for AI self-correction
This commit is contained in:
parent
c647805cfb
commit
06e1511773
@ -1296,9 +1296,15 @@ async def device_config_send(
|
||||
device_configs: Annotated[list, Field(
|
||||
description="List of device configs. Each entry: {\"device_name\": \"R1\", \"config_commands\": [\"int lo0\", \"ip add 1.1.1.1 255.255.255.255\"]}"
|
||||
)],
|
||||
template: Annotated[str | None, Field(description="Optional Jinja2 template. Use with vars in each device to reduce token usage for batch config. Example: \"interface lo{{ n }}\\nip address {{ ip }} 255.255.255.255\"")] = None,
|
||||
) -> list[dict[str, Any]]:
|
||||
"""Send configuration commands to network devices via console (telnet/SSH).
|
||||
|
||||
Two modes:
|
||||
1. Direct commands: each device has config_commands=[...]
|
||||
2. Jinja2 template: provide template + vars per device — template is rendered for each
|
||||
Example: device_configs=[{\"device_name\": \"R1\", \"vars\": {\"n\": 0, \"ip\": \"1.1.1.1\"}}]
|
||||
|
||||
Devices must be started first (use node_start or node_start_all).
|
||||
Device type is auto-detected from the 'device_type:<type>' tag on each node.
|
||||
Common device types: cisco_ios_telnet, cisco_xr_telnet, huawei_telnet, gns3_huawei_telnet_ce
|
||||
|
||||
@ -33,18 +33,52 @@ import json
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from jinja2 import Template as JinjaTemplate, TemplateError as JinjaError
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _render_template(template: str, device_configs: list[dict]) -> list[dict]:
|
||||
"""Render a Jinja2 template for each device's vars into config_commands.
|
||||
|
||||
Each device in device_configs can have:
|
||||
- "vars": dict of template variables (rendered into config_commands)
|
||||
- "config_commands": merged after rendering if already present
|
||||
"""
|
||||
jinja = JinjaTemplate(template)
|
||||
results = []
|
||||
for dev in device_configs:
|
||||
rendered = dev.copy()
|
||||
vars_data = rendered.pop("vars", {})
|
||||
if vars_data:
|
||||
try:
|
||||
output = jinja.render(**vars_data)
|
||||
lines = [l for l in output.splitlines() if l.strip()]
|
||||
existing = rendered.get("config_commands", [])
|
||||
rendered["config_commands"] = existing + lines
|
||||
except JinjaError as e:
|
||||
error_msg = f"Template rendering failed for '{dev.get('device_name')}': {e}"
|
||||
log.error(error_msg)
|
||||
return [{"error": error_msg}]
|
||||
results.append(rendered)
|
||||
return results
|
||||
|
||||
|
||||
# ── Tool handlers ──────────────────────────────────────────────────────────
|
||||
|
||||
def device_config_send_handler(params: dict[str, Any], gns3_ctx: dict[str, Any]) -> list[dict[str, Any]]:
|
||||
"""Send configuration commands to network devices via console."""
|
||||
project_id = params.get("project_id")
|
||||
device_configs = params.get("device_configs")
|
||||
template = params.get("template")
|
||||
if not project_id or not device_configs:
|
||||
return [{"error": "project_id and device_configs are required"}]
|
||||
|
||||
if template:
|
||||
device_configs = _render_template(template, device_configs)
|
||||
if len(device_configs) == 1 and "error" in device_configs[0]:
|
||||
return device_configs
|
||||
|
||||
from gns3server.agent.gns3_copilot.tools_v2.config_tools_nornir import ExecuteMultipleDeviceConfigCommands
|
||||
|
||||
tool = ExecuteMultipleDeviceConfigCommands()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user