How should I restart a service using ansible? - ansible

I tried to use Ansible service module to restart a service but I got an error.
tasks:
- ini_file: dest=/etc/dd-agent/datadog.conf
section=Main
option=use_mount
state=absent
register: ddagent
- service: name='datadog-agent' state=reloaded
when: ddagent.changed
This generated this error: ERROR: change handler (restart datadog) is not defined
I know that an alternative is to execute:
- command: "service datadog-agent restart"
Still, in this case what's the purpose of the service module?

You should add the following code:
handlers:
- name: restart datadog
service: name=datadog-agent state=restarted
The problem that you are facing is that you don't have the handler defined. This will do the job

Related

Restart service when service file changes when using Ansible

I am creating a systemd service using template module
---
- name: Systemd service
template:
src: sonar.unit.j2
dest: /etc/systemd/system/sonarqube.service
when: "ansible_service_mgr == 'systemd'"
The contents of the sonarqube.service can change of course. On change I want to restart the service. How can I do this?
There are two solutions.
Register + When changed
You can register template module output (with its status change),
register: service_conf
and then use when clause.
when: service_conf.changed
For example:
---
- name: Systemd service
template:
src: sonar.unit.j2
dest: /etc/systemd/system/sonarqube.service
when: "ansible_service_mgr == 'systemd'"
register: service_conf
- name: restart service
service:
name: sonarqube
state: restarted
when: service_conf.changed
Handler + Notify
You define your restart service task as handler. And then in your template task you notify the handler.
tasks:
- name: Add Sonarqube to Systemd service
template:
src: sonar.unit.j2
dest: /etc/systemd/system/sonarqube.service
when: "ansible_service_mgr == 'systemd'"
notify: Restart Sonarqube
- …
handlers:
- name: Restart Sonarqube
service:
name: sonarqube
state: restarted
More info can be found in Ansible Doc.
Difference between those 2?
In the first case, the service will restart directly. In the case of the handler the restart will happen at the end of the play.
Another difference will be, if you have several tasks changes that need to restart of your service, you simply add the notify to all of them.
The handler will run if any of those task get a changed status. With the first solution, you will have to register several return. And it will generate a longer when clause_1 or clause_2 or …
The handler will run only once even if notified several times.
This calls for a handler
---
- name: Testplaybook
hosts: all
handlers:
- name: restart_service
service:
name: <servicename>
state: restarted
tasks:
- template:
src: ...
dest: ...
notify:
- restart_service
The handler will automatically get notified by the module when something changed. See the documentatation for further information on handlers.
Since you are using systemd, you will also need to execute daemon-reload because you updated the service file.
The task just templates the service file and notifies a handler:
- name: Systemd service
template:
src: sonar.unit.j2
dest: /etc/systemd/system/sonarqube.service
when: "ansible_service_mgr == 'systemd'"
notify: restart sonarqube systemd
Based on the presence of your specific when clause above, I'm assuming you might want to specify separate handlers in the case that systemd is not in use. The handler for the systemd case would look like the following:
- name: restart sonarqube systemd
systemd:
name: sonarqube
state: restarted
daemon_reload: yes

Issue with handler restarting service

I have an issue where I was handed a gaming service from a dev group in Bulgaria that was coded and built last fall. the only documentation I have for the platform which is a video showing one of the devs running the playbooks to build the env. the video doesnt show version of ansible that is being used. I am trying to run playbooks on ubuntu 16.04 and ansible 2.0.0.2. I am trying to execute the following:
- hosts: nler-example-nxx
user: ubuntu
tasks:
- include: ../../templates/nler-nxx.yml
- name: change nodes ip in nxx config
replace:
path: /www/nler-nxx/conf/nxx.properties
regexp: '(\s+)nxx.defaultPeers=(.*)$'
replace: '\1nxt.defaultPeers=52.202.223.114; 35.173.242.207; 34.238.136.137; 54.164.46.62; 54.86.17.225;'
notify:
- restart nxx service
handlers:
- name: restart nxx service
become: yes
systemd: name=nxx state=restarted
And get this error:
ERROR! no action detected in task
The error appears to have been in '/etc/ansible/playbook/niler/example/nxx.yml': line 15, column 7, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
handlers:
- name: restart nxx service
^ here
In doing some research I am thinking this is a version conflict issue but no way to confirm what version they were using.
Indentation is wrong. Should be:
tasks:
- include: ../../templates/nler-nxx.yml
...
.
handlers:
- name: restart nxx service
...

ansible to restart network service

I copy-pasted this from the manual and it fails in my playbook (version 2.0.2):
- service: name=network state=restarted args=eth0
I am getting this error:
"msg": "Failed to stop eth0.service: Unit eth0.service not loaded.\nFailed to start eth0.service: Unit eth0.service failed to load: No such file or directory.\n"}
What is the correct syntax, please?
Just do like this (#nasr already commented it):
- name: Restart network
service:
name: network
state: restarted
But if you change network configuration before restart, something like IP address, after restart ansible hangs because connection is lost (IP address changed).
There is a way to do things right.
tasks.yml
- name: net configuration step 1
debug:
msg: we changed some files
notify: restart systemd-networkd
- name: net configuration step 2
debug:
msg: do some more work, but restart net services only once
notify: restart systemd-networkd
handlers.yml
- name: restart systemd-networkd
systemd:
name: systemd-networkd
state: restarted
async: 120
poll: 0
register: net_restarting
- name: check restart systemd-networkd status
async_status:
jid: "{{ net_restarting.ansible_job_id }}"
register: async_poll_results
until: async_poll_results.finished
retries: 30
listen: restart systemd-networkd
As per Ansible 2.7.8. You have to make following changes to restart the network.
Note: I tried this on Ubuntu 16.04
Scenario 1: Only network restart
- name: Restarting Network to take effect new IP Address
become: yes
service:
name: networking
state: restarted
Scenario 2: Flush interface and then restart network
- name: Flushing Interface
become: yes
shell: sudo ip addr flush "{{net_interface}}"
- name: Restarting Network
become: yes
service:
name: networking
state: restarted
Note: Make sure you have net_interface configured and then imported in the file where you execute this Ansible task.
OUTPUT
Please find below output that I received on my screen.
- command: /etc/init.d/network restart
does work wonderfully but I feel that using command kinda defeats the purpose of using ansible.
I m using Ubuntu 22.04.1 LTS that uses systemd instead of init
The following worked fine with me ( I tried the solutions mentioned earlier but none has worked for me)
- name: restart network
systemd:
name: NetworkManager
state: restarted

How to run command after error occurs in ansible handler

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'

Using Ansible to stop service that might not exist

I am using Ansible 2.6.1.
I am trying to ensure that certain service is not running on target hosts.
Problem is that the service might not exist at all on some hosts. If this is the case Ansible fails with error because of missing service. Services are run by Systemd.
Using service module:
- name: Stop service
service:
name: '{{ target_service }}'
state: stopped
Fails with error Could not find the requested service SERVICE: host
Trying with command module:
- name: Stop service
command: service {{ target_service }} stop
Gives error: Failed to stop SERVICE.service: Unit SERVICE.service not loaded.
I know I could use ignore_errors: yes but it might hide real errors too.
An other solution would be having 2 tasks. One checking for existance of service and other that is run only when first task found service but feels complex.
Is there simpler way to ensure that service is stopped and avoid errors if the service does not exists?
I'm using the following steps:
- name: Get the list of services
service_facts:
- name: Stop service
systemd:
name: <service_name_here>
state: stopped
when: "'<service_name_here>.service' in services"
service_facts could be called once in the gathering facts phase.
The following will register the module output in service_stop; if the module execution's standard output does not contain "Could not find the requested service" AND the service fails to stop based on return code, the module execution will fail. Since you did not include the entire stack trace I am assuming the error you posted is in the standard output, you may need to change slightly based on your error.
- name: Stop service
register: service_stop
failed_when:
- '"Could not find the requested service" not in service_stop.stdout'
- service_stop.rc != 0
service:
name: '{{ target_service }}'
state: stopped
IMHO there isn't simpler way to ensure that service is stopped. Ansible service module doesn't check service's existence. Either (1) more then one task, or (2) command that check service's existence is needed. The command would be OS specific. For example for FreeBSD
command: "service -e | grep {{ target_service }} && service {{ target_service }} stop"
Same solution as Vladimir's, but for Ubuntu (systemd) and with better state handling:
- name: restart {{ target_service }} if exists
shell: if systemctl is-enabled --quiet {{ target_service }}; then systemctl restart {{ target_service }} && echo restarted ; fi
register: output
changed_when: "'restarted' in output.stdout"
It produces 3 states:
service is absent or disabled — ok
service exists and was restarted — changed
service exists and restart failed — failed
Same solution as #ToughKernel's but use systemd to manage service.
- name: disable ntpd service
systemd:
name: ntpd
enabled: no
state: stopped
register: stop_service
failed_when:
- stop_service.failed == true
- '"Could not find the requested service" not in stop_service.msg'
# the order is important, only failed == true, there will be
# attribute 'msg' in the result
When the service module fails, check if the service that needs to be stopped is installed at all. That is similar to this answer, but avoids the rather lengthy gathering of service facts unless necessary.
- name: Stop a service
block:
- name: Attempt to stop the service
service:
name: < service name >
state: stopped
rescue:
- name: Get the list of services
service_facts:
- name: Verify that Nagios is not installed
assert:
that:
- "'< service name >.service' not in services"

Resources