Ansible: What's wrong with my "with_itmes" in playbook - ansible

I register 3 hosts key and try to loop my host let another remote host save the key
- setup:
- name: Generate Public Key On 3nodes
openssh_keypair:
path: /root/.ssh/id_rsa
comment: "{{ ansible_hostname }}"
when: inventory_hostname in groups['new_percona']
- name: register public key
shell: cat /root/.ssh/id_rsa.pub
register: public_key
when: inventory_hostname in groups['new_percona']
- name: Add Nodes Public Key On master-0
lineinfile:
dest: /root/.ssh/authorized_keys
line: "{{ hostvars['{{ item }}']['public_key']['stdout'] }}"
with_items:
- percona-0
- percona-1
- percona-2
when: '"master-0" in inventory_hostname'
and the result
TASK [Install : Add Nodes Public Key On master-0] ******************************
fatal: [master-0]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: \"hostvars['{{ item }}']\" is undefined\n\nThe error appears to be in '/tmp/awx_5004_1s769t9j/project/roles/Install/tasks/install-percona.yml': line 62, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: Add Nodes Public Key On master-0\n ^ here\n"}
I also try
- name: Add Nodes Public Key On master-0
lineinfile:
dest: /root/.ssh/authorized_keys
line: "{{ hostvars['{{ groups[new_percona] }}']['public_key']['stdout'] }}"
when: '"master-0" in inventory_hostname'
or loop
- name: Add Nodes Public Key On master-0
lineinfile:
dest: /root/.ssh/authorized_keys
line: "{{ hostvars['{{ item }}']['public_key']['stdout'] }}"
loop: [ 'percona-0', 'percona-1', 'percona-2' ]
when: '"master-0" in inventory_hostname'
But above are wrong
How to use variable to loop the host?
this is working if just single host
- name: Add Nodes Public Key On master-0
lineinfile:
dest: /root/.ssh/authorized_keys
line: "{{ hostvars['percona-0']['public_key']['stdout'] }}"
when: '"master-0" in inventory_hostname'

You cannot use curly braces inside curly braces.
line: "{{ hostvars[item]['public_key']['stdout'] }}"
This should do what you want.

Related

ansible playbook inline to add multiple lines

i got following pb to add multiple lines to chrony.conf
- name: add line
lineinfile:
backup: no
backrefs: no
state: present
path: "{{ file_path }}"
insertafter: "{{ line.replace_with }}"
line: "{{ line.line_to_add }}"
with_items:
- { search: "{{ line.replace_with }}", add: "{{ line.line_to_add }}" }
in my vars files I got it like this
line:
line_to_add:
- "server ntp1.domain.com iburst"
- "server ntp2.domain.com iburst"
- "server ntp3.domain.com iburst"
but the change put all 3 ntp servers in one line instead of 3.
any idea?
when i change my yml to
- name: add line
lineinfile:
backup: no
backrefs: no
state: present
path: "{{ file_path }}"
#regexp: '^(\s*)[#]?{{ item.search }}(: )*'
insertafter: "{{ line.replace_with }}"
line: "{{ item }}"
create: true
loop: "{{ line.line_to_add }}"
with_items:
- { search: "{{ line.replace_with }}", add: "{{ line.line_to_add }}" }
I get suplicate loop in task: items
You can use loop for this to iterate each line in the line.line_to_add variable. I also assumed that you have another line.replace_with variable.
- name: Example of multiple lines
hosts: localhost
gather_facts: no
vars:
line:
line_to_add:
- "server ntp1.domain.com iburst"
- "server ntp2.domain.com iburst"
- "server ntp3.domain.com iburst"
replace_with:
- test_line
tasks:
- name: add line
lineinfile:
backup: no
backrefs: no
state: present
path: test_file
insertafter: "{{ line.replace_with }}"
line: "{{ item }}"
create: true
loop: "{{ line.line_to_add }}"
Gives:
server ntp1.domain.com iburst
server ntp2.domain.com iburst
server ntp3.domain.com iburst

Ansible ERROR! unexpected parameter type in action:

I try to run a role/task, but i cant solve the following error:
ERROR! unexpected parameter type in action: <class 'ansible.parsing.yaml.objects.AnsibleSequence'>
The error appears to be in '/home/<user>/ansible/ilias6/roles/keysAndUsers/tasks/main.yaml': line 2, column 3, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
---
- name: createUser and add to sudoer
^ here
This is my task:
---
- name: createUser and add to sudoer
become: yes
vars_files:
- /home/<user>/ansible/ilias6/roles/keysAndUsers/lists/userCreateList.yaml
user:
name: "{{ item }}"
groups: "sudo, www-data"
password: "{{ 'password' | password_hash('sha512', 'mysecretsalt') }}"
update_password: on_create
state: present
shell: /bin/bash
system: no
createhome: yes
loop: "{{ users }}"
register: useradd
- name: change user password upon creation
shell: chage -d 0 "{{ item.name }}"
loop: "{{ useradd.results }}"
when: item.changed
I noticed, if I comment out the section vars_files its fine. But i need the extern variables unfortunately

Ansible Read csv file and encrypt passwords, output of command to file

I have a csv file containing ip addresses and passwords. These passwords need to be encrypted and written to a file.
This is what I have tried so far:
- name: Read csv file
read_csv:
path: files/ww.csv
fieldnames: ip,password
delimiter: ','
register: routers
delegate_to: localhost
- name: encrypt password
command: "ansible-vault encrypt_string --vault-password-file password '{{ router.password }}' --name 'password'"
loop: "{{ routers.list }}"
loop_control:
loop_var: router
register: "output"
delegate_to: localhost
- name: write file
copy:
content: "{{ output.stdout }}"
dest: "/tmp/{{ router.ip }}.yaml"
loop: "{{ routers.list }}"
loop_control:
loop_var: router
delegate_to: localhost
I want to use output.stdout but I get the following error:
TASK [robustel : write file] *********************************************************************************************************************************
fatal: [10.41.1.161]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'stdout'\n\nThe error appears to be in '/ansible/roles/routers/tasks/create_var_files.yaml': line 20, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: write file\n ^ here\n"}
How can I solve this?
You are registering a variable on a task with a loop. This changes the structure of the data as described in the documentation. Debugging output would have given you a clue.
output.results is a list where each element contains a stdout key (e.g. the first one being output.results.0.stdout). Moreover, each element also contains an item key containing the original element in the loop that was registered.
Modifying your last task like below should give you the expected result:
- name: write file
copy:
content: "{{ output_result.stdout }}"
dest: "/tmp/{{ output_result.item.ip }}.yaml"
loop: "{{ output.results }}"
loop_control:
loop_var: output_result
delegate_to: localhost

ansible "with_lines: cat somefile" fails in a skipped block

I have a playbook with a block that has a when condition. Inside is a task with a loop. How can I change this loop so that when the condition is false the skipped task doesn't fail?
block:
- name: create a file
lineinfile:
line: "Hello World"
path: "{{my_testfile}}"
create: yes
- name: use the file
debug:
msg: "{{ item}}"
with_lines: cat "{{my_testfile}}"
when: false
TASK [create a file] ************************************************************************************************************************************************************
TASK [use the file] *************************************************************************************************************************************************************
cat: files/my/testfile: No such file or directory
fatal: [ipad-icpi01]: FAILED! => {"msg": "lookup_plugin.lines(cat \"files/mytestfile\") returned 1"}
Change your failing task to the following which will always be able to run, even if the file does not exists, and will not use the shell or command where there is no need to:
- name: use the file
debug:
msg: "{{ item }}"
loop: "{{ (lookup('file', my_testfile, errors='ignore') | default('', true)).split('\n') }}"
The key points:
use the file lookup plugin with errors='ignore' so that it returns the file content or None rather than an error when file does not exists.
use the default filter with second option to true so that it return default value if var exists but is null or empty.
split the result on new lines to get a list of lines (empty list if file does not exist).
Note: as reported by #Vladimir, I corrected your var name which is not valid in ansible.
Test the existence of the file. For example
- block:
- name: create a file
lineinfile:
line: "Hello World"
path: "{{ my_testfile }}"
create: yes
- name: use the file
shell: '[ -f "{{ my_testfile }}" ] && cat {{ my_testfile }}'
register: result
- name: use the file
debug:
msg: "{{ item }}"
loop: "{{ result.stdout_lines }}"
when: false
The lookup plugin file should be preferred.
I ended up with a mix of the provided answers. These tasks will be skipped without failing or creating a warning.
- block:
- name: create a file
lineinfile:
line: "Hello World"
path: "{{ my_testfile }}"
create: yes
- name: get the file
slurp:
src: "{{ my_testfile }}"
register: result
- name: use the file
debug:
msg: "{{ item }}"
loop: "{{ (result['content'] | b64decode).split('\n') }}"
when: false

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