ansible error 'first argument must be string or compiled pattern' - ansible

I have this code in my playbook:
- hosts: standby
remote_user: root
tasks:
- name: replace hostname in config
replace:
path: /opt/agentd.conf
regexp: #\s+Hostname\=
replace: Hostname={{hname}}
backup: yes
- name: add database array in files
lineinfile:
path: /opt/zabbix_agent/share/scripts/{{ item }}
line: 'DBNAME_ARRAY=( {{dbname}} )'
insertafter: DB2PATH=/home/db2inst1/sqllib/bin/db2
backup: yes
with_items:
- Connections
- HadrAndLog
- Memory
- Regular
- name: restart service
shell: /etc/init.d/agent restart
register: command_output
become: yes
become_user: root
tags: restart
- debug: msg="{{command_output.stdout_lines}}"
tags: set_config_st
it will replace # Hostname= in a config file with Hostname= givenhostname and add an array in 4 scripts. array is the name of given database. then it will restart the agent to apply the changes.
when i run this command:
ansible-playbook -i /Ansible/inventory/hostfile /Ansible/provision/nconf.yml --tags set_config_st --extra-vars "hname=fazi dbname=fazidb"
i get this error:
first argument must be string or compiled pattern
i searched a bit but couldn't find the reason. what should i do?

The problem is in this line:
regexp: #\s+Hostname\=
You have to quote the regex because YAML comments start with #, so everything after the # will be ignored by ansible and that is why the error message occures.
So the correct line should be:
regexp: '#\s+Hostname\='
or
regexp: "#\s+Hostname\="

I think the problem is with indention. Please try as below.
- hosts: standby
remote_user: root
tasks:
- name: replace hostname in config
replace:
path: /opt/agentd.conf
regexp: #\s+Hostname\=
replace: Hostname={{hname}}
backup: yes
- name: add database array in files
lineinfile:
path: /opt/zabbix_agent/share/scripts/{{ item }}
line: 'DBNAME_ARRAY=( {{dbname}} )'
insertafter: DB2PATH=/home/db2inst1/sqllib/bin/db2
backup: yes
with_items:
- Connections
- HadrAndLog
- Memory
- Regular
- name: restart service
shell: /etc/init.d/agent restart
register: command_output
become: yes
become_user: root
tags: restart
- debug: msg="{{command_output.stdout_lines}}"
tags: set_config_st

Related

Adding entry to end of line Ansible SLES 12

On SLES 12 server. Trying to append to this entry in my /etc/security/pam_winbind.conf file with this extra entry S-1-5-21-84296906-944397292-530207130-587119.
The line is
require_membership_of=S-1-5-21-84296906-944397292-530207130-496773,S-1-5-21-84296906-944397292-530207130-71056,S-1-5-21-84296906-944397292-530207130-218591
My playbook
---
- name: Configuring ad_access_filter for RHEL systems.
hosts: smt-test
become: yes
tasks:
- name: Taking Backup.
copy:
src: /etc/security/pam_winbind.conf
dest: /etc/security/pam_winbind.conf.backup
remote_src: yes
- name: Add HQCloud to the sssd.conf file
lineinfile:
path: /etc/security/pam_winbind.conf
backrefs: yes
regexp: '(^*2185915*)$'
line: '\1,S-1-5-21-84296906-944397292-530207130-587119'
- name: Add HQCloudScapeSupp to the sudoers file.
lineinfile:
path: /etc/sudoers
line: 'HQCloudScapeSupp ALL=(ALL) NOPASSWD: ALL'
- name: Restarting WinBind Service
service:
name: winbind
state: restarted
Since the pam_winbind.conf will be different on each server, how do I just add that entry to the end of that line regardless of the other memberships?
There are a few problems with your approach IMO
It might be possible to do add your membership line with only a regex and backrefences but achieving idempotence will be a real pain. Indeed, you actually need to add your required membership if it does not already exist anywhere in the string (it might be present but not in last position). If it is already present anywhere, you should not touch anything.
You are making a backup of your file separately where the lineinfile module can do this automatically for you and only when there is a change
you are unconditionally restarting your service where it should only restart when something has actually changed requiring a restart.
The below playbook addresses the above issues:
---
- name: Configuring ad_access_filter for RHEL systems.
hosts: smt-test
become: yes
vars:
config_file: /etc/security/pam_winbind.conf
required_member: S-1-5-21-84296906-944397292-530207130-587119
search_needle: require_membership_of=
search_regexp: "^{{ search_needle }}(.*)$"
tasks:
- name: slurp file content to get existing membership entries
slurp:
path: "{{ config_file }}"
register: slurped_file
- name: Add HQCloud to the sssd.conf file if it does not exist + backup if any change
vars:
file_content_lines: "{{ (slurped_file.content | b64decode).splitlines() }}"
requirement_line: "{{ file_content_lines | select('match', search_needle) | first }}"
existing_members: "{{ (requirement_line | regex_replace(search_regexp, '\\g<1>')).split(',') | map('trim') }}"
wanted_members: "{{ existing_members | union([required_member]) }}"
lineinfile:
path: "{{ config_file }}"
regexp: "{{ search_regexp }}"
backup: true
line: "{{ search_needle }}{{ wanted_members | join(',') }}"
- name: Add HQCloudScapeSupp to the sudoers file.
lineinfile:
path: /etc/sudoers
line: 'HQCloudScapeSupp ALL=(ALL) NOPASSWD: ALL'
# Not really sure this is needed
notify: Restart winbind
handlers:
- name: Restart winbind
service:
name: winbind
state: restarted

hostvars on a temp group in a ansible playbook

I am trying to preserve a command output from one dynamic host group to another one but get a variable is undefined error in my ansible playbook.
My playbook is dynamically getting the primary and secondary hosts by running a command. I want to use the output that I get from the secondary host on the primary with a when statement. Here's what I have.
- hosts: all
serial: 1
tasks:
- name: run curl command to determine primary/secondary
command: /tmp/status.sh
register: apis_op
- name: run curl command to determine primary/secondary
debug: var=apis_op.stdout_lines
- name: If node is primary add to primary
add_host:
name: "{{ ansible_hostname }}"
groups: temp_primary
when: apis_op.stdout == "primary"
- name: run curl command to determine primary/secondary
debug: var=groups
- name: If node is secondary add to secondary
add_host:
name: "{{ ansible_hostname }}"
groups: temp_secondary
when: apis_op.stdout == "secondary"
- name: run curl command to determine primary/secondary
debug: var=groups
- hosts: temp_secondary
tasks:
- name: Run schell script
command: /tmp/runthis.sh
become: yes
become_user: root
register: op
- hosts: temp_primary
tasks:
- name: Run schell script
command: /tmp/testthis.sh
become: yes
become_user: root
when: hostvars['temp_secondary']['op'] == "{false}"
When I run this I get a hostvars['temp_secondary'] is undefined error. Can I not use hostvars with temporary/dynamic host groups?

When Condition with Ansible

I am new to Ansible, and I am writing a script to install a package when disk space is more then a limit. I am getting error like this >> error while evaluating conditional
---
- hosts: dev
become: true
become_user: root
tasks:
- name: Install zsh if enough space
yum:
name: zsh
state: latest
with_items: "{{ ansible_mounts}}"
when: item.mount == "/" and item.size_available > 10737400
I am giving the size in bytes. ( Is there a way to give the size in MB ? )
Thanks.
Ansible uses the YAML format, you need to use the right indent.
In YAML, the indent is important as closing brackets or semicolons in most programming languages.
with_items is not a definition for the yum module, it is a directive for Ansible, so it should be at the same level as when and the module call (e.g. yum). Both examples below should work:
---
- hosts: dev
become: true
become_user: root
tasks:
- name: Install zsh if enough space
yum:
name: zsh
state: latest
with_items: "{{ ansible_mounts }}"
when: item.mount == "/" and item.size_available > 10737400
or
---
- hosts: dev
become: true
become_user: root
tasks:
- name: Install zsh if enough space
with_items: "{{ ansible_mounts }}"
when: item.mount == "/" and item.size_available > 10737400
yum:
name: zsh
state: latest

Will this variable be visible?

I have a simple playbook:
- name: "Ensure /etc/host contains '127.0.0.1'"
lineinfile:
name: /etc/host
line: "127.0.0.1"
state: present
check_mode: yes
register: conf
- name: "Use java role playbook"
roles:
- role: java
if_exist: conf
My question: Will this conf variable be visible and assigned to if_exist?
First you can use shell module to read the file and register the output, then use "when" to search for a specific content in the registered output of the file and base of the result run the task.
- name: cat
shell: "cat /etc/host "
register: conf
- include_role:
name:
when: conf.stdout.find('127.0.0.1') != 1
It's possible even without cat/grep/awk, just use Ansible's lookup and search.
vars:
out: "{{ lookup('file', '/etc/host') }}"
tasks:
- name: "Use java role playbook"
include_role:
name: Java
when: out is search("127.0.0.1")

Ansible writing output from multiple task to a single file

In Ansible, I have written an Yaml playbook that takes list of host name and the executes command for each host. I have registered a variable for these task and at the end of executing a task I append output of each command to a single file.
But every time I try to append to my output file, only the last record is getting persisted.
---
- hosts: list_of_hosts
become_user: some user
vars:
output: []
tasks:
- name: some name
command: some command
register: output
failed_when: "'FAILED' in output"
- debug: msg="{{output | to_nice_json}}"
- local_action: copy content='{{output | to_nice_json}}' dest="/path/to/my/local/file"
I even tried to append using lineinfile using insertafter parameter yet was not successful.
Anything that I am missing?
You can try something like this:
- name: dummy
hosts: myhosts
serial: 1
tasks:
- name: create file
file:
dest: /tmp/foo
state: touch
delegate_to: localhost
- name: run cmd
shell: echo "{{ inventory_hostname }}"
register: op
- name: append
lineinfile:
dest: /tmp/foo
line: "{{ op }}"
insertafter: EOF
delegate_to: localhost
I have used serial: 1 as I am not sure if lineinfile tasks running in parallel will garble the output file.
Ansible doc recommend use copy:
- name: get jstack
shell: "/usr/lib/jvm/java/bin/jstack -l {{PID_JAVA_APP}}"
args:
executable: /bin/bash
register: jstackOut
- name: write jstack
copy:
content: "{{jstackOut.stdout}}"
dest: "tmp/jstack.txt"
If you want write local file, add this:
delegate_to: localhost
Why to complicate things ?
I did this like that and it worked:
ansible-playbook your_playbook.yml >> /file/you/want/to/redirect/output.txt
you can also try some parsing with grep or some other stuff with tee -a.

Resources