boolean property in YAML object doesn't remain a boolean - yaml

I have a pipeline with multiple stages, and each stage has a common option. I want to control that option for each stage individually, but also have a way to force it off for all stages. The YAML looks roughly like this:
parameters:
-name: globalFlag
type: boolean
default: true
-name: stageSettings
type: object
default:
- stageName: stageOne
stageFlag: true
- stageName: stageTwo
stageFlag: false
...
stages
- ${{each stageDef in parameters.stageSettings }}:
...
myFlag: ${{ and(parameters.globalFlag, stageDef.stageFlag) }}
That almost works, except I believe stageDef.stageFlag is being interpreted as a string as the last line always evaluates to true if parameters.globalFlag is true. Which is odd as if that line is just myFlag: ${{ stageDef.stageFlag }} it works as expected.
I can work around this by changing the line to
myFlag: ${{ and(parameters.globalFlag, eq(stageDef.stageFlag, 'true')) }}
This is pretty good and even works for True and TRUE as well as true. But it doesn't work for Yes or On which are also true in YAML. So it could easily trip up someone when they enter a true value and it doesn't work as expected.
How can I get the property stageFlag in my object type to be interpreted as a boolean? Is there a way to mark the type of a property within an object? Is there a way to cast a string to a boolean that handles all valid ways of entering a boolean value?

This could be due to the fact that all YAML variables are stored as string in an Azure DevOps pipeline.
Your parameters on the other hand can use different data types.
Despite that globalFlag is a boolean, the stagesettings is a YAML object so the all YAML variables are stored as a string unfortunately applies here.
But as you discovered, using expressions like 'eq' can solve your issue a bit through type casting the string in the expression.
I don't think there is another way with this object parameter, nor is there a way to define types to the variables.

Related

GitLab CI yml check if value is within array at workflow rules

I have to validate a pipeline before triggering it. One criterion of the validation is if a CI/CD variable has one of the accepted values. Is there a way to find if it is matching the correct values?
I tried to create an array of values then to check it in the workflow rules but it is not clear from the other questions how to do that.
So it should be looking like this:
#WARNING: invalid yml!
variables:
ValidValues: ["Value1", "Value2", "SomeOtherValue"]
workflow:
rules:
- if: ValidValues contains $GivenValue
when: always
Searching on this issue, I found that I can add the allowed values to a regex on which I can check at the workflow rules. In the end it looks like this:
workflow:
rules:
- if: $GivenValue =~ /\b(Value1|Value2|SomeOtherValue)\b/
when: always
- when: never
Unfortunately I did not found a solution on my initial approach (adding the allowed values to an array, then looking for them) but this works as well.

How to encode "structure contains one or more X" in a .yaml file

I'm trying to define an OpenAPI interface in a .yaml file.
The interface specification says that one of the parameters will be a data structure foo containing, among other things, one or more members of a second data structure bar. In C++ I would define a structure containing a vector of bar but I cannot figure out how to encode this in YAML. I tried making a list with just one item, and Swagger Editor complained:
# ... details omitted
- in: header
name: foo
required: true
schema:
type: object
properties:
identity:
type: integer
version:
type: integer
- bar: # <<<<< bad indentation of a mapping entry
type: object
properties:
key:
type: string
value:
type: string
This doesn't look like it's really an indentation problem. I say this because the only level of indentation that removes the error is back out level with the in. Note that, if I remove the dash and following space, the editor shows no errors, so I'm pretty sure there are no other issues here.
main question How can I define this parameter as something containing one or more structures of type bar?
bonus question Is there a way to name the structures I'm defining, e.g. KeyValuePair for bar?
This doesn't look like it's really an indentation problem.
No, but it is a syntactic error that has nothing to do with OpenAPI (or JSON Schema, which is what is most relevant for your problem). YAML defines the structure of your document, and you have made a structural error.
This snippet is enough to see the error:
version:
type: integer
- bar:
The key version: shows that we are inside a mapping here, i.e. a list of key-value pairs. What follows is a nested mapping with the single entry type: integer. Then however, a - follows on the indentation level of version:. In YAML, this is a sequence indicator. But there is no sequence at the indentation level of version:; instead, this indentation level holds a mapping. You cannot have a sequence item as part of a mapping, since a mapping contains key-value pairs. The error message could of course be a better one.
Now what you actually want to do is to define an array of bar (JSON term for a vector of bar):
version:
type: integer
bar:
type: array
items:
type: object
properties:
key:
type: string
value:
type: string
Be aware of the important difference between the syntactic YAML structure of your input, and the desired semantic of your input. You want to describe an array in your JSON Schema, but that does not mean that you have to use a YAML sequence for that. You also don't write 42 if you want to define an integer-type field.
Also be aware that bar is the name of the field, not the name of the type. You can reference previously defined types with $ref.

Changing list value in Ansible

I have inventory with a very complicated structure. For my specific installation I want to override only some values. For example, I have structure:
---
System:
atr1: 47
config:
- nodes:
- logger:
id: 'all'
svr: 'IEW'
- Database:
constr: 'login/pass#db'
atr2: 'some value'
I want to override severity of the logger, i.e. add statistic information
svr: 'IEWS'. I want to provide an override within --extra-vars parameter.
In ansible.cfg -> hash_behaviour = merge
I don't want to use something like - svr: "{{ svr_custom | default('IEW') }}", because there are too many parameters, and thus it will be difficult to write the entire inventory in such way.
I read about combine filter, but I can't use it, when I had to override only one item in hash.
How can I achieve my goal?
The way you found is the simplest one. It's verbose to write but very easy to debug and to fix.
If you REALLY want to shrink this job, you can write your own lookup plugin. (https://docs.ansible.com/ansible/2.5/plugins/lookup.html).
From my experience, I really want to say that direct and dumb approach (write verbose) is much better for overall maintainability. A next person will see a dumb dump (pun intended) which is easy to fix, not a some obscure python snippet.
To make life easier you may want to store this configuration as a separate file (with all jinja pieces) and use lookup (st right from docs):
# Since 2.4, you can pass in variables during evaluation
- debug: msg="{{ lookup('template', './some_template.j2', template_vars=dict(x=42)) }} is evaluated with x=42"
Moreover, you can use Jinja's |from_yaml (or from_json) to convert loaded and processed template into data structure.
I read about combine filter, but I can't use it, when I had to override only one item in hash.
Why is that? Wouldn't new_svr defined in --extra-vars achieve what you want?
- set_fact:
System: "{{ System | combine({'config':[{'nodes':[{'logger':{'svr':new_svr }}]}]}, recursive=True) }}"

Ansible YAML attribute reading [duplicate]

I am trying to make sense of a variable reference I found in an incomplete Ansible role. The role references a value using
dest: “{{params['box'].t1}}”
In a separate yaml file I have
box:
t1: "Albany"
t2: "Albuquerque"
params isn't defined, so obviously this isn't going to work, but I can't figure out the correct way to define it. Can someone tell me where (or how) params must be defined for this variable reference to work in Ansible?
Related questions. Does the use of square brackets in dest: “{{params['box'].t1}}” indicate that it is a dictionary? If yes, could I also write this as dest: “{{params['box']['t1']}” or dest: “{{params.box.t1}”?
params['box'].t1 refers to Albany in:
params:
box:
t1: "Albany"
t2: "Albuquerque"
It is the same as params.box.t1 and params['box']['t1'].
Brackets refer to a key name, so they imply it is a dictionary.
You typically use square bracket-notation when you want to refer to a key via a variable:
vars:
wanted_key: box
params:
box:
t1: Albany
other:
t1: Albuquerque
Then params[wanted_key].t1 refers to Albany.
In your example the value inside square brackets is a string (quoted), so all above examples are equivalent.

How should this Ansible variable be defined?

I am trying to make sense of a variable reference I found in an incomplete Ansible role. The role references a value using
dest: “{{params['box'].t1}}”
In a separate yaml file I have
box:
t1: "Albany"
t2: "Albuquerque"
params isn't defined, so obviously this isn't going to work, but I can't figure out the correct way to define it. Can someone tell me where (or how) params must be defined for this variable reference to work in Ansible?
Related questions. Does the use of square brackets in dest: “{{params['box'].t1}}” indicate that it is a dictionary? If yes, could I also write this as dest: “{{params['box']['t1']}” or dest: “{{params.box.t1}”?
params['box'].t1 refers to Albany in:
params:
box:
t1: "Albany"
t2: "Albuquerque"
It is the same as params.box.t1 and params['box']['t1'].
Brackets refer to a key name, so they imply it is a dictionary.
You typically use square bracket-notation when you want to refer to a key via a variable:
vars:
wanted_key: box
params:
box:
t1: Albany
other:
t1: Albuquerque
Then params[wanted_key].t1 refers to Albany.
In your example the value inside square brackets is a string (quoted), so all above examples are equivalent.

Resources