I would like to retrieve the modulo of two Ansible variables.
How can we do something like that?
kernel_shmallV: "{{ sys_mem.stdout }} % {{sys_page_size.stdout }}"
Ansible uses Jinja2 templating language. You write Jinja2 expressions inside {{ }}. Anything inside the quotes, but outside the braces is a string.
What you wrote in the question are two independent expressions each printing the value of a variable separated by a string %.
What you are looking for is:
kernel_shmallV: "{{ sys_mem.stdout|int % sys_page_size.stdout|int}}"
Stdout values returned by command or shell modules are of string type, hence casting to integer with int.
Related
I define a yml variable files for ansible with the following structure:
appserver:
root_directory: C:\app
config_directory: '{{ root_directory }}\config'
it seems the second variable config_directory cannot be interpreted correctly, I get a VARIABLE NOT FOUND ERROR.
I tried with:
appserver:
root_directory: C:\app
config_directory: '{{ appserver.root_directory }}\config'
It does not work either, I have a very long trace of error, the most interesting part is :
recursive loop detected in template string:{{ appserver.root_directory }}\config
When I use double quotes instead of simple quotes,
appserver:
root_directory: C:\app
config_directory: "{{ appserver.root_directory }}\config"
I get the following error:
The offending line appears to be:
app_root: D:\WynsureEnvironments\Application
wynsure_root: "{{ appserver.root_directory }}\config"
^ here
We could be wrong, but this one looks like it might be an issue with
missing quotes. Always quote template expression brackets when they
start a value. For instance:
with_items:
- {{ foo }}
Should be written as:
with_items:
- "{{ foo }}"
When using variable blocks, how can I reuse variables to assign new variables?
Thanks!
You cannot use such a recursive jinja2 variable declaration in ansible.
Here are 2 (non exhaustive list) alternative solutions:
Don't use a hash. Prepend your vars names. You will typically find this type of naming conventions in e.g. reusable roles on ansible galaxy
appserver_root_directory: C:\app
appserver_config_directory: '{{ appserver_root_directory }}\config'
If you really need a hash of this kind, declare a "private" variable outside of your hash and reuse it inside.
_appserver_root: C:\app
appserver:
root_directory: "{{ _appserver_root }}"
config_directory: "{{ _appserver_root }}\config"
I use Ansible 2.3.2.0 for my project. In this project, I have a task using is_file test:
- name: Create repository.ini file
template: src="{{ playbook_dir }}/../../../repository.ini" dest="/{{ repository_dir }}/repository.ini"
when: "{{ playbook_dir }}/../../..//repository.ini"|is_file
This task produces the following error:
The offending line appears to be:
template: src="{{ playbook_dir }}/../../../repository.ini" dest="/{{ jse_repository_dir }}/repository.ini"
when: "{{ playbook_dir }}/../../../repository.ini"|is_file
^ here
We could be wrong, but this one looks like it might be an issue with
missing quotes. Always quote template expression brackets when they
start a value. For instance:
. . . .
I tried everything I could with no avail.
When you start a YAML key value with a quote, you must quote the whole value, so if there are any other strings inside, you should use a different quotation mark (e.g., single quote + double quote).
Ansible expects the value of when to be a Jinja2 statement, so there is no need to use {{ inside.
Because 2. that you need to use Jinja2 syntax for string concatenation variable + 'string'.
Combined, your conditional should be:
when: "(playbook_dir+'/../../../repository.ini')|is_file"
assume I have test.yml and a variable: packages in command line to specify which yml need to run, test.yml is as below:
- include: "{{item}}.yml"
with_items:
- a
- a_a
- b
- c
when: "'{{item}}' in packages"
loop_control:
loop_var: item
it seems when ansible check the condition "'{{item}}' in packages" it is using like but not equal. e.g. if I run:
ansible-playbook -i hosts -e hosts=myhost test.yml -e packages = [a_a, b]
Anisible will run a_a.yml, b.yml and a.yml as well (don't want a.yml to run). how could I change the way ansible check the condition to fix it (change name is not a sustainable way)?
First: don't use curly brackets in when statement – it's already Jinja2 expression.
when: item in packages
Second: in operator checks that one list(item) is a part of another list and because strings in Python may be treated as lists, in operator is often used to check for pattern in string like: 'pattern' in str_var.
Third: -e argument for ansible-playbook accepts two form of values: key=value and JSON, and there is a note about this in the docs:
Note
Values passed in using the key=value syntax are interpreted as strings. Use the JSON format if you need to pass in anything that shouldn’t be a string (Booleans, integers, floats, lists etc).
Combining all this together, you should fix your when statement and pass extra vars as JSON:
-e '{"packages":["a_a","b"]}'
In particular, I have a group_vars/all.yml file, with essentially the following contents:
my_foo: asdf
my_bar: '{{ my_foo }}'
If I later, while templating a file in a playbook, such as:
- name: template a file
template:
src: something.j2
dest: '....'
And in that something.j2 file, I use {{ my_bar }}, I somehow get asdf. How?
My prior understanding was that files such as group_vars/all.yml where essentially parsed as parse_yaml(parse_and_evaluate_jinja2(contents_of_the_file)). But if this were true, the line my_bar: '{{ my_foo }}' would not correctly evaluate: either we'd get an error, since my_foo is undefined to Jinja, or some default text, like "undefined", or ''. It's like the YAML was being parsed at the same time as the the Jinja2, which seems unlikely. Is that really what Ansible does? Or am I missing something else entirely?
(I couldn't find any exact documentation on how variable files are parsed in Ansibles docs, so if they exist, links are appreciated.)
My prior understanding was that files such as group_vars/all.yml where essentially parsed as parse_yaml(parse_and_evaluate_jinja2(contents_of_the_file))
Wrong. Ansible does all evaluation in runtime, for example:
You tell Ansible:
- debug:
msg: "{{ my_bar }}"
So when Ansible is going to pass msg parameter to debug module, it will do:
What is the parameter?
The parameter is {{ my_bar }}. Oh, it's a template and there's variable my_bar.
What is the my_bar's value?
The value is {{ my_foo }}. Oh, it's a template again, and there's variable my_foo.
What is the my_foo's value?
The value is asdf. Good! Nothing more to template.
So, my_bar's value is now asdf.
And parameter value is not asdf.
Let's print asdf.
By writing:
my_var: "{{ my_other_var }}"
you don't assign variables as in general programming, but write a simple template to calculate my_var's value in any given time (runtime), and not in time of parsing.
I am trying to split the variable based on delimiter. How can I achieve it?
some_module: {{item}}.split('#')[1]
with_items:
- git#someversionxxx
- gradle#someversionxxx
I get following error:
list object' has no attribute 'split ansible
I want to consider only first part of variable i.e. before '#'
some_module: "{{ item.split('#')[0] }}"
{{ ... }} is used to indicate Jinja2 expressions and everything you have is a Jinja2 expression
with YAML syntax in Ansible you must quote a string if it starts with { (unless it was a JSON object, here it's not)
the first element of the split result will have an index of 0