ansible/library/service

216 lines
7.4 KiB
Text
Raw Normal View History

#!/usr/bin/python
# (c) 2012, Michael DeHaan <michael.dehaan@gmail.com>
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
SERVICE = None
CHKCONFIG = None
2012-07-30 11:18:24 +02:00
def _find_binaries(m):
# list of possible paths for service/chkconfig binaries
# with the most probable first
global CHKCONFIG
global SERVICE
global INITCTL
paths = ['/sbin', '/usr/sbin', '/bin', '/usr/bin']
binaries = [ 'service', 'chkconfig', 'update-rc.d', 'initctl']
location = dict()
for binary in binaries:
location[binary] = None
for binary in binaries:
for path in paths:
if os.path.exists(path + '/' + binary):
location[binary] = path + '/' + binary
break
if location.get('chkconfig', None):
CHKCONFIG = location['chkconfig']
elif location.get('update-rc.d', None):
CHKCONFIG = location['update-rc.d']
else:
2012-07-30 11:18:24 +02:00
m.fail_json(msg='unable to find chkconfig or update-rc.d binary')
if location.get('service', None):
SERVICE = location['service']
else:
2012-07-30 11:18:24 +02:00
m.fail_json(msg='unable to find service binary')
if location.get('initctl', None):
INITCTL = location['initctl']
else:
INITCTL = None
def _get_service_status(name):
rc, status_stdout, status_stderr = _run("%s %s status" % (SERVICE, name))
# set the running state to None because we don't know it yet
running = None
# Check if we got upstart on the system and then the job state
if INITCTL != None:
# check the job status by upstart response
initctl_rc, initctl_status_stdout, initctl_status_stderr = _run("%s status %s" % (INITCTL, name))
if initctl_status_stdout.find("stop/waiting") != -1:
running = False
elif initctl_status_stdout.find("start/running") != -1:
running = True
# if the job status is still not known check it by response code
if running == None:
if rc == 3:
running = False
elif rc == 0:
running = True
# if the job status is still not known check it by status output keywords
if running == None:
# first tranform the status output that could irritate keyword matching
cleanout = status_stdout.lower().replace(name.lower(), '')
if "stop" in cleanout:
running = False
elif "run" in cleanout and "not" in cleanout:
running = False
elif "run" in cleanout and "not" not in cleanout:
running = True
elif "start" in cleanout and "not" not in cleanout:
running = True
elif 'could not access pid file' in cleanout:
running = False
elif 'is dead and pid file exists' in cleanout:
running = False
# if the job status is still not known check it by special conditions
if running == None:
if name == 'iptables' and status_stdout.find("ACCEPT") != -1:
# iptables status command output is lame
# TODO: lookup if we can use a return code for this instead?
running = True
return running
def _run(cmd):
# returns (rc, stdout, stderr) from shell command
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
stdout, stderr = process.communicate()
return (process.returncode, stdout, stderr)
def _do_enable(name, enable):
# we change argument depending on real binary used
# update-rc.d wants enable/disable while
# chkconfig wants on/off
valid_argument = dict({'on' : 'on', 'off' : 'off'})
if CHKCONFIG.endswith("update-rc.d"):
valid_argument['on'] = "enable"
valid_argument['off'] = "disable"
if enable.lower() in ['on', 'true', 'yes', 'enable']:
rc, stdout, stderr = _run("%s %s %s" % (CHKCONFIG, name, valid_argument['on']))
elif enable.lower() in ['off', 'false', 'no', 'disable']:
rc, stdout, stderr = _run("%s %s %s" % (CHKCONFIG, name, valid_argument['off']))
return rc, stdout, stderr
2012-07-30 11:18:24 +02:00
def main():
module = AnsibleModule(
argument_spec = dict(
name = dict(required=True),
state = dict(choices=['running', 'started', 'stopped', 'restarted', 'reloaded']),
list_items = dict(choices=['status']),
enable = dict(choices=['on', 'off', 'true', 'false', 'yes', 'no', 'enable', 'disable', 'none'])
)
)
p = module.params
name = p['name']
state = p.get('state', None)
list_items = p.get('list_items', None)
enable = p.get('enable', None)
# ===========================================
# find binaries locations on minion
_find_binaries(module)
2012-07-30 11:18:24 +02:00
# ===========================================
# get service status
running = _get_service_status(name)
2012-07-30 11:18:24 +02:00
# ===========================================
# Some common variables
changed = False
rc = 0
err = ''
2012-07-30 11:18:24 +02:00
out = ''
if enable:
rc_enable, out_enable, err_enable = _do_enable(name, enable)
rc += rc_enable
out += out_enable
err += err_enable
if state and running == None:
2012-07-30 11:18:24 +02:00
module.fail_json(msg="failed determining the current service state => state stays unchanged", changed=False)
elif state:
# a state change command has been requested
# ===========================================
# determine if we are going to change anything
2012-07-30 11:18:24 +02:00
if not running and state in ["started", "running"]:
changed = True
2012-07-30 11:18:24 +02:00
elif running and state in ["stopped","reloaded"]:
changed = True
elif state == "restarted":
changed = True
# ===========================================
# run change commands if we need to
if changed:
2012-07-30 11:18:24 +02:00
if state in ['started', 'running']:
rc_state, stdout, stderr = _run("%s %s start" % (SERVICE, name))
elif state == 'stopped':
rc_state, stdout, stderr = _run("%s %s stop" % (SERVICE, name))
2012-05-15 11:28:49 +02:00
elif state == 'reloaded':
rc_state, stdout, stderr = _run("%s %s reload" % (SERVICE, name))
elif state == 'restarted':
rc1, stdout1, stderr1 = _run("%s %s stop" % (SERVICE, name))
rc2, stdout2, stderr2 = _run("%s %s start" % (SERVICE, name))
rc_state = rc + rc1 + rc2
stdout = stdout1 + stdout2
stderr = stderr1 + stderr2
out += stdout
err += stderr
rc = rc + rc_state
if rc != 0:
2012-07-30 11:18:24 +02:00
module.fail_json(msg=err)
result = {"changed": changed}
rc, stdout, stderr = _run("%s %s status" % (SERVICE, name))
2012-07-30 11:18:24 +02:00
if list_items == 'status':
result['status'] = stdout
2012-07-30 11:18:24 +02:00
module.exit_json(**result);
2012-07-30 11:18:24 +02:00
# this is magic, see lib/ansible/module_common.py
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
2012-07-30 11:18:24 +02:00
main()