Calculation with a jinja type =============================== .. 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. A jinja calculated variable's hidden property ------------------------------------------------ We can hide or disable some variables or families with other techniques than pointing on a variable's value. Let's reason on the previous HTTPS proxy configuration's manual mode: .. code-block:: yaml manual: use_for_https: description: Also use this proxy for HTTPS default: true https_proxy: type: family description: HTTPS Proxy hidden: variable: manual.use_for_https This is extracted from the proxy's manual configuration we discussed before. We see here that there is an `https_proxy` family that is going to be hidden depending on the value of another variable: .. code-block:: yaml https_proxy: type: family hidden: variable: manual.use_for_https Now we could write it like that: .. code-block:: yaml manual: use_for_https: description: Also use this proxy for HTTPS default: true https_proxy: description: HTTPS Proxy type: family hidden: type: jinja jinja: | {% if rougail.manual.use_for_https %} the HTTPS Proxy family is hidden {% endif %} Yes, it's done in a more complicated (but more powerful) way. Let's explain this a little: We have replaced this simple hidden property declaration: .. code-block:: yaml hidden: variable: manual.use_for_https by this (more complicated) hidden property declaration: .. code-block:: yaml hidden: type: jinja jinja: | {% if rougail.manual.use_for_https %} the HTTPS Proxy family is hidden {% endif %} The fact is that it has same result, but here we have more possibilities. The hidden process is done by a calculation. Another jinja calculation type sample --------------------------------------- We can now hide or disable some variables or families with other techniques than pointing on a variable's value. Let's reason upon the proxy's manual configuration we discussed before. We have the :file:`dict/02-proxy_manual.yml` structure file: .. code-block:: yaml :caption: the :file:`structfile/02-proxy_manual.yml` file --- version: '1.1' manual: description: Manual proxy configuration type: family disabled: type: jinja jinja: | {% if rougail.proxy.proxy_mode != 'Manual proxy configuration' %} the proxy mode is not manual {% endif %} .. questions:: Question **question**: OK then. What happens when you select the "Manual proxy configuration"? Here if the user selects the "Manual proxy configuration" proxy mode, the the `manual` family will be disabled. This is what the jinja code says. Let's explain it more precisely. .. note:: The "the proxy mode is not manual" output is be used in the log outputs for example while Why Jinja? --------------- .. questions:: What about this `Jinja` type? If the :term:`Jinja` template returns some text, then the family will be `disabled`. Otherwise it is accessible. Deactivating a family means that we will not be able to access it as well as the variables or families included in this family. .. note:: If the Jinja template does not return any text, the variable will be **enabled**. Here we are using the Jinja condition statement. .. 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. What can be calculated? --------------------------- We have seen that the `disabled` or `hidden` properties could be calculated. The default values can be calculated too. .. todo:: montrer un exemple de valeur par défaut calculées (type jinja) .. todo:: montrer aussi ici des exemples de calculs de valeurs variables, ce qui est un des usages principaux de jinja Using jinja in a dynamic family declaration ----------------------------------------------- Let's come back to the previous section's :ref:`dynamic family example `\ . In a dynamic family, as seen before, you have the possibility to name your identifier. In the classic declaration, the identifier's variable is named "identifier" by default. Sounds logical: .. code-block:: yaml "{{ identifier }}_proxy": description: "{{ identifier }} Proxy" dynamic: - HTTPS - SOCKS dynamic: - HTTPS - SOCKS Here the identifer's variable takes the value of the `dynamic` family parameter. .. type-along:: Using a jinja calculation with a parameter We have the possibility to use a given variable variable inside a jinja calculation: .. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_050/firefox/20-manual.yml :language: yaml :caption: firefox/20-proxy.yml .. manual: use_for_https: description: Also use this proxy for HTTPS default: true "{{ identifier }}_proxy": description: "{{ identifier }} Proxy" dynamic: - HTTPS - SOCKS hidden: jinja: | {% if my_identifier == 'HTTPS' and manual.use_for_https %} HTTPS is same has HTTP {% endif %} params: my_identifier: type: identifier description: | in HTTPS case if "manual.use_for_https" is set to True address: description: "{{ identifier }} address" default: variable: manual.http_proxy.address port: description: "{{ identifier }} port" default: variable: manual.http_proxy.port version: description: SOCKS host version used by proxy choices: - v4 - v5 default: v5 disabled: type: identifier when: 'HTTPS' This can be done by defining a `my_identifier` variable. This jinja variable comes from the `params` parameter of the `hidden` property. .. code-block:: yaml params: my_identifier: type: identifier Here the `hidden` property's value is defined by a jinja calculation. In this jinja calculation we have a `my_identifier` jinja variable. .. code-block:: yaml hidden: jinja: | {% if my_identifier == 'HTTPS' and manual.use_for_https %} HTTPS is same has HTTP {% endif %} params: my_identifier: type: identifier description: | in HTTPS case if "manual.use_for_https" is set to True .. type-along:: The `when` and `when_not` parameter notation Handling the SOCKS version ---------------------------- Now we need to handle the SOKS version as show in the firefox configuration screenshot: .. image:: images/firefox_soks_version.png We'll just add a choice variable with a default value and a disabled property: .. code-block:: yaml version: description: SOCKS host version used by proxy choices: - v4 - v5 default: v5 disabled: type: identifier when: 'HTTPS' There is still something new about this YAML, though. It is the `when` parameter of the `disabled` property. You have two possible notations: `when` or `when_not`. These two notations are just a short hand of what we could express in jinja as this code: .. code-block:: jinja {% if identifier == 'HTTPS' %} when the identifer equals 'HTTPS' then the SOCKS version is disabled {% endif %} And the `when_not` parameter is just the logical opposite. Here is the final version of our YAML dynamic family: .. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_050/firefox/20-manual.yml :language: yaml :caption: firefox/20-proxy.yml .. 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.