=============== Using Templates =============== ------- General ------- For config file generation, we provide a backend service which can bind config.xml data to templates written in Jinja2 (http://jinja.pocoo.org/docs/dev/). All available templates should be installed at the following location on the OPNsense system: #. /usr/local/opnsense/service/templates/ ----------------- Naming convention ----------------- All templates should be put into a directory structure containing the vendor and package/application name, our sample application is placed inside the directory: /usr/local/opnsense/service/templates/*OPNsense/Sample* Template package content Every template directory should contain at least 2 files: #. a content descriptor, containing the actual targets, named +TARGETS #. one or more template(s) ------- Targets ------- The +TARGETS file contains the source template name inside the template directory and the (dynamic) target filename divided by a colon (:) multiple lines may be inserted per file. For example : :: example_simple_page.txt:/tmp/template_sample/simple_page.txt Will create a file /tmp/template\_sample/simple\_page.txt using the template example\_simple\_page.txt. .. Note:: Optionally you can specify which file or files to remove on call of "template cleanup", which can be specified by using an extra tag next to the target, such as: :code:`example_simple_page.txt:/tmp/template_sample/simple_page.txt:/tmp/template_sample/simple_page.*` By default all targets will be removed when calling cleanup. If you want to use information from within the config.xml file as output filename, you can use tags to address the content, like [version] to input the tag version from the xml file. When generating multiple files from 1 template, you can use one wildcard (%) to address a section of the config file, for example [interfaces.%.if] loops over the interfaces and outputs the value of **if**. ----------------- Target overwrites ----------------- Every template package can specify overwrites, which can be used by vendors who implement and maintain their own templates for features in OPNsense. Simply add files using the target definition in the **+TARGETS.D** directory of the templates folder using as extension **.TARGET**. For example an overwrite for OPNsense/Sample can use the following name and location :code:`/usr/local/opnsense/service/templates/OPNsense/Sample/+TARGETS.D/custom.TARGET` .. Note:: Be vey careful using this feature, you need to maintain these templates yourself and features may break after upgrades of OPNsense. --------- Templates --------- For more information of the template language itself, please look at http://jinja.pocoo.org/docs/dev/ and the examples installed in /usr/local/opnsense/service/templates/OPNsense/Sample. There's one special case when using the template engine, every wildcard used for the output file generation is also provided to the template, so you are able to determine which filter let to this output. Those filters are stored in the variable TARGET\_FILTERS. .. code-block:: jinja {% if TARGET_FILTERS['interfaces.wan'] %} {% endif %} ---------- Test usage ---------- The templates can be rendered via the backend service (configd), to test this functionality on a running OPNsense system, use: :: # generate template package configctl template reload OPNsense/Sample # cleanup files configctl template cleanup OPNsense/Sample | ----------------------------- Python template usage example ----------------------------- The template system itself is a separate module which is used by configd, to use (or test) the system without the daemon, use: .. code-block:: python # import template system and config.xml handling from modules import template from modules import config   # construct a new template object, set root to /tmp/ tmpl = template.Template(target_root_directory="/tmp/") # open the config.xml and bind to template object conf = config.Config('/config.xml') tmpl.setConfig(conf.get())   # generate output for OPNsense/Sample generated_filenames = tmpl.generate('OPNsense/Sample')   # print results for filename in generated_filenames: print ('.. generated : %s'%filename)