It is relatively easy to manage one device via its GUI or CLI. However, managing tens or even hundreds of devices is where efficiency comes into play or falters.
FortiManager offers two main ways of automation in terms of object configuration, interface management, and setting up devices in bulk: Native CLI Scripts and Jinja2 Templates. Although they perform pretty much the same tasks, they differ greatly in terms of their execution, flexibility, and application.
The following text will help you understand when it is better to apply one or another way of management.
1. Native CLI Scripts
Native CLI scripts consist of a sequential list of commands using standard FortiOS commands. The execution is done sequentially on FortiManager, just like a network engineer would paste individual commands while working in an SSH session.
- Execution Environment: It can execute against the Device Database (the policy package or device configuration that is stored on FortiManager before installation) or directly on the Remote FortiGate via CLI (which bypasses FortiManager’s policy DB synchronization and modifies the device itself).
- Support for Logic: Static. Some limited dynamic support through metadata variables such as $(name) and $(ip).
- Error Handling: Sequential. If an error occurs, the script can either abort or proceed based on its global settings, but with limited rollback abilities.
config system dns
set primary 1.1.1.1
set secondary 8.8.8.8
end
config system global
set hostname "FG-$(name)"
end
2. Jinja2 Templates
Jinja2 is an advanced templating engine which is built-in to FortiManager. This engine enables the use of conditionals, loops, variables, and math operations in your definition.
- Execution Context: Evaluated dynamically at deployment time with FortiManager metadata, device variables, and CLI template groups.
- Logic: Complete programmatic logic (conditional statements such as if/else statements, for loops, filters like default, ipaddr, etc.)
- Error Handling: Evaluated before execution; syntax error in template is detected before execution of the commands on device.
config system interface
{% for intf in device_interfaces %}
edit "{{ intf.name }}"
set vdom "root"
set ip {{ intf.ip }} {{ intf.mask }}
{% if intf.allow_ping %}
set allowaccess ping
{% endif %}
next
{% endfor %}
end
Direct Comparison
| Feature / Dimension | Native CLI Scripts | Jinja2 Templates |
| Learning Curve | Extremely Low (Standard FortiOS CLI) | Moderate (Requires basic programming logic) |
| Logic & Conditionals | No (if/else not supported) | Yes (Full if/elif/else and loop control) |
| Variable Manipulation | Basic FortiManager Meta-Variables | Advanced (Filters, string transformations, arithmetic) |
| Code Reusability | Low (Requires separate scripts per variant) | High (Single template handles varying site specs) |
| Debugging Complexity | Low (Direct CLI output) | Moderate (Need to inspect rendered CLI before deployment) |
| Ideal Scope | Quick fixes, one-off changes, simple baselines | Complex multi-site provisioning, SD-WAN, Hub-Spoke networks |