# Advanced usage

Caution

The examples in this section are not fully functional files, and only demonstrate the behavior of the various functionalities.

# Special variables

To simplify the usage of StackForms, you might want to be able to always use the organization, project's name, etc instead of specifying it every time you configure a new project.

This is achieved by a previously established concept: special variables that will be substituted in both the destination/content of your files.

Special variables format if the following:

($ variable_name $)
1

Here is the list of all the available special vars:

Variable Description
project The project canonical
project_owner_canonical The canonical of the project owner
project_owner_name The name of the project owner
project_owner_surname The surname of the project owner
project_owner_email The email of the project owner
environment The environment
organization_canonical The canonical of the organization
scs_url The URL of the catalog repository where the stack is located
scs_branch The branch of the catalog repository where the stack resides
scs_cred_type The type of credential used to access the stack's service catalog
scs_cred_path The path in Vault of the credential used to access the service catalog
stack_path The path of the stack in the service catalog, basically the path to the .cycloid.yml file for that stack
cr_url The URL of the config repository configured for this stack
cr_branch The branch in the config repo holding the configuration for the stack
cr_cred_type The type of credential used to access the stack's config repo
cr_cred_path The path in Vault of the credential used to access the config repo
inventory_jwt The JSON Web Token used to access the inventory
api_url The URL of the Cycloid API
console_url The URL of the Cycloid console
use_case The use case name of the stack

The URL and branch will be the ones that you have set up on the service catalog page. So for example the URL could be: git@github.com:cycloidio/cycloid-stacks.git and the branch stacks.

So, as a value in your .forms.yml file, you could use:

default: ($ project $)/terraform/($ environment $)/main.tf

# Using common use case

Depending on the configuration for your use-cases, you might run into a configuration of variables that are very repetitive. This issue is addressed with a special common use-case called cycloid-common, which will be merged with the other ones.

This happens in various situations, you have a stack that can deploy either on-premise or mutualized, or a stack that can deploy on different cloud providers, etc. In such scenarios, you will have to specify your application every time: image to use for your components, cache retention, etc. This can be leveraged by defining them only once in the cycloid-common instead of doing so in every section.

If a section/group was defined in cycloid-common, and not in the others, those would be added to them. However if those were already defined only the missing ones would be added, meaning any groups or variables defined in the other use-cases have priorities over the common one.

The process of merging elements is done prior to returning it to the user, so they will only see the final result.

The following examples will illustrate what the file looks like, prior to the various injection of the cycloid-common use-case into the other ones. To allow understanding the merging more easily, a 'name' has been added to each variable, which is of the format: use-case.section.group.key, so that it is easier on the final file, to know where a variable is coming from.

Example of a file defined with the cycloid-common use case:

version: "2"
use_cases:
- name: cycloid-common
  sections:
  # This section exist, so groups will be checked
  - name: pipeline
    groups:
    # Group exist but the variable 'three' doesn't so it will be added
    - name: backend
      vars:
      - key: one
        name: common.pipeline.backend.one
      - key: three
        name: common.pipeline.backend.three
    # Group exist and variable 'four' too, so nothing change
    - name: frontend
      vars:
      - key: four
        name: common.pipeline.frontend.four
  # This section doesn't exist, so everything will be added
  - name: terraform
    groups:
    - name: backend
      vars:
      - key: five
        name: common.terraform.backend.five
    - name: frontend
      vars:
      - key: six
        name: common.frontend.backend.six

- name: first
  sections:
  - name: pipeline
    groups:
    - name: backend
      vars:
      - key: one
        name: first.pipeline.backend.one
      - key: two
        name: first.pipeline.backend.two
    - name: frontend
      vars:
        - key: four
          name: first.pipeline.frontend.four
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

The final merged file is the one that will be delivered to the user, please note that it won't contain cycloid-common use-case anymore, as its elements will have been integrated into other ones.

If you pay attention to the variables name, you'll notice some come from the common use-case, while some remain from the use-case's definition. Sections or groups that weren't defined will also be added to each use-case.

version: "2"
use_cases:
- name: first
  sections:
  - name: pipeline
    groups:
    - name: backend
      vars:
      - key: one
        name: first.pipeline.backend.one
      - key: two
        name: first.pipeline.backend.two
      - key: three
        name: common.pipeline.backend.three
    - name: frontend
      vars:
        - key: four
          name: first.pipeline.frontend.four
  - name: terraform
    groups:
    - name: backend
      vars:
      - key: five
        name: common.terraform.backend.five
    - name: frontend
      vars:
      - key: six
        name: common.frontend.backend.six
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# Sharing technologies

It is possible to also share variables across technologies; to do so add technologies to the list within the group and they will be automatically written/read from their respective files. This can be quite useful as you might not want to repeat the filling of identical variables for different technologies when they are all the same. In the scenario where those shared variables wouldn't be the same anymore (got manually edited for example), the user would be notified and have to manually solve the conflict of settings.

Conflict

Currently only 'simple' widgets/types support sharing:

Widgets Can be shared?
auto_complete, dropdown, number, radios, simple_text, slider_list, slider_range, switch, text_area
cy_cred, cy_scs, cy_crs, cy_branch

# Conditions

Groups can have an attribute called condition. When configuring a project, variables belonging to the group with a condition will only be processed if that group's condition is met, otherwise, variables will simply be ignored.

Conditions are a form of expression that allow to preconfigure certain validations and enable/disable groups accordingly.

You can use complex logical expressions (as opposed to previous versions, where only one expression was accepted). For example, the following condition is considered valid: $var1 == 'hello world' && $var2 > 10 || ($var3 != true && $var4 == 'value').

To better understand how to use the conditions you can check on the following subsections the format of the variables, the available operators and values to use. For an example of conditions in the stackforms please check the examples section.

# Condition variables

The variables used in the conditions expressions correspond to the stackforms variables and its their corresponding value that will be verified in the condition.

The condition variables should be prefixed with $ symbol and cannot contain spaces or special characters, e.g $var1 or $var_1 are valid variables.

Only the following variables types can be used in the expressions: integer, float, string, boolean.

Variables of type map, array and raw are not supported yet.

Important

The variables cannot belong to the same group of the condition, since they're used to enable/disable other groups.

# Condition operators

There's two operators to use in conditions:

  • Comparators that are used to compare variables to values in a expression, as follows $variable $comparator $value Available comparators are:

    • > greater than
    • >= greater than or equal
    • < less than
    • <= less than or equal
    • == equal
    • != not equal
  • Logical operators that are used to establish logical value, as follows $expressionA $logicalOperator $expressionB. You can group expressions by using parentesis: ($expression) ... Available logical operators:

    • || logical OR
    • && logical AND

# Conditions values

The supported values formats to use in the expressions are:

  • boolean: true or false
  • numbers: 123.45, 25 and -100 to check negative
  • string: 'text_string'.
  • dates: '2022-10-04_13:37:37Z'. RFC3339, ISO8601, ruby date, or unix date formats are supported. Note! Date values can only be compared when using string variables

Important

All string/date values are required to be enclosed within single quotes, for example 'value one' or '2022-10-04_13:37:37Z' are considered valid, while value one or 2022-10-04_13:37:37Z aren't (no quotes).

# Group scope

Groups can have an attribute called condition. Condition is a form of expression allowing to preconfigure certain validations. This way when configuring a project, variables belonging to the group with a condition will only be processed if that group's condition is met; otherwise, variables will simply be ignored.

Group-condition

# Variable scope

The variables you define can have dynamic values and default, based on a set of conditions. Those values will change depending on the user's input. For example if you were to allow the configuration of the environment, you could have different instance size based on the environment name.

The default & values allow 2 kinds of input: static & dynamic. You can use either dynamic default alone, dynamic values alone or both together.

Here is the preview of the previous example with dynamic elements:

# YAML anchors and aliases

To reduce and factorize your .forms.yml definition, YAML Anchors and aliases can be used.

Item can be identified with an anchor, and then refer to that item with an alias later in the forms.yml. Anchors can be used repeatedly by multiple aliases. Anchors are identified by an & character, and aliases by an * character.

Lets take an example, my stack has 3 use cases. Both A and B share the same section FOO but C is different.

Here is a sample of .forms.yml using anchor to add a FOO section in both A and B only.

# YAML anchors
shared:
- &foo-section
  name: FOO
  groups:
  - name: Group1
    technologies: [pipeline]
    vars:
      - name: Widget1
        ...

version: "2"
use_cases:
- name: A
  sections:
  - *foo-section

- name: B
  sections:
  - *foo-section

- name: C
  sections:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

Anchors and aliases could be used at any levels from your .forms (not only sections). Feel free to check the yaml documentation (opens new window) for more advanced needs.