yaml syntactical error with_items loop with a list - ansible

trying to loop with a list to create a append a yaml file; getting some syntactical error ?
any idea how we can fix this ?
- name: "append yml"
shell: echo "instances:\n\n - name: all\n - command: all\n - arguments:\n - cluster_name: dbtype{{ item }} all\n - host: {{ipv4}}\n" >> /path/dbtype-config.yml
shell: echo " - auth_source: admin\n - ssl: false\n - ssl_insecure_skip_verify: false\n - labels:\n - env: env\n" >> /tmp/newrelic-infra/integrations.d/dbtype-config.yml
with_items: "{{ instances.stdout_lines }}"
ERROR! Syntax Error while loading YAML.
The error appears to have been in '/ansible/projects/newrelic/dbtype_nr.yml': line 27, column 47, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
- name: "update yml"
shell: echo "instances:\n\n - name: all\n - command: all\n - arguments:\n - cluster_name: dbtype{{ item }} all\n - host: {{ipv4}}\n" >> /path/dbtype-config.yml
^ 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 }}"

looks like it's something similar to #Unknown's suggestion, put single quotes around the : inside of the echo.
Also, are you certain two shell commands will work inside of the single task? I would make two tasks, like:
- name: "append 1st yml"
shell: echo 'first part'
with_items: "{{ my_list }}"
- name: "append 2nd yml"
shell: echo 'second part'
with_items: "{{ my_list }}"

Related

Ansible trim string

I'm trying write role to install MySql 8, and get problem with this:
- name: Extract root password from logs into {{ mysql_root_old_password }} variable
ansible.builtin.slurp:
src: "{{ mysql_logfile_path }}"
register: mysql_root_old_password
#when: "'mysql' in ansible_facts.packages"
- name: Extract root password from logs into {{ mysql_root_old_password }} variable
set_fact:
mysql_root_old_password: "{{ mysql_root_old_password.content | b64decode | regex_findall('generated for root#localhost: (.*)$', 'multiline=true') }}"
#when: "'mysqld' in ansible_facts.packages"
- name: Get Server template
ansible.builtin.template:
src: "{{ item.name }}.j2"
dest: "{{ item.path }}"
loop:
- { name: "my.cnf", path: "/root/.my.cnf" }
notify:
- Restart mysqld
on the .my.cnf I get password with quotes and brackets:
[client]
user=root
password=['th6k(gZeJSt4']
How to trim that?
What I try:
- name: trim password
set_fact:
mysql_root_old_password2: "{{ mysql_root_old_password | regex_findall('[a-zA-Z0-9,()!##$%^&*]{12}')}}"
Thanks.
The result of regex_findall is a list because there might be more matches. Take the last item
- set_fact:
mysql_root_old_password: "{{ mysql_root_old_password.content|
b64decode|
regex_findall('generated for root#localhost: (.*)$', 'multiline=true')|
last }}"
From your description
on the .my.cnf I get password with quotes and brackets ... How to trim that
I understand that you like to read a INI file like my.cnf.ini
[client]
user=root
password=['A1234567890B']
where the value of the key password looks like a list with one element in YAML and the structure doesn't change, but you are interested in the value without leading and trailing square brackets and single quotes only.
To do so there are several possibilities.
Via Ansible Lookup plugins
---
- hosts: localhost
become: false
gather_facts: false
tasks:
- name: Extract root password from INI file
debug:
msg: "{{ lookup('ini', 'password section=client file=my.cnf.ini') }}"
register: result
- name: Show result with type
debug:
msg:
- "{{ result.msg }}"
- "result.msg is of type {{ result.msg | type_debug }}"
- "Show password only {{ result.msg[0] }}" # the first list element
Such approach will work on the Control Node.
Like all templating, lookups execute and are evaluated on the Ansible control machine.
Further Q&A
How to read a line from a file into an Ansible variable
What is the difference between .ini and .conf?
Further Documentation
ini lookup – read data from an INI file
Via Ansible shell module, sed and cut.
---
- hosts: localhost
become: false
gather_facts: false
tasks:
- name: Extract root password from INI file
shell:
cmd: echo $(sed -n 's/^password=//p' my.cnf.ini | cut -d "'" -f 2)
register: result
- name: Show result
debug:
msg: "{{ result.stdout }}"
Please take note regarding "I get password with quotes and brackets ... ['<pass>'] ... How to trim that?" that from perspective of the SQL service, .cnf file, [' and '] are actually part of the password!
- name: Server template
template:
src: "my.cnf.ini"
dest: "/root/.my.cnf"
If that is correct they will be necessary for proper function of the service.

how to use with_items register.results

I'm currently running a command as follows:
- name: "1. search directory"
shell: find /var/ -name "directory"
register: directoty
- name: "boucle"
debug:
msg: "{{item}}"
with_items: "{{directory.stdout_lines}}"
- name: "2. check existance of file"
stat:
path: "{{item}}/file.log"
with_items: "{{directory.stdout_lines}}"
register: checkfile
- debug:
msg: "file name {{item}} exists"
with_items: {{checkfile.results}}
when: checkfile.stat.exists
when i launch it i have error:
with_items: \"{{checkfile.results}}\"\n ^ here\nWe could be wrong, but this one looks like it might be an issue with\nmissing quotes. Always quote template expression brackets when they\nstart a value. For instance:\n\n with_items:\n - {{ foo }}\n\nShould be written as:\n\n with_items:\n - \"{{ foo }}\"\n"}
what can i do to use with_items with stat register
There are a few issues with your last task.
Add quotes " to the with_items: parameter value
Use item in the when: parameter
Use consistent spacing in YAML files (i.e. 2 space indentations)
Example below:
- name: "2. check existance of file"
stat:
path: "{{item}}/file.log"
with_items: "{{directory.stdout_lines}}"
register: checkfile
- debug:
msg: "file name {{item}} exists"
with_items: "{{checkfile.results}}"
when: item.stat.exists

I tried to use "with_items" inside when statement but failed

- hosts: 22rrvgndns01
gather_facts: no
vars_files:
- /etc/ansible/dnschange/dns_resource_record.yml
tasks:
- shell: grep "{{item.name}}" check_result.txt
args:
chdir: /cluster/dnschange
when: "{{item.action}}" is match("delete")
with_items: "{{resource_record}}"
Here is the resource_record:
- resource_record:
- name: test.201.apn.epc.mnc002.mcc505.3gppnetwork.org
record_type: naptr
action: create
view: MME
ttl: 300
order: 100
preference: 999
flags: s
service: x-3gpp-pgw:x-gn:x-gp:x-s5-gtp
replacement: wip-ows-pgw-e-NSW.node.epc.mnc002.mcc505.3gppnetwork.org
I got the error when I executed the script
The offending line appears to be:
chdir: /cluster/dnschange
when: "{{item.action}}" is match("delete")
^ here
I 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 }}"
Can anyone help me out?
I guess your indentation is wrong and change in when condition. Can you try as below
- shell: grep "{{item.name}}" check_result.txt
args:
chdir: /cluster/dnschange
when: item.action == 'delete'
with_items: "{{resource_record}}"

How to escape ? in Ansible task?

Is it possible to include a JSON query in the actual task? All of the examples show using an additional var for the query.
Taking the example from Ansible Filters
- name: "Display all ports from cluster1"
debug:
var: item
loop: "{{ domain_definition | json_query(server_name_cluster1_query) }}"
vars:
server_name_cluster1_query: "domain.server[?cluster=='cluster1'].port"
Converted to:
- name: "Display all ports from cluster1"
debug:
var: item
loop: "{{ domain_definition | json_query(domain.server[?cluster=='cluster1'].port) }}"
as is it returns:
FAILED! => {"reason": "Syntax Error while loading YAML.\n found unknown escape character '?'
I have tried to add an escape backslash before the question mark, but it still fails with:
"template error while templating string: unexpected char '?'
It's possible to use back-ticks ` . For example
- name: "Display all ports from cluster1"
debug:
var: item
loop: "{{ domain_definition | json_query('domain.server[?cluster==`cluster1`].port') }}"
(not tested)
Ok it appears you can escape double quote the query and it will work!
- name: "Display all ports from cluster1"
debug:
var: item
loop: "{{ domain_definition | json_query(\"domain.server[?cluster=='cluster1'].port\") }}"
To step a little bit aside from escape hell, I like to take advantage of yaml scalar blocks
- name: "Display all ports from cluster1"
vars:
my_query: >-
domain.server[?cluster=='cluster1'].port
debug:
var: item
loop: "{{ domain_definition | json_query(my_query) }}"
You don't have to escape anything this way (works for quotes and backslash as well, nice for regexps)

How to register with_items and act on conditional check result for each item

I'd like to register the contents of bashrc for two users and edit as/if required. My play is as follows.
- name: Check bashrc
shell: cat {{ item }}/.bashrc
register: bashrc
with_items:
- "{{ nodepool_home }}"
- "{{ zuul_home }}"
- name: Configure bashrc
shell:
cmd: |
cat >> {{ item }}/.bashrc <<EOF
STUFF
EOF
with_items:
- "{{ nodepool_home }}"
- "{{ zuul_home }}"
when: '"STUFF" not in bashrc.stdout'
It fails as follows:
fatal: [ca-o3lscizuul]: FAILED! => {"failed": true, "msg": "The conditional check '\"STUFF\" not in bashrc.stdout' failed. The error was: error while evaluating conditional (\"STUFF\" not in bashrc.stdout): Unable to look up a name or access an attribute in template string ({% if \"STUFF\" not in bashrc.stdout %} True {% else %} False {% endif %}).\nMake sure your variable name does not contain invalid characters like '-': argument of type 'StrictUndefined' is not iterable\n\nThe error appears to have been in '/root/openstack-ci/infrastructure-setup/staging/zuul/create-user.yml': line 35, column 5, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - name: Configure bashrc\n ^ here\n"}
I think, if I understand your requirement correctly, you can use the 'lineinfile' or 'blockinfile' modules and save yourself the hassle of testing for the existence of the content:
- name: Noddy example data
set_fact:
single_line: "STUFF"
multi_line: |
STUFF
STUFF
profile_dirs:
- "{{ nodepool_home }}"
- "{{ zuul_home }}"
- name: Ensure STUFF exists in file
lineinfile:
path: "{{ item }}/.bashrc"
line: "{{ single_line }}"
loop: "{{ profile_dirs }}"
- name: Ensure block of STUFF exists in file
blockinfile:
path: "{{ item }}/.bashrc"
block: "{{ multi_line }}"
loop: "{{ profile_dirs }}"
Both modules give a lot more control and you can find their docs here: lineinfile | blockinfile

Resources