A dynamic family

Objectives

In this section we will learn how to create a dynamically built family.

Reminder

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:

../_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 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 HTTPS proxy

  • the SOCKS proxy

As they have the same structure, would it be possible to define the two of them in one shot?

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.

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):

https_proxy:
  description: HTTPS Proxy
  ...

  address:
    description: HTTPS address
    ...

  port:
    description: HTTPS Port
    ...

sock_proxy:
  description: SOCKS Proxy
  ...

  address:
    description: SOCKS address
    ...

  port:
    description: SOCKS Port
    ...

Now with identifiers, we have the ability to declare our families this way:

"{{ 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`.

It is used in the context of a loop. For example:

- name: Loop example with 'item'
  ansible.builtin.debug:
    msg: "The current value is {{ item }}"
  loop:
    - value1
    - value2
    - value3

This code will output:

The current value is value1
The current value is value2
The current value is value3

In the Rougail context, we name this item an identifier because it is an item that allow us to define dynamically family names.

identifier

In the dynamic family creation field we call an identifier an item that defines a family name. An item is a variable on which an iteration on keywords will be carried out.

An identifier is a local variable, used only for creating multiple iterations, used for creating multiple families in only one declaration.

It allows us to declare very similar families in a more generic way.

Here is the syntax we are using that allows the declaration of multiple families at one time:

"{{ identifier }}_proxy":
  description: "{{ identifier }} Proxy"
  dynamic:
    - HTTPS
    - SOCKS

This identifier is a parameter that enables us to create two families named https_proxy and socks_proxy:

https_proxy:
  description: "HTTPS Proxy"

socks_proxy:
  description: "SOCKS Proxy"

Note

The declaration syntax used is the Jinja templating syntax, Jinja which is widely used in python.

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 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:

rougail -m structfile/proxy.yml -u yaml --yaml.filename userdata/proxy.yml
╭─────────────────── Caption ────────────────────╮
│ Variable              Default value            │
│ Unmodifiable variable Modified value           │
│                       (Original default value) │
╰────────────────────────────────────────────────╯
Variables:
┗━━ 📂 Manual proxy configuration
    ┣━━ 📂 HTTP Proxy
    ┃   ┣━━ 📓 HTTP address: ... (loaded from the YAML file "userdata/proxy.yml")
    ┃   ┗━━ 📓 HTTP Port: ... (8080 - loaded from the YAML file "userdata/proxy.yml")
    ┣━━ 📓 Also use this proxy for HTTPS: true
    ┣━━ 📂 HTTPS Proxy
    ┃   ┣━━ 📓 HTTPS address: ...
    ┃   ┗━━ 📓 HTTPS port: ...
    ┗━━ 📂 SOCKS Proxy
        ┣━━ 📓 SOCKS address: ...
        ┗━━ 📓 SOCKS port: ...

We can see that the dynamic family has created:

  • an HTTPS Proxy family

  • a SOCKS Proxy family

as we wanted, containing an address and a port.

A conditional hidden familiy

Here is the final YAML version of the HTTPS and SOCKS proxy families:

We have added:

  • a conditional hidden family property

  • a default value

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:

hidden:
  variable: manual.use_for_https

it uses use_for_https variable:

use_for_https:
  description: Also use this proxy for HTTPS
  default: true

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.