|
|
@ -1,38 +1,34 @@
|
|
|
|
#!/usr/bin/python
|
|
|
|
#!/usr/bin/python
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
|
|
|
|
# (c) 2012, Michael DeHaan <michael.dehaan@gmail.com>
|
|
|
|
# Copyright: (c) 2012, Michael DeHaan <michael.dehaan@gmail.com>
|
|
|
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
|
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
|
|
|
|
|
|
|
|
|
|
from __future__ import absolute_import, division, print_function
|
|
|
|
from __future__ import absolute_import, division, print_function
|
|
|
|
__metaclass__ = type
|
|
|
|
__metaclass__ = type
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
|
|
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
|
|
|
'status': ['stableinterface'],
|
|
|
|
'status': ['stableinterface'],
|
|
|
|
'supported_by': 'core'}
|
|
|
|
'supported_by': 'core'}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DOCUMENTATION = '''
|
|
|
|
DOCUMENTATION = '''
|
|
|
|
---
|
|
|
|
---
|
|
|
|
module: service
|
|
|
|
module: service
|
|
|
|
author:
|
|
|
|
author:
|
|
|
|
- "Ansible Core Team"
|
|
|
|
- Ansible Core Team
|
|
|
|
- "Michael DeHaan"
|
|
|
|
- Michael DeHaan
|
|
|
|
version_added: "0.1"
|
|
|
|
version_added: "0.1"
|
|
|
|
short_description: Manage services.
|
|
|
|
short_description: Manage services
|
|
|
|
description:
|
|
|
|
description:
|
|
|
|
- Controls services on remote hosts. Supported init systems include BSD init,
|
|
|
|
- Controls services on remote hosts. Supported init systems include BSD init,
|
|
|
|
OpenRC, SysV, Solaris SMF, systemd, upstart.
|
|
|
|
OpenRC, SysV, Solaris SMF, systemd, upstart.
|
|
|
|
- For Windows targets, use the M(win_service) module instead.
|
|
|
|
- For Windows targets, use the M(win_service) module instead.
|
|
|
|
options:
|
|
|
|
options:
|
|
|
|
name:
|
|
|
|
name:
|
|
|
|
required: true
|
|
|
|
|
|
|
|
description:
|
|
|
|
description:
|
|
|
|
- Name of the service.
|
|
|
|
- Name of the service.
|
|
|
|
|
|
|
|
required: true
|
|
|
|
state:
|
|
|
|
state:
|
|
|
|
required: false
|
|
|
|
|
|
|
|
choices: [ started, stopped, restarted, reloaded ]
|
|
|
|
|
|
|
|
description:
|
|
|
|
description:
|
|
|
|
- C(started)/C(stopped) are idempotent actions that will not run
|
|
|
|
- C(started)/C(stopped) are idempotent actions that will not run
|
|
|
|
commands unless necessary. C(restarted) will always bounce the
|
|
|
|
commands unless necessary. C(restarted) will always bounce the
|
|
|
@ -40,86 +36,81 @@ options:
|
|
|
|
and enabled are required.) Note that reloaded will start the
|
|
|
|
and enabled are required.) Note that reloaded will start the
|
|
|
|
service if it is not already started, even if your chosen init
|
|
|
|
service if it is not already started, even if your chosen init
|
|
|
|
system wouldn't normally.
|
|
|
|
system wouldn't normally.
|
|
|
|
|
|
|
|
choices: [ reloaded, restarted, running, started, stopped ]
|
|
|
|
sleep:
|
|
|
|
sleep:
|
|
|
|
required: false
|
|
|
|
|
|
|
|
version_added: "1.3"
|
|
|
|
|
|
|
|
description:
|
|
|
|
description:
|
|
|
|
- If the service is being C(restarted) then sleep this many seconds
|
|
|
|
- If the service is being C(restarted) then sleep this many seconds
|
|
|
|
between the stop and start command. This helps to workaround badly
|
|
|
|
between the stop and start command. This helps to workaround badly
|
|
|
|
behaving init scripts that exit immediately after signaling a process
|
|
|
|
behaving init scripts that exit immediately after signaling a process
|
|
|
|
to stop.
|
|
|
|
to stop.
|
|
|
|
|
|
|
|
version_added: "1.3"
|
|
|
|
pattern:
|
|
|
|
pattern:
|
|
|
|
required: false
|
|
|
|
|
|
|
|
version_added: "0.7"
|
|
|
|
|
|
|
|
description:
|
|
|
|
description:
|
|
|
|
- If the service does not respond to the status command, name a
|
|
|
|
- If the service does not respond to the status command, name a
|
|
|
|
substring to look for as would be found in the output of the I(ps)
|
|
|
|
substring to look for as would be found in the output of the I(ps)
|
|
|
|
command as a stand-in for a status result. If the string is found,
|
|
|
|
command as a stand-in for a status result. If the string is found,
|
|
|
|
the service will be assumed to be running.
|
|
|
|
the service will be assumed to be running.
|
|
|
|
|
|
|
|
version_added: "0.7"
|
|
|
|
enabled:
|
|
|
|
enabled:
|
|
|
|
required: false
|
|
|
|
|
|
|
|
choices: [ "yes", "no" ]
|
|
|
|
|
|
|
|
description:
|
|
|
|
description:
|
|
|
|
- Whether the service should start on boot. B(At least one of state and
|
|
|
|
- Whether the service should start on boot. B(At least one of state and
|
|
|
|
enabled are required.)
|
|
|
|
enabled are required.)
|
|
|
|
|
|
|
|
type: bool
|
|
|
|
runlevel:
|
|
|
|
runlevel:
|
|
|
|
required: false
|
|
|
|
|
|
|
|
default: 'default'
|
|
|
|
|
|
|
|
description:
|
|
|
|
description:
|
|
|
|
- "For OpenRC init scripts (ex: Gentoo) only. The runlevel that this service belongs to."
|
|
|
|
- "For OpenRC init scripts (ex: Gentoo) only. The runlevel that this service belongs to."
|
|
|
|
|
|
|
|
default: default
|
|
|
|
arguments:
|
|
|
|
arguments:
|
|
|
|
description:
|
|
|
|
description:
|
|
|
|
- Additional arguments provided on the command line
|
|
|
|
- Additional arguments provided on the command line
|
|
|
|
aliases: [ 'args' ]
|
|
|
|
aliases: [ args ]
|
|
|
|
use:
|
|
|
|
use:
|
|
|
|
description:
|
|
|
|
description:
|
|
|
|
- The service module actually uses system specific modules, normally through auto detection, this setting can force a specific module.
|
|
|
|
- The service module actually uses system specific modules, normally through auto detection, this setting can force a specific module.
|
|
|
|
- Normally it uses the value of the 'ansible_service_mgr' fact and falls back to the old 'service' module when none matching is found.
|
|
|
|
- Normally it uses the value of the 'ansible_service_mgr' fact and falls back to the old 'service' module when none matching is found.
|
|
|
|
default: 'auto'
|
|
|
|
default: auto
|
|
|
|
version_added: 2.2
|
|
|
|
version_added: 2.2
|
|
|
|
notes:
|
|
|
|
notes:
|
|
|
|
- For Windows targets, use the M(win_service) module instead.
|
|
|
|
- For Windows targets, use the M(win_service) module instead.
|
|
|
|
'''
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
EXAMPLES = '''
|
|
|
|
EXAMPLES = '''
|
|
|
|
# Example action to start service httpd, if not running
|
|
|
|
- name: Start service httpd, if not running
|
|
|
|
- service:
|
|
|
|
service:
|
|
|
|
name: httpd
|
|
|
|
name: httpd
|
|
|
|
state: started
|
|
|
|
state: started
|
|
|
|
|
|
|
|
|
|
|
|
# Example action to stop service httpd, if running
|
|
|
|
- name: Stop service httpd, if running
|
|
|
|
- service:
|
|
|
|
service:
|
|
|
|
name: httpd
|
|
|
|
name: httpd
|
|
|
|
state: stopped
|
|
|
|
state: stopped
|
|
|
|
|
|
|
|
|
|
|
|
# Example action to restart service httpd, in all cases
|
|
|
|
- name: Restart service httpd, in all cases
|
|
|
|
- service:
|
|
|
|
service:
|
|
|
|
name: httpd
|
|
|
|
name: httpd
|
|
|
|
state: restarted
|
|
|
|
state: restarted
|
|
|
|
|
|
|
|
|
|
|
|
# Example action to reload service httpd, in all cases
|
|
|
|
- name: Reload service httpd, in all cases
|
|
|
|
- service:
|
|
|
|
service:
|
|
|
|
name: httpd
|
|
|
|
name: httpd
|
|
|
|
state: reloaded
|
|
|
|
state: reloaded
|
|
|
|
|
|
|
|
|
|
|
|
# Example action to enable service httpd, and not touch the running state
|
|
|
|
- name: Enable service httpd, and not touch the running state
|
|
|
|
- service:
|
|
|
|
service:
|
|
|
|
name: httpd
|
|
|
|
name: httpd
|
|
|
|
enabled: yes
|
|
|
|
enabled: yes
|
|
|
|
|
|
|
|
|
|
|
|
# Example action to start service foo, based on running process /usr/bin/foo
|
|
|
|
- name: Start service foo, based on running process /usr/bin/foo
|
|
|
|
- service:
|
|
|
|
service:
|
|
|
|
name: foo
|
|
|
|
name: foo
|
|
|
|
pattern: /usr/bin/foo
|
|
|
|
pattern: /usr/bin/foo
|
|
|
|
state: started
|
|
|
|
state: started
|
|
|
|
|
|
|
|
|
|
|
|
# Example action to restart network service for interface eth0
|
|
|
|
- name: Restart network service for interface eth0
|
|
|
|
- service:
|
|
|
|
service:
|
|
|
|
name: network
|
|
|
|
name: network
|
|
|
|
state: restarted
|
|
|
|
state: restarted
|
|
|
|
args: eth0
|
|
|
|
args: eth0
|
|
|
|
|
|
|
|
|
|
|
|
'''
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
|
|
import glob
|
|
|
|
import glob
|
|
|
@ -314,7 +305,7 @@ class Service(object):
|
|
|
|
self.running = False
|
|
|
|
self.running = False
|
|
|
|
lines = psout.split("\n")
|
|
|
|
lines = psout.split("\n")
|
|
|
|
for line in lines:
|
|
|
|
for line in lines:
|
|
|
|
if self.pattern in line and not "pattern=" in line:
|
|
|
|
if self.pattern in line and "pattern=" not in line:
|
|
|
|
# so as to not confuse ./hacking/test-module
|
|
|
|
# so as to not confuse ./hacking/test-module
|
|
|
|
self.running = True
|
|
|
|
self.running = True
|
|
|
|
break
|
|
|
|
break
|
|
|
@ -323,9 +314,9 @@ class Service(object):
|
|
|
|
if self.state and self.running is None:
|
|
|
|
if self.state and self.running is None:
|
|
|
|
self.module.fail_json(msg="failed determining service state, possible typo of service name?")
|
|
|
|
self.module.fail_json(msg="failed determining service state, possible typo of service name?")
|
|
|
|
# Find out if state has changed
|
|
|
|
# Find out if state has changed
|
|
|
|
if not self.running and self.state in ["started", "running", "reloaded"]:
|
|
|
|
if not self.running and self.state in ["reloaded", "running", "started"]:
|
|
|
|
self.svc_change = True
|
|
|
|
self.svc_change = True
|
|
|
|
elif self.running and self.state in ["stopped","reloaded"]:
|
|
|
|
elif self.running and self.state in ["reloaded", "stopped"]:
|
|
|
|
self.svc_change = True
|
|
|
|
self.svc_change = True
|
|
|
|
elif self.state == "restarted":
|
|
|
|
elif self.state == "restarted":
|
|
|
|
self.svc_change = True
|
|
|
|
self.svc_change = True
|
|
|
@ -337,7 +328,7 @@ class Service(object):
|
|
|
|
# Only do something if state will change
|
|
|
|
# Only do something if state will change
|
|
|
|
if self.svc_change:
|
|
|
|
if self.svc_change:
|
|
|
|
# Control service
|
|
|
|
# Control service
|
|
|
|
if self.state in ['started', 'running']:
|
|
|
|
if self.state in ['running', 'started']:
|
|
|
|
self.action = "start"
|
|
|
|
self.action = "start"
|
|
|
|
elif not self.running and self.state == 'reloaded':
|
|
|
|
elif not self.running and self.state == 'reloaded':
|
|
|
|
self.action = "start"
|
|
|
|
self.action = "start"
|
|
|
@ -417,8 +408,6 @@ class Service(object):
|
|
|
|
# Replace previous rc.conf.
|
|
|
|
# Replace previous rc.conf.
|
|
|
|
self.module.atomic_move(tmp_rcconf_file, self.rcconf_file)
|
|
|
|
self.module.atomic_move(tmp_rcconf_file, self.rcconf_file)
|
|
|
|
|
|
|
|
|
|
|
|
# ===========================================
|
|
|
|
|
|
|
|
# Subclass: Linux
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class LinuxService(Service):
|
|
|
|
class LinuxService(Service):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
@ -664,7 +653,6 @@ class LinuxService(Service):
|
|
|
|
|
|
|
|
|
|
|
|
return self.running
|
|
|
|
return self.running
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def service_enable(self):
|
|
|
|
def service_enable(self):
|
|
|
|
|
|
|
|
|
|
|
|
if self.enable_cmd is None:
|
|
|
|
if self.enable_cmd is None:
|
|
|
@ -746,7 +734,7 @@ class LinuxService(Service):
|
|
|
|
if 'chkconfig --add %s' % self.name in err:
|
|
|
|
if 'chkconfig --add %s' % self.name in err:
|
|
|
|
self.execute_command("%s --add %s" % (self.enable_cmd, self.name))
|
|
|
|
self.execute_command("%s --add %s" % (self.enable_cmd, self.name))
|
|
|
|
(rc, out, err) = self.execute_command("%s --list %s" % (self.enable_cmd, self.name))
|
|
|
|
(rc, out, err) = self.execute_command("%s --list %s" % (self.enable_cmd, self.name))
|
|
|
|
if not self.name in out:
|
|
|
|
if self.name not in out:
|
|
|
|
self.module.fail_json(msg="service %s does not support chkconfig" % self.name)
|
|
|
|
self.module.fail_json(msg="service %s does not support chkconfig" % self.name)
|
|
|
|
# TODO: look back on why this is here
|
|
|
|
# TODO: look back on why this is here
|
|
|
|
# state = out.split()[-1]
|
|
|
|
# state = out.split()[-1]
|
|
|
@ -905,7 +893,6 @@ class LinuxService(Service):
|
|
|
|
|
|
|
|
|
|
|
|
return (rc, out, err)
|
|
|
|
return (rc, out, err)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def service_control(self):
|
|
|
|
def service_control(self):
|
|
|
|
|
|
|
|
|
|
|
|
# Decide what command to run
|
|
|
|
# Decide what command to run
|
|
|
@ -974,8 +961,6 @@ class LinuxService(Service):
|
|
|
|
|
|
|
|
|
|
|
|
return(rc_state, stdout, stderr)
|
|
|
|
return(rc_state, stdout, stderr)
|
|
|
|
|
|
|
|
|
|
|
|
# ===========================================
|
|
|
|
|
|
|
|
# Subclass: FreeBSD
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class FreeBsdService(Service):
|
|
|
|
class FreeBsdService(Service):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
@ -1071,7 +1056,6 @@ class FreeBsdService(Service):
|
|
|
|
except Exception:
|
|
|
|
except Exception:
|
|
|
|
self.module.fail_json(msg='unable to set rcvar')
|
|
|
|
self.module.fail_json(msg='unable to set rcvar')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def service_control(self):
|
|
|
|
def service_control(self):
|
|
|
|
|
|
|
|
|
|
|
|
if self.action == "start":
|
|
|
|
if self.action == "start":
|
|
|
@ -1088,8 +1072,6 @@ class FreeBsdService(Service):
|
|
|
|
|
|
|
|
|
|
|
|
return ret
|
|
|
|
return ret
|
|
|
|
|
|
|
|
|
|
|
|
# ===========================================
|
|
|
|
|
|
|
|
# Subclass: OpenBSD
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class OpenBsdService(Service):
|
|
|
|
class OpenBsdService(Service):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
@ -1239,8 +1221,6 @@ class OpenBsdService(Service):
|
|
|
|
|
|
|
|
|
|
|
|
self.changed = True
|
|
|
|
self.changed = True
|
|
|
|
|
|
|
|
|
|
|
|
# ===========================================
|
|
|
|
|
|
|
|
# Subclass: NetBSD
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class NetBsdService(Service):
|
|
|
|
class NetBsdService(Service):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
@ -1297,8 +1277,7 @@ class NetBsdService(Service):
|
|
|
|
self.svc_cmd = "%s" % self.svc_initscript
|
|
|
|
self.svc_cmd = "%s" % self.svc_initscript
|
|
|
|
return self.execute_command("%s %s" % (self.svc_cmd, self.action), daemonize=True)
|
|
|
|
return self.execute_command("%s %s" % (self.svc_cmd, self.action), daemonize=True)
|
|
|
|
|
|
|
|
|
|
|
|
# ===========================================
|
|
|
|
|
|
|
|
# Subclass: SunOS
|
|
|
|
|
|
|
|
class SunOSService(Service):
|
|
|
|
class SunOSService(Service):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
This is the SunOS Service manipulation class - it uses the svcadm
|
|
|
|
This is the SunOS Service manipulation class - it uses the svcadm
|
|
|
@ -1406,7 +1385,6 @@ class SunOSService(Service):
|
|
|
|
|
|
|
|
|
|
|
|
self.changed = True
|
|
|
|
self.changed = True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def service_control(self):
|
|
|
|
def service_control(self):
|
|
|
|
status = self.get_sunos_svcs_status()
|
|
|
|
status = self.get_sunos_svcs_status()
|
|
|
|
|
|
|
|
|
|
|
@ -1433,8 +1411,6 @@ class SunOSService(Service):
|
|
|
|
|
|
|
|
|
|
|
|
return self.execute_command("%s %s %s" % (self.svcadm_cmd, subcmd, self.name))
|
|
|
|
return self.execute_command("%s %s %s" % (self.svcadm_cmd, subcmd, self.name))
|
|
|
|
|
|
|
|
|
|
|
|
# ===========================================
|
|
|
|
|
|
|
|
# Subclass: AIX
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AIX(Service):
|
|
|
|
class AIX(Service):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
@ -1468,7 +1444,6 @@ class AIX(Service):
|
|
|
|
if not self.refresh_cmd:
|
|
|
|
if not self.refresh_cmd:
|
|
|
|
self.module.fail_json(msg='unable to find refresh binary')
|
|
|
|
self.module.fail_json(msg='unable to find refresh binary')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_service_status(self):
|
|
|
|
def get_service_status(self):
|
|
|
|
status = self.get_aix_src_status()
|
|
|
|
status = self.get_aix_src_status()
|
|
|
|
# Only 'active' is considered properly running. Everything else is off
|
|
|
|
# Only 'active' is considered properly running. Everything else is off
|
|
|
@ -1514,13 +1489,13 @@ class AIX(Service):
|
|
|
|
def main():
|
|
|
|
def main():
|
|
|
|
module = AnsibleModule(
|
|
|
|
module = AnsibleModule(
|
|
|
|
argument_spec=dict(
|
|
|
|
argument_spec=dict(
|
|
|
|
name = dict(required=True),
|
|
|
|
name=dict(type='str', required=True),
|
|
|
|
state = dict(choices=['running', 'started', 'stopped', 'restarted', 'reloaded']),
|
|
|
|
state=dict(type='str', choices=['running', 'started', 'stopped', 'reloaded', 'restarted']),
|
|
|
|
sleep = dict(required=False, type='int', default=None),
|
|
|
|
sleep=dict(type='int'),
|
|
|
|
pattern = dict(required=False, default=None),
|
|
|
|
pattern=dict(type='str'),
|
|
|
|
enabled=dict(type='bool'),
|
|
|
|
enabled=dict(type='bool'),
|
|
|
|
runlevel = dict(required=False, default='default'),
|
|
|
|
runlevel=dict(type='str', default='default'),
|
|
|
|
arguments = dict(aliases=['args'], default=''),
|
|
|
|
arguments=dict(type='str', default='', aliases=['args']),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
supports_check_mode=True,
|
|
|
|
supports_check_mode=True,
|
|
|
|
required_one_of=[['state', 'enabled']],
|
|
|
|
required_one_of=[['state', 'enabled']],
|
|
|
@ -1594,12 +1569,13 @@ def main():
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
# as we may have just bounced the service the service command may not
|
|
|
|
# as we may have just bounced the service the service command may not
|
|
|
|
# report accurate state at this moment so just show what we ran
|
|
|
|
# report accurate state at this moment so just show what we ran
|
|
|
|
if service.module.params['state'] in ['started','restarted','running','reloaded']:
|
|
|
|
if service.module.params['state'] in ['reloaded', 'restarted', 'running', 'started']:
|
|
|
|
result['state'] = 'started'
|
|
|
|
result['state'] = 'started'
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
result['state'] = 'stopped'
|
|
|
|
result['state'] = 'stopped'
|
|
|
|
|
|
|
|
|
|
|
|
module.exit_json(**result)
|
|
|
|
module.exit_json(**result)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|
|
|
|
main()
|
|
|
|