Use dotted YAML variables file in Ansible - variables

I'm trying to achieve the following using Ansible:
Define a YAML file with some variables in the dotted format inside it (variables.yml)
database.hosts[0]: "db0"
database.hosts[1]: "db1"
database.hosts[2]: "db2"
foo.bar: 1
foo.baz: 2
Load the variables in variables.yml by using the include_vars module in my playbook (playbook.yml) and print them in a tree structure
- hosts: all
gather_facts: not
tasks:
- name: "Loading vars"
run_once: true
include_vars:
file: 'variables.yml'
- name: "Testing"
debug:
msg: "{{ foo }}"
- name: "Testing"
debug:
msg: "{{ database }}"
Running this results in the following error:
fatal: [host0]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'foo' is undefined\n\nThe error appears to be in '.../playbook.yml': line 9, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - name: \"Testing\"\n ^ here\n"}
Which makes it clear that each property in the YAML file has been loaded as a separate property and not as properties within two trees rooted in database and foo.
Of course, the playbook works as expected if I specify the properties as follows:
database:
hosts:
- "db0"
- "db1"
- "db2"
foo:
bar: 1
baz: 2
However, I need the YAML variables file to be in the dotted format instead of in the classic indented format. Is there any way to achieve this? E.g.: a module different from include_vars or some configuration that I can add to the ansible.cfg file? I have already tried to use hash_behaviour=merge, but that didn't help.

Q: "I need the YAML variables file to be in the dotted format instead of in the classic indented format. Is there any way to achieve this?"
A: No. It's' not possible. See Creating valid variable names.

Related

DevOps Pipeline Variables cannot be compared

I have a question to DevOps Pipelines.
I have created a Pipeline and during this creation I add a variable with this values “ Name: RESIDENCE ; value: ISS“. So this Value is defined outside from any script.
Pipeline Variable
Inside the .yml file I use this code:
variables:
- name: shuttle
value: Columbia
- name: pipe_var
value: $(RESIDENCE)
- name: location
${{ if eq(variables.pipe_var, 'ISS') }}:
value: pretty_cool
${{ if eq(variables.pipe_var, 'MIR') }}:
value: not_possible
steps:
- script: |
echo space shuttle is: $(shuttle)
echo residence is: $(pipe_var)
echo place to be is: $(location)
But The Pipeline output is only showing:
space shuttel is: Columbia
resicende is: ISS
place to be is:
So as it can be seen in the line “resicende is: ISS “ the value from the outside variable “RESIDENCE” is shown correct. To show this value I use the detour over the variable “pipe_var”. But when I try to compare this variable value with the “if equal” lines then I get no results.
What I’m doing wrong? Is there a special way to compare string values in a pipeline?
It would be nice if someone could give me a hint.

Ansible registered variable has attribute not found error due to multiple when conditions

How do we check for a registered variable if only one of the two conditions turns out to be true having the same registered variable?
Below is my playbook that executes only one of the two shell modules.
- name: Check file
shell: cat /tmp/front.txt
register: myresult
when: Layer == 'front'
- fail:
msg: data was read from front.txt and print whatever
when: myresult.rc != 0
- name: Check file
shell: cat /tmp/back.txt
register: myresult
when: Layer == 'back'
- fail:
msg: data was read from back.txt and print whatever
when: myresult.rc != 0
Run the above playbook as
ansible-playbook test.yml -e Layer="front"
I do get error that says myresult does not have an attribute rc. What is the best way to print debug one statements based on the condition met?
Note: I wish the fail to terminate the execution of the play as soon as the condition is met hence I beleive ignore_errors with fail will not help.
Note: The shell modules can be any Unix command.
I tried myresult is changed but that too does not help. Can you please suggest.
You may want to look at this logical grouping of tasks: blocks
- name: Check file
block:
- name: check file
shell: cat /tmp/front.txt
register: myresult
ignore_errors: true
- fail:
msg: data was read from front.txt and print whatever
when: myresult.rc != 0
when: Layer == 'front'
- name: Check file
block:
- name: check file
shell: cat /tmp/back.txt
register: myresult
ignore_erros: true
- fail:
msg: data was read from back.txt and print whatever
when: myresult.rc != 0
when: Layer == 'back'
when the variable Layer is set to the front it will execute the shell command for front. but in case when the file doesn't exists it will give the error no such file exists and stop the play. so i have put the ignore_errors in the shell task.it will ignore it and jump to the fail module.

Ansible variable list span

When adding a variable list in Ansible how would one achieve a span of similar values? For instance "000-100" - in an Ansible hosts file this can be done by listing like so, "hostname-[a:v].com". Would this process be the similar in a variable list?
My use case is to provision many VM's within oVirt in a single go without having to make a line by line list.
---
- name: Create VM based on template
hosts: ovirt-engine
become: yes
become_method: sudo
vars:
- temp: '{{temp_fedora25}}'
- iname:
- db-aa
- db-ab
- db-ac
tasks:
- name: Giving Birth to lil Baby VM's
ovirt:
user: '{{ovirt_usr}}'
password: '{{ovirt_pass}}'
url: '{{engine_url}}'
instance_name: "{{item}}"
instance_nic: ovirtmgmt
resource_type: template
image: '{{temp}}'
zone: superblade-a
disk_alloc: preallocated
with_items: "{{iname}}"
You can use sequence lookup:
- name: numeric
debug:
msg: "{{ item }}"
with_sequence: start=1 count=10 format=server-%0d
- name: characters from small 'a'
debug:
msg: "{{ item }}"
with_sequence: start=0x61 count=10 format=server-%c
- name: save for future use
set_fact:
my_seq: "{{ lookup('sequence','start={} count={} format={}{}'.format(beg,cnt,pref,fmt),wantlist=True) }}"
vars:
beg: 1
cnt: 10
pref: host-
fmt: '%0d'
You can skip set_fact and define my_seq in vars section, but if you use my_seq much, list generation will be done internally every time. With set_fact list is generated once.
With respect to the correct answer from Konstantin, I'm adding the full solution as per my case....
My goal is to be able to reuse the sequenced values as registered variables in order to pass the instance name to host name. This works so far but Im sure it can be streamlined by nesting variables perhaps?
---
- name: Create VM based on template
hosts: ovirt-engine
become: yes
become_method: sudo
vars:
- temp: '{{temp_fedora25}}'
- host_pre: db
- host_seq: a%c
- host_cnt: 3
- host_srt: 0x61
tasks:
- name: Giving Birth to lil Baby VM's
ovirt:
user: '{{ovirt_usr}}'
password: '{{ovirt_pass}}'
url: '{{engine_url}}'
instance_name: "{{item}}"
instance_nic: ovirtmgmt
resource_type: template
image: '{{temp}}'
zone: superblade-a
disk_alloc: preallocated
with_sequence: start="{{host_srt}}" count="{{host_cnt}}" format="{{host_pre}}-{{host_seq}}"

Paste sensitive data the ansible way

Let's suppose i have some applications inside a repository. Sensitive data, like database username+password, are not stored inside the repository but are in a separate encrypted password database. Within the source code are only place-holders like this: %%mysqlpassword%%.
I want to create an ansible-playbook to checkout the code and replace the user-credentials.
I have two ideas to do so:
with a template or
with the replace module.
Is there a best practise way to accomplish this task?
---
- hosts: test
vars_prompt:
- name: "mysqlpassword"
prompt: "Enter mysql password for app"
private: yes
tasks:
- name: copy code from repo
subversion: repo=https://repo.url.local/app dest=/srv/www/app
- name: Replacement of sensitive data by templating
template: src=mysqlconnect.php.j2 dest=/srv/www/app/inc/mysqlconnect.php
- name: Replacement of sensitive data by replacement function
replace: dest=/srv/www/app/inc/mysqlconnect.php regexp='%%mysqlpassword%%' replace='{{ mysqlpassword }}'
The best answer to your question is use ansible-vault.
1- use mysqlpassword as variable {{ mysqlpassword }} inside your template mysqlconnect.php.j2
2- create separate file like my_very_secure.yml(whatever name you want) with all the values of your secure username and password:
---
mysqlpassword: very-secure-password-value
anothervariable: another-secure-value
After that you can encrypt this file with ansible-vault:
ansible-vault encrypt my_very_secure.yml
Then you can store this file into source control server because it's encrypted or leave it on the ansible master server, but once you are ready to run the playbook just include the --ask-vault-pass option like this and path to your secure file:
ansible-playbook -i yourhostfile yourplaybook.yml -e#/path-to-your-file/my_very_secure.yml --ask-vault-pass
Hope this will help you.

ansible playbook of playbooks with variables

I'm not even sure if this is possible..
I know you can have a playbook that calls other playbooks..
IE:
---
# MasterPlaybook.yml
- include: playbook1.yml
when: some_var == "true"
- include: playbook2.yml
when: someother_var == "true"
and this will work if I call MasterPlaybook.yml and pass in the Vars..
BUT I want to include the vars from some other yml
for example here is myvars.yml
some_var: "true"
someother_var: "false"
Other_var: "Foo"
So if I want this included in a playbook1.yml I simply add..
---
- name: Script Play use variables to get and push out the code
hosts: somegroup
remote_user: "some user"
vars:
url: 'The url of the build'
buildNumber: 'the build number'
jobName: 'passed in job name'
vars_files:
- ~/myvars.yml
serial: 1
and it will pull in the vars..
My question is how do I do this in the masterplaybook.yml so that I don't have to pass in the vars?
and while we are at it.. are there any good examples of a master playbook? (or a playbook of playbooks)
You can specify vars as part of the include statements. This is what I do for some of my projects.
---
- include: playbook1.yml
vars:
some_var: "true"
someother_var: "false"
Other_var: "Foo"
when: some_var == "true"
- include: playbook2.yml
when: someother_var == "true"
Have a look at roles in ansible. They are a more structured way for the "playbook of playbooks" concept. There you can define global variables in the "master" playbook and variables within the sub-playbooks http://docs.ansible.com/playbooks_roles.html.
You can also have a look at the example playbooks to see how roles are used and structured.