jinja and calculations

This commit is contained in:
gwen 2025-09-16 18:51:35 +02:00
parent 1da10b7970
commit 91112a905a
6 changed files with 267 additions and 105 deletions

View file

@ -8,9 +8,6 @@
Rougail
===========
.. todolist::
.. todo:: définir les termes suivants
family.rst:25: WARNING: label non défini: 'convention on variable names'

View file

@ -0,0 +1,154 @@
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 <https://jinja.palletsprojects.com>`_ 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.
.. todo:: montrer aussi ici des exemples de calculs de valeurs variables, ce qui est un des usages principaux de jinja
.. keypoints:: Key points
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.

View file

@ -5,37 +5,40 @@ A dynamic family
.. objectives:: Objectives
In this section we will learn how to create a dynamically created family.
In this section we will learn how to create a dynamically built family.
.. prerequisites:: Reminder
We handled the HTTPS mode in the previous section. But there's more.
Let's have a look at the firefox's configuration page:
We handled the HTTPS mode in the previous section. But there's more modes to handle.
Let's turn back to the firefox's configuration page:
.. image:: images/soksv5.png
We see that we need to handle the SOCKS configuration in addition to the HTTPs configuration.
Moreover, we can see that these two group of variables are very similar:
We see that we need to handle the SOCKS configuration in addition to the HTTPS configuration.
Moreover, we can see that these two groups of variables are similar in the structure:
they both have a host and a port.
Creating a generic family
----------------------------
There are two proxies that are to be configured :
- the HTTP proxy
- the HTTPS proxy
- the SOCKS proxy
It's not the place here to describe what the HTTP and SOCKS protocols are.
The interesting point here is that they are very similar in our firefox's configuration.
As they have the same structure, would it be possible to define the two of them
in one shot?
With Rougail, we can create some kind of a model of family.
we can use a generic family declaration mode in this use case.
We call this genericity family a "dynamic creation" because as we will see below,
these families exist at the very moment we define their identifiers.
.. note:: It's not the place here to describe what the HTTP and SOCKS protocols are.
The interesting point here is that they are very similar in our firefox's
configuration and that we can do batch processing.
what we could do with our current knowledge:
With Rougail, it is possible to create some kind of a model of family.
Kind of a generic family declaration.
We call this generic family creation process a "dynamic creation" because as we will see below,
these families exist at the very moment we define their **identifiers**.
First, here is what we need to make (without identifiers):
.. code-block:: yaml
@ -63,14 +66,24 @@ what we could do with our current knowledge:
description: SOCKS Port
...
With Rougail we have the ability to declare our families this way:
Now with identifiers, we have the ability to declare our families this way:
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_037/firefox/20-manual.yml
:language: yaml
:caption: firefox/20-proxy.yml
.. code-block:: yaml
What is an identifier?
-------------------------
"{{ identifier }}_proxy":
description: "{{ identifier }} Proxy"
dynamic:
- HTTPS
- SOCKS
address:
description: "{{ identifier }} address"
port:
description: "{{ identifier }} port"
What is exactly an identifier?
-------------------------------
If you know a YAML declaration tool named Ansible,
the variable used to iterate over multiple values in a task is called an **`item`**.
@ -123,8 +136,6 @@ Here is the syntax we are using that allows the declaration of multiple families
This identifier is a parameter that enables us to create two families named `https_proxy` and `socks_proxy`:
.. code-block:: yaml
https_proxy:
@ -136,15 +147,15 @@ This identifier is a parameter that enables us to create two families named `htt
.. note:: The declaration syntax used is the :term:`Jinja <jinja>` templating syntax,
Jinja which is widely used in python.
.. attention:: Be careful when choosing your identifiers items: the family
that will be dynamically created shall not exist already.
.. attention:: Be careful when choosing your identifiers items: pay attention that the family
that will be dynamically created has not been declared before in some other
YAML structure file.
If you define a dynamic family with the `https` item that will
build a `https_proxy` family and if this familiy already exist,
then rougail will raise a warning.
Besides, when we launch the rougail command line, we can have a look at the concrete variables here:
build a `https_proxy` family and if this familiy already exists,
then rougail will raise a family/variable override warning.
When we launch the rougail command line, we can have a look at the concrete families and variables that have appear:
.. code-block:: text
@ -172,15 +183,76 @@ We can see that the dynamic family has created:
- an `HTTPS Proxy` family
- a `SOCKS Proxy` family
as we wanted.
as we wanted, containing an address and a port.
A conditional hidden familiy
--------------------------------
Yes we have gained in genericity but we have lost in readability, you would say.
But we haven't just been generic. We now have the ability to create conditional hidden family
(and not only conditionnal hidden variables like we did earlier).
Here is the final YAML version of the HTTPS and SOCKS proxy families:
We have added:
- a conditional hidden family property
- a default value
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_037/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:
variable: manual.use_for_https
address:
description: "{{ identifier }} address"
default:
variable: manual.http_proxy.address
port:
description: "{{ identifier }} port"
default:
variable: manual.http_proxy.port
The conditional property is this one:
.. code-block:: yaml
hidden:
variable: manual.use_for_https
it uses `use_for_https` variable:
.. code-block:: yaml
use_for_https:
description: Also use this proxy for HTTPS
default: true
.. keypoints:: Key points
- We now know what a generic family is, with its identifier.
- we now how to create default values for a variable that is calculated
because it retrieves the value of another variable.
- we know how to hide conditionaly a family with the same mechanism,
that is a calculated value. It is calculated because there is a dependancy
over another variable.
We will see other types of calculation in the next section.

View file

@ -31,6 +31,9 @@ The values entered by the user have to be
- validated
- consitent
- conformity
.. todo:: explain the congruent term. or another term? compliance ? accordance ? conformity ?
At first glance we can see that we have a selection of five configuration options values that we need to fill in, they are highlighted here in this screenshot:
@ -45,4 +48,5 @@ At first glance we can see that we have a selection of five configuration option
disabled
boolean
dynfam
calculation

View file

@ -250,6 +250,9 @@ In our firefox use case, the real type of the `proxy_mode` variable will be now
choice type
A choice type variable is a variable where the content is constrained by a list
When a variable's setting is "choice" (`type: choice`), it means that
there is a list of available values that can be selected.
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_013/firefox/00-proxy.yml
:linenos:
@ -311,12 +314,6 @@ We have the list of the possible (authorized) values:
- `Manual proxy configuration`
- `Automatic proxy configuration URL`
.. glossary::
choice type
The `proxy_mode` setting is "choice" (`type: choice`) means that
there is a list of available values that can be selected.
.. keypoints:: Key points progress

View file

@ -1,68 +1,6 @@
:orphan:
The Firefox proxy: the manual configuration
=============================================
.. objectives:: Objectives
We will learn how to: FIXME
.. prerequisites:: Reminders
FIXME
The manual mode
------------------
.. questions:: Question
**question**: OK then. What happens when you select the "Manual proxy configuration"?
A good configuration design is to place all the proxy's manual configuration in a :term:`family`.
Let's create the :file:`dict/02-proxy_manual.yml` dictionary:
.. code-block:: yaml
:caption: the the :file:`dict/02-proxy_manual.yml` file
---
version: '1.1'
proxy:
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 %}
Well, if the user selects the "Manual proxy configuration" proxy mode, we want to see a new subfamily (that is, a new set of configuration variables) called `manual` to appear (which is disabled).
.. glossary::
subfamily
A subfamily is just a family inside a family, a family that contains a family.
.. 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 <https://jinja.palletsprojects.com>`_ 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.
The HTTP proxy configuration
------------------------------