Playing with Jinja ==================== .. objectives:: Objectives In this section we will learn how to create new ways of calculation. Up to now, our only way of dynamically (that is, during the runtime) calculating a value is to point on another variable's value. But this is not the only way. We will learn how to insert `Jinja templating language `_ into our structure files. Please note that we do not intend to template our YAML files. That is a completely different activity. We will simply insert YAML code to calculate variable, property, or parameter values. .. prerequisites:: Prerequisites - We assume that Rougail's library is :ref:`installed ` on your computer. - It is possible to retrieve the current state of the various Rougail files manipulated in this tutorial step by checking out the corresponding tag of the `rougail-tutorials` git repository. Each tag corresponds to a stage of progress in the tutorial. Of course, you can also decide to copy/paste or download the tutorial files contents while following the tutorial steps. If you want to follow this tutorial with the help of the corresponding :tutorial:`rougail-tutorials git repository `, this workshop page corresponds to the tags :tutorial:`v1.1_070 ` to :tutorial:`v1.1_072 ` in the repository. :: git clone https://forge.cloud.silique.fr/stove/rougail-tutorials.git git switch --detach v1.1_070 .. type-along:: Why the jinja templating engine ? We are going to embed some `jinja templating code `_ in our structure file. .. glossary:: Jinja `Jinja `_ is a template engine. we are using Jinja in a classical way, that is, Jinja allows us to handle different cases, for example with the `if` statement. .. questions:: What about a `Jinja` calculation? The :term:`Jinja` templating language enables some complex calculation. For example we can code more complex behavior for hiding or disabling a variable, that is not only depending on the value of another variable as we saw before. A conditional hidden family with Jinja --------------------------------------- Here we are going to use the Jinja conditional (testing) statement. Here is our structure file: .. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_070/firefox/20-manual.yml :language: yaml :caption: The :file:`firefox/20-manual.yml` structure file with some `jinja` code in the `hidden` property .. %YAML 1.2 --- version: 1.1 manual: use_for_https: true # Also use this proxy for HTTPS '{{ identifier }}_proxy': description: '{{ identifier }} Proxy' hidden: jinja: |- {% if _.use_for_https %} HTTPS is same has HTTP {% endif %} dynamic: - HTTPS - SOCKS address: description: '{{ identifier }} address' default: variable: __.http_proxy.address port: description: '{{ identifier }} port' default: variable: __.http_proxy.port version: description: SOCKS host version used by proxy choices: - v4 - v5 default: v5 disabled: type: identifier when: HTTPS ... In this jinja code, we are testing the `use_for_https` variable: .. code-block:: jinja {% if _.use_for_https %} HTTPS is same has HTTP {% endif %} If this variable is set to `true`, the `"HTTPS is same has HTTP"` expression will appear. .. note:: Have a look at the `jinja website's test section `_ for a closer look about testing a variable. But first, let's set our `use_for_https` variable to `false`: .. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_070/config/01/config.yml :language: yaml :caption: The :file:`config/01/config.yml` user data file with the `use_for_https` set to `false` .. --- proxy_mode: Manual proxy configuration manual: http_proxy: address: http.proxy.net port: 3128 use_for_https: false https_proxy: address: https.proxy.net Nothing special appears when we launch the Rougail CLI: .. raw:: html :url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_070/config/01/cmd_ro.txt :class: terminal .. rougail -m firefox/ -u yaml -yf config/01/config.yml We have this output: .. raw:: html :url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_070/config/01/output_ro.html :class: output .. Variables: ┣━━ 📓 Configure Proxy Access to the Internet: Manual proxy configuration ◀ loaded from the YAML file "config/01/config.yml" (⏳ No proxy) ┗━━ 📂 Manual proxy configuration ┣━━ 📂 HTTP Proxy ┃ ┣━━ 📓 HTTP address: http.proxy.net ◀ loaded from the YAML file "config/01/config.yml" ┃ ┗━━ 📓 HTTP Port: 3128 ◀ loaded from the YAML file "config/01/config.yml" (⏳ 8080) ┣━━ 📓 Also use this proxy for HTTPS: false ◀ loaded from the YAML file "config/01/config.yml" (⏳ true) ┣━━ 📂 HTTPS Proxy ┃ ┣━━ 📓 HTTPS address: https.proxy.net ◀ loaded from the YAML file "config/01/config.yml" (⏳ http.proxy.net) ┃ ┗━━ 📓 HTTPS port: 3128 ┗━━ 📂 SOCKS Proxy ┣━━ 📓 SOCKS address: http.proxy.net ┣━━ 📓 SOCKS port: 3128 ┗━━ 📓 SOCKS host version used by proxy: v5 If we set the `use_for_https` to `true` in the :file:`config.yml` user data file, then we launch again the Rougail CLI: .. raw:: html :url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_070/config/01/cmd_ro.txt :class: terminal then we have a warning: :: 🔔 Warning ┗━━ Manual proxy configuration ┗━━ HTTPS Proxy ┗━━ HTTPS address: 🔔 family "HTTPS Proxy" has property hidden, so cannot access to "HTTPS address", it will be ignored when loading from the YAML file "config/01/config.yml" What is interesting here is to launch the Rougail CLI in the :term:`read write mode`: :: rougail -m firefox/ --cli.root manual.https_proxy -u yaml environment \ -yf config/01/config.yml --cli.read_write Then we have an error: .. code-block:: bash ERROR: cannot access to optiondescription "HTTPS Proxy" because has property "hidden" (HTTPS is same has HTTP) .. note:: Note that we can see the "HTTPS is same has HTTP" string (the one that was present in the jinja code) as an explanation inside the error message. .. type-along:: What can be calculated? We have seen that the `disabled` or `hidden` properties could be calculated. The default values can be calculated too. We'll see a bunch of examples later on. Let's reason on the previous HTTPS proxy configuration's manual mode settings: .. code-block:: yaml use_for_https: default: true https_proxy: type: family description: HTTPS Proxy hidden: variable: _.use_for_https We see here that the `https_proxy` family is be hidden depending on the value of another variable. This is what we saw before, how to hide a variable. Now we can code the same behavior in a somehow different way: .. code-block:: yaml https_proxy': description: HTTPS Proxy hidden: jinja: |- {% if _.use_for_https %} HTTPS is same has HTTP {% endif %} This code has the same result but yes, it's done in a more complicated way. We have replaced this simple `hidden` property variable parameter by a jinja parameter. The hidden process is done by a calculation. The fact is that it has same result, but it wil open more possibilities. FIXME .. keypoints:: Key points **keywords** - calculation with a jinja type calculation - calculation with a `when` or `when_not` parameter - defining a jinja internal variable in a jinja calculation **progress** Here we have come to the possibility of making any kind of calculations based on the state of the :term:`configuration`. This is an important feature to manage the stateful aspect of a configuration.