Ansible fileinline not working with loop - yaml

I am trying to add or edit multiple lines in a file using lineinfile but not working. I am using below code with no luck Ref: ansible: lineinfile for several lines?
# vim /etc/ansible/playbook/test-play.yml
- hosts: tst.wizvision.com
tasks:
- name: change of line
lineinfile:
dest: /root/test.txt
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
backrefs: yes
with_items:
- { regexp: '^# line one', line: 'NEW LINE ONE' }
- { regexp: '^# line two', line: 'NEW LINE TWO' }
Ansible Error:
# ansible-playbook test-2.yml
TASK [change of line] **********************************************************
fatal: [localhost]: FAILED! => {"failed": true, "msg": "the field 'args' has an invalid value, which appears to include a variable that is undefined. The error was: 'item' is undefined\n\nThe error appears to have been in '/etc/ansible/playbook/test-2.yml': line 3, column 5, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n tasks:\n - name: change of line\n ^ here\n"}

Your with_items is not indented correctly within the task.
with_items should be at the level of the module, not as a parameter to the module itself. In your case, you are passing with_items as a parameter to lineinfile module, and ansible is complaining that there is no parameter as with_items for lineinfile module.
Your task should look something like this -
tasks:
- name: change of line
lineinfile:
dest: /root/test.txt
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
backrefs: yes
with_items:
- { regexp: '^# line one', line: 'NEW LINE ONE' }
- { regexp: '^# line two', line: 'NEW LINE TWO' }

Related

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

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.

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 Script Module Not Interpreting Variable

I am having an issue with the Ansible script module interpreting a with_items variable.
vsa_deploy_config/tasks/main.yml:
- name: Create VSA scripts for center
template:
src: vsa_deploy.ps1.j2
dest: "/opt/ansible/roles/vsa_deploy_config/files/{{ item.vsa_hostname }}.ps1"
when: target == "local"
with_items:
- "{{ vsa_center }}"
- name: Deploy VSAs on Center
script: "files/{{ item.vsa_hostname }}.ps1"
register: out
when: target == "win_center"
- debug: var=out
with_items:
- "{{ vsa_center }}"
vsa_deploy_config/vars/main.yml:
---
vsa_center:
- vcsa_hostname: 10.10.10.74
vcsa_username: administrator#vsphere.local
vcsa_password: password
vcsa_datacenter: DataCenter1
vsa_rdm_lun: 02000000006006bf1d58d25a1020d292f8fcfb22b3554353432d4d
vsa_hostname: sm01-ct01
vsa_mgmt_ip: 10.10.10.75
vsa_mgmt_netmask: 255.255.255.192
vsa_mgmt_gw: 10.10.10.65
vsa_mgmt_ns: 10.10.10.92
vsa_mgmt_pg: SC-MGMT
vsa_mgmt_moref: Network:network-13
vsa_iscsi_ip: 192.168.2.1
vsa_iscsi_netmask: 255.255.255.0
vsa_iscsi_pg: ISCSI
vsa_iscsi_moref: Network:network-22
vsa_mirror_ip: 192.168.5.1
vsa_mirror_netmask: 255.255.255.0
vsa_mirror_pg: Mirror
vsa_mirror_moref: Network:network-23
esxi_hostname: 10.10.10.72
esxi_datastore: DS-01
- vcsa_hostname: 10.10.10.74
vcsa_username: administrator#vsphere.local
vcsa_password: password
vcsa_datacenter: DataCenter1
vsa_rdm_lun: 02000000006006bf1d58d25dd0210bb356a78344e5554353432d4d
vsa_hostname: sm02-ct01
vsa_mgmt_ip: 10.10.10.76
vsa_mgmt_netmask: 255.255.255.192
vsa_mgmt_gw: 10.10.10.65
vsa_mgmt_ns: 10.10.10.92
vsa_mgmt_pg: SC-MGMT
vsa_mgmt_moref: Network:network-13
vsa_iscsi_ip: 192.168.2.2
vsa_iscsi_netmask: 255.255.255.0
vsa_iscsi_pg: ISCSI
vsa_iscsi_moref: Network:network-22
vsa_mirror_ip: 192.168.5.2
vsa_mirror_netmask: 255.255.255.0
vsa_mirror_pg: Mirror
vsa_mirror_moref: Network:network-23
esxi_hostname: 10.2.120.73
esxi_datastore: DS-02
When I run the playbook I get the following error:
TASK [vsa_deploy_config : Deploy VSAs on Center] *******************************************************************************
fatal: [auto-win1.lab.com]: FAILED! => {"failed": true, "msg": "the field 'args' has an invalid value, which appears to include a variable that is undefined. The error was: 'item' is undefined\n\nThe error appears to have been in '/opt/ansible/roles/vsa_deploy_config/tasks/main.yml': line 10, 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: Deploy VSAs on Center\n ^ here\n"}
to retry, use: --limit #/opt/ansible/powershell.retry
The first task using the template module interprets the item.vsa_hostname variable correctly, but the script module does not. Is the script module not capable of using with_items?
There is no with_items for your script task:
- name: Deploy VSAs on Center # -\
script: "files/{{ item.vsa_hostname }}.ps1" # \
register: out # / This is task1
when: target == "win_center" # -/
- debug: var=out # -\
with_items: # > This is task2
- "{{ vsa_center }}" # -/
I guess you'd want to move debug to the very bottom:
- name: Deploy VSAs on Center
script: "files/{{ item.vsa_hostname }}.ps1"
register: out
when: target == "win_center"
with_items: "{{ vsa_center }}"
- debug: var=out
P.S. also there is no need to feed unnecessary nested list into with_items.
just move the line - debug: var=out to the end of the file and it will work

ansible conditional check a item's attribute exist

I want to create users using ansible and want to set their shell and sudo permissions.
Now I have vars/main.yml as below:
users: [{'name': 'user1', 'shell': '/bin/bash', 'sudo': 'user1 ALL=(ALL) NOPASSWD: ALL'}, {'name': 'user2', 'shell': '/bin/zsh', 'sudo': 'user2 ALL=NOPASSWD:/bin/systemctl *start nginx'}, {'name': 'user3', 'shell': '/bin/fish'}]
On the task Set sudo permission for users
because not every user have sudo permission, which I need to check if the sudo attribute is exist or not.
- name: Set sudo permission for users
lineinfile:
dest: /etc/sudoers
state: present
regexp: '^{{ item.name }}'
line: "{{ item.sudo }}"
backup: true
when: "{{ item.sudo }}"
with_items:
- "{{ users }}"
I got error as below:
TASK [createUsers : Set sudo permission for users] ***************************
fatal: [ubuntu]: FAILED! => {"failed": true, "msg": "The conditional check '{{ item.sudo }}' failed. The error was: expected token 'end of statement block', got 'ALL'\n line 1\n\nThe error appears to have been in '/Users/csj/proj/roles/createUsers/tasks/main.yml': line 26, 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: Set sudo permission for users\n ^ here\n"}
I tried many about quote things but it didn't help.
It should work
when: item.sudo is defined
so the task is
- name: Set sudo permission for users
lineinfile:
dest: /etc/sudoers
state: present
regexp: '^{{ item.name }}'
line: "{{ item.sudo }}"
backup: true
when: item.sudo is defined
with_items:
- "{{ users }}"

Ansible loops in lineinfile

Commenting out multiple lines should work with a standard loop [1] like this:
- name: "Allow /srv folder accessed by default. Just comment out the lines to allow."
lineinfile: dest=/etc/apache2/apache2.conf regexp={{ item.regexp }} line={{ item.line }} state=present
with_items:
- { regexp: '#<Directory /srv/>', line: '<Directory /srv/>' }
But I got an error:
failed: [192.168.101.101] => (item={'regexp': '#<Directory /srv/>', 'line': '<Directory /srv/>'}) => {"failed": true, "item": {"line": "<Directory /srv/>", "regexp": "#<Directory /srv/>"}}
msg: this module requires key=value arguments (['dest=/etc/apache2/apache2.conf', 'regexp=#<Directory', '/srv/>', 'line=<Directory', '/srv/>', 'state=present'])
FATAL: all hosts have already failed -- aborting
So how to get this working with multiple lines/items?
[1] http://docs.ansible.com/playbooks_loops.html#standard-loops
Thank you, tedder42! You we're more than right.
To be idempotent, the lineinfile task needs to match both the commented and uncommented state of the line so we start it: ^#?
So the fully functioning play set out to be:
- name: "Allow /srv folder accessed by default. Comment out the lines to allow. "
lineinfile:
dest=/etc/apache2/apache2.conf
regexp="{{ item.regexp }}"
line="{{ item.line }}"
state=present
with_items:
- { regexp: '^#?<Directory /srv/>', line: '<Directory /srv/>' }
- { regexp: '^#?\tOptions Indexes FollowSymLinks', line: '\tOptions Indexes FollowSymLinks' }
- { regexp: '^#?\tAllowOverride None', line: '\tAllowOverride None' }
- { regexp: '^#?\tRequire all granted', line: '\tRequire all granted' }
- { regexp: '^#?</Directory>', line: '</Directory>'}
This is actually not a good idea. Definitely better is use the copy with backup=yes.
You were really close to having it working. Simply add quotes around the regexp and line.
lineinfile: dest=/etc/apache2/apache2.conf regexp="{{ item.regexp }}" line="{{ item.line }}" state=present
I wasn't entirely sure, but the error message implied there were problems with seeing the regexp and line args, so I tried a few things.
As a reminder, lineinfile is somewhat of an antipattern. When you find yourself using it, that's a sign you should consider switching to copy or template.

Resources