How to run command after error occurs in ansible handler - ansible

I have a simple playbook that copies some config files for nginx server and then issues service nginx reload command:
---
- hosts: mirrors
tasks:
- name: Installs nginx web server
apt: pkg=nginx state=installed update_cache=true
notify:
- start nginx
- name: Copy vhost file
copy: src=vhost/test.vhost dest=/etc/nginx/sites-available/ mode=0644
- name: Symlink vhost file to enabled sites
file: src=/etc/nginx/sites-available/test.vhost dest=/etc/nginx/sites-enabled/test.vhost state=link
notify:
- reload nginx
handlers:
- name: start nginx
service: name=nginx state=started
- name: reload nginx
service: name=nginx state=reloaded
Now, the problem is that it might happen that the test.host file contains an error and nginx won't reload properly. If it happens, I'd like to run a command systemctl status nginx.service and see it's output when ansible playbook executes. How can I add this "error handler"?

If the handler output tells you about the failure, you can put together a nice bit of error handling with the ignore_errors and register keywords.
Set your handler not to end to fail and end the play when it gets an error code back, but to register the output as a variable:
handlers:
- name: reload nginx
service: name=nginx state=reloaded
ignore_errors: True
register: nginx_reloaded
Then back in the tasks section, call flush_handlers to execute all the queued handlers that would otherwise wait until the end of the play. Add a task in to go and ask the server about the status of Nginx when your nginx_reloaded variable has a non-zero return code, and then print the information from that with the debug module:
- name: Symlink vhost file to enabled sites
file: src=/etc/nginx/sites-available/test.vhost dest=/etc/nginx/sites-enabled/test.vhost state=link
notify:
- reload nginx
- meta: flush_handlers
- name: Get the Nginx service status if it failed to failed.
command: "systemctl status nginx.service"
register: nginx_status
when: nginx_reloaded.rc != 0
- debug: var=nginx_status
when: nginx_reloaded.rc != 0
Of course, a better solution would be to fix those errors in your configuration files - and figuring them out through Ansible output has limitations compared to SSHing onto the target host to check it out.

Why don't use Ansible modules ability to validate configuration?:
http://docs.ansible.com/ansible/template_module.html
http://docs.ansible.com/ansible/replace_module.html
http://docs.ansible.com/ansible/lineinfile_module.html
For example:
- template: src=/mine/sudoers dest=/etc/sudoers validate='visudo -cf %s'
- lineinfile: dest=/etc/sudoers state=present regexp='^%ADMIN ALL\=' line='%ADMIN ALL=(ALL) NOPASSWD:ALL' validate='visudo -cf %s'
- replace: dest=/etc/apache/ports regexp='^(NameVirtualHost|Listen)\s+80\s*$' replace='\1 127.0.0.1:8080' validate='/usr/sbin/apache2ctl -f %s -t'

Related

I just tried to write a playbook same error in every playbook

--- # this is first playbook with handler
- host: demo
user: ansible
become: yes
connection: ssh
vars:
pkgname: httpd
task:
- name: install httpd service
action: yum name='{{pkgname}}' state=installed
notify: restart httpd
handler:
- name: restart httpd
action: service name=httpd state=restarted
ERROR! 'task' is not a valid attribute for a Play
The error appears to be in '/home/ansible/handler.yml': line 2, column 3, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
--- # this is first playbook with handler
- host: demo
^ here
i think it is tasks: (plural), not task:

Ansible: Failed to restart apache2.service: Connection timed out

I am using Ansible AWX to issue a restart command to restart an apache2 service on a host. The restart command is contained in a playbook.
---
- name: Manage Linux Services
hosts: all
tasks:
- name: Restart a linux service
command: systemctl restart '{{ service_name }}'
register: result
ignore_errors: yes
- name: Show result of task
debug:
var: result
OR
---
- name: Manage Linux Services
hosts: all
tasks:
- name: Restart a linux service
ansible.builtin.service:
name: '{{ service_name }}'
state: restarted
register: result
ignore_errors: yes
- name: Show result of task
debug:
var: result
However, when I run the command, I get the error below:
"Failed to restart apache2.service: Connection timed out",
"See system logs and 'systemctl status apache2.service' for details."
I have tried to figure out the issue, but no luck yet.
I later figured the cause of the issue.
Here's how I fixed it:
The restart command requires sudo access to run which was missing in my command.
All I have to do was to add the become: true command so that I can execute the command with root privileges.
So my playbook looked like this thereafter:
---
- name: Manage Linux Services
hosts: all
tasks:
- name: Restart a linux service
command: systemctl restart '{{ service_name }}'
become: true
register: result
ignore_errors: yes
- name: Show result of task
debug:
var: result
OR
---
- name: Manage Linux Services
hosts: all
tasks:
- name: Restart a linux service
ansible.builtin.service:
name: '{{ service_name }}'
state: restarted
become: true
register: result
ignore_errors: yes
- name: Show result of task
debug:
var: result
Another way if you want to achieve this on Ansible AWX is to tick the Privilege Escalation option in the job template.
If enabled, this runs the selected playbook in the job template as an administrator.
That's all.
I hope this helps
Restarting a service requires sudo privileges. Besides adding the 'become' directive, if you would like to prompt for the password, you can do so by passing the -K flag (note: uppercase K)
$ ansible-playbook myplay.yml -i hosts -u myname --ask-pass -K

"Failure talking to yum: Cannot find a valid baseurl for repo: remi"

I am using the following ansible script to install php-fpm module in centOS but cannot figure out the error.
---
- hosts: all
become: yes
tasks:
- name: download remi release repo for php
get_url:
url: http://rpms.famillecollet.com/enterprise/remi-release-6.rpm
dest: /tmp/remi-release-6.rpm
tags: php-fpm
- name: install remi repo
shell: /bin/rpm -Uvh /tmp/remi-release-6.rpm
register: remi_repo_result
failed_when: "'conflict' in remi_repo_result.stderr"
tags: php-fpm
- name: enable remi repo
ini_file: dest=/etc/yum.repos.d/remi.repo
section=remi
option=enabled
value=1
- name: install php-fpm and its deps
yum: name={{item}} state=present
with_items:
- php
- php-fpm
tags: php-fpm
- name: backup default php configuration
shell: /bin/cp /etc/php.ini /etc/php.default.ini creates=/etc/php.default.ini
tags: php-fpm
- name: display php errors when not in production
ini_file: dest=/etc/php.ini
section=PHP
option=display_errors
value=On
when: env is defined and env != "production"
notify:
- restart php-fpm
tags: php-fpm
- name: do not show php errors when in production
ini_file: dest=/etc/php.ini
section=PHP
option=display_errors
value=Off
when: env is defined and env == "production"
notify:
- restart php-fpm
tags: php-fpm
- name: backup default php-fpm configuration
shell: /bin/cp /etc/php-fpm.d/www.conf /etc/php-fpm.d/www.conf.default creates=/etc/php-fpm.d/www.conf.default
tags: php-fpm
- name: change php-fpm to listen on socket
ini_file: dest=/etc/php-fpm.d/www.conf
section=www
option=listen
value=/var/run/php-fpm/php-fpm.sock
notify:
- restart php-fpm
tags: php-fpm
- name: php-fpm listen mode should always be 0666
ini_file: dest=/etc/php-fpm.d/www.conf
section=www
option=listen.mode
value=0666
notify:
- restart php-fpm
tags: php-fpm
- name: change php-fpm user
ini_file: dest=/etc/php-fpm.d/www.conf
section=www
option=user
value=nginx
notify:
- restart php-fpm
tags: php-fpm
- name: change php-fpm group
ini_file: dest=/etc/php-fpm.d/www.conf
section=www
option=group
value=nginx
notify:
- restart php-fpm
tags: php-fpm
- name: start php-fpm
service: name=php-fpm state=running enabled=yes
tags: php-fpm
I get the following error in the task "install php-fpm and its deps"
failed: [127.0.0.1] (item=[u'php', u'php-fpm']) => {"ansible_loop_var": "item", "changed": false, "item": ["php", "php-fpm"], "msg": "Failure talking to yum: Cannot find a valid baseurl for repo: remi"}
Can someone help with a solution for this?
Note: most of the below is deduced from wild guesses since you did not provide a full and verbose run of the relevant tasks nor the values of the variables for the target you run the playbook against.
There are several issues with your above playbook, the most obvious and relevant one being that
- name: install remi repo
shell: /bin/rpm -Uvh /tmp/remi-release-6.rpm
register: remi_repo_result
failed_when: "'conflict' in remi_repo_result.stderr"
tags: php-fpm
is likelly to not fail although the command is in error.
And since you did not use create: false on the next ini_file task, /etc/yum.repos.d/remi.repo will still be created containing only
[remi]
enabled=1
(For this, I am of course assuming that env is not set or is different from production)
From there, the message you get is quite coherent since there is literally no base url for repo remi.
Some other notes you might want to take into account:
you can install a remote rpm with the yum module by directly passing the url as name
you should not loop over the yum module: pass the list of packages directly in the name attribute (see doc)
don't cp with shell, use the copy module with remote_src: true
Use the yaml syntax rather than ini style shortcut syntax

Ansible playbook example code fail to run

I'm started to try Ansible, and using example code from Ansible Documentation. After I try several examples, I get error at the beginning of the code. It says
- name: Change the hostname to Windows_Ansible
^ here(Point at name)"
Any advice would be appreciate.
I tried this one
https://docs.ansible.com/ansible/latest/modules/win_hostname_module.html#win-hostname-module
---
- name: Change the hostname to Windows_Ansible
win_hostname:
name: "Windows_Ansible"
register: res
- name: Reboot
win_reboot:
when: res.reboot_required
The below task will change the hostname of the server. Make sure you run on a test server so that it wont create issues. If you just wanted to test some playbook, use the second playbook with win_command
---
- hosts: <remote server name which needs to be added in the inventory>
tasks:
- name: Change the hostname to Windows_Ansible
win_hostname:
name: "Windows_Ansible"
register: res
- name: Reboot
win_reboot:
when: res.reboot_required
---
- hosts: <remote server name which needs to be added in the inventory>
tasks:
- name: Test
win_command: whoami
register: res

ansible check non-existent service [duplicate]

I have an Ansible playbook for deploying a Java app as an init.d daemon.
Being a beginner in both Ansible and Linux I'm having trouble to conditionally execute tasks on a host based on the host's status.
Namely I have some hosts having the service already present and running where I want to stop it before doing anything else. And then there might be new hosts, which don't have the service yet. So I can't simply use service: name={{service_name}} state=stopped, because this will fail on new hosts.
How I can I achieve this? Here's what I have so far:
- name: Check if Service Exists
shell: "if chkconfig --list | grep -q my_service; then echo true; else echo false; fi;"
register: service_exists
# This should only execute on hosts where the service is present
- name: Stop Service
service: name={{service_name}} state=stopped
when: service_exists
register: service_stopped
# This too
- name: Remove Old App Folder
command: rm -rf {{app_target_folder}}
when: service_exists
# This should be executed on all hosts, but only after the service has stopped, if it was present
- name: Unpack App Archive
unarchive: src=../target/{{app_tar_name}} dest=/opt
See the service_facts module, new in Ansible 2.5.
- name: Populate service facts
service_facts:
- debug:
msg: Docker installed!
when: "'docker' in services"
Of course I could also just check if the wrapper script exists in /etc/init.d. So this is what I ended up with:
- name: Check if Service Exists
stat: path=/etc/init.d/{{service_name}}
register: service_status
- name: Stop Service
service: name={{service_name}} state=stopped
when: service_status.stat.exists
register: service_stopped
I modified Florian's answer to only use the return code of the service command (this worked on Mint 18.2)
- name: Check if Logstash service exist
shell: service logstash status
register: logstash_status
failed_when: not(logstash_status.rc == 3 or logstash_status.rc == 0)
- name: Check if Logstash service exist
service:
name: logstash
state: stopped
when: logstash_status.rc == 0
It would be nice if the "service" module could handle "unrecognized service" errors.
This is my approach, using the service command instead of checking for an init script:
- name: check for apache
shell: "service apache2 status"
register: _svc_apache
failed_when: >
_svc_apache.rc != 0 and ("unrecognized service" not in _svc_apache.stderr)
- name: disable apache
service: name=apache2 state=stopped enabled=no
when: "_svc_apache.rc == 0"
check the exit code of "service status" and accept the exit code 0 when the output contains "unrecognized service"
if the exit code was 0, that service is installed (stopped or running)
Another approach for systemd (from Jakuje):
- name: Check if cups-browsed service exists
command: systemctl cat cups-browsed
check_mode: no
register: cups_browsed_exists
changed_when: False
failed_when: cups_browsed_exists.rc not in [0, 1]
- name: Stop cups-browsed service
systemd:
name: cups-browsed
state: stopped
when: cups_browsed_exists.rc == 0
Building on #Maciej's answer for RedHat 8, and combining it with the comments made on it.
This is how I managed to stop Celery only if it has already been installed:
- name: Populate service facts
service_facts:
- debug:
msg: httpd installed!
when: ansible_facts.services['httpd.service'] is defined
- name: Stop celery.service
service:
name: celery.service
state: stopped
enabled: true
when: ansible_facts.services['celery.service'] is defined
You can drop the debug statement--it's there just to confirm that ansible_facts is working.
This way using only the service module has worked for us:
- name: Disable *service_name*
service:
name: *service_name*
enabled: no
state: stopped
register: service_command_output
failed_when: >
service_command_output|failed
and 'unrecognized service' not in service_command_output.msg
and 'Could not find the requested service' not in service_command_output.msg
My few cents. The same approach as above but for kubernetes
Check if kublete service is running
- name: "Obtain state of kublet service"
command: systemctl status kubelet.service
register: kubelet_status
failed_when: kubelet_status.rc > 3
Display debug message if kublet service is not running
- debug:
msg: "{{ kubelet_status.stdout }}"
when: "'running' not in kubelet_status.stdout"
You can use the service_facts module since Ansible 2.5. But you need to know that the output are the real name of the service like docker.service or somthing#.service. So you have different options like:
- name: Populate service facts
service_facts:
- debug:
msg: Docker installed!
when: "'docker.service' in services"
Or you can search for the string beginning with the service name; that is much more reliable, because the service names are different between the distributions:
- name: Populate service facts
service_facts:
- debug:
msg: Docker installed!
when: "services.keys()|list|select('search', '^docker')|length >0"

Resources