ca8002d7c5
Checks if update-rc.d (Ubuntu) or chkconfig (RHEL) should be used. Adds basic bin path search for those binaries Adds 'enable' and 'disable' options for 'enable' command since it's the arguments that update-rc.d uses (this might be somewhat confusing to have a command line with 'enable=enable', but probably mkes sense for Ubuntu users). Allows use of mixed case for 'list' and 'state' commands.
231 lines
6.7 KiB
Python
Executable file
231 lines
6.7 KiB
Python
Executable file
#!/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/>.
|
|
|
|
try:
|
|
import json
|
|
except ImportError:
|
|
import simplejson as json
|
|
import sys
|
|
import shlex
|
|
import subprocess
|
|
import os.path
|
|
|
|
# TODO: switch to fail_json and other helper functions
|
|
# like other modules are using
|
|
|
|
# ===========================================
|
|
|
|
SERVICE = None
|
|
CHKCONFIG = None
|
|
|
|
def fail_json(d):
|
|
print json.dumps(d)
|
|
sys.exit(1)
|
|
|
|
def _find_binaries():
|
|
# list of possible paths for service/chkconfig binaries
|
|
# with the most probable first
|
|
paths = ['/sbin', '/usr/sbin', '/bin', '/usr/bin']
|
|
binaries = [ 'service', 'chkconfig', 'update-rc.d' ]
|
|
location = dict()
|
|
|
|
for binary in binaries:
|
|
location[binary] = None
|
|
|
|
for path in paths:
|
|
for binary in binaries:
|
|
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:
|
|
fail_json(dict(failed=True, msg='unable to find chkconfig or update-rc.d binary'))
|
|
|
|
if location.get('service', None):
|
|
SERVICE = location['service']
|
|
else:
|
|
fail_json(dict(failed=True, msg='unable to find service binary'))
|
|
|
|
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
|
|
|
|
argfile = sys.argv[1]
|
|
args = open(argfile, 'r').read()
|
|
items = shlex.split(args)
|
|
|
|
if not len(items):
|
|
fail_json(dict(failed=True, msg='this module requires arguments (-a)'))
|
|
|
|
params = {}
|
|
for arg in items:
|
|
if "=" not in arg:
|
|
fail_json(dict(failed=True, msg='expected key=value format arguments'))
|
|
|
|
(name, value) = arg.split("=")
|
|
params[name] = value
|
|
|
|
name = params.get('name', None)
|
|
|
|
if name is None:
|
|
fail_json(dict(failed=True, msg='missing name'))
|
|
|
|
state = params.get('state', None)
|
|
list_items = params.get('list', None)
|
|
enable = params.get('enable', None)
|
|
|
|
# running and started are the same
|
|
if state and state.lower() not in [ 'running', 'started', 'stopped', 'restarted' ]:
|
|
fail_json(dict(failed=True, msg='invalid value for state'))
|
|
if list_items and list_items.lower() not in [ 'status' ]:
|
|
fail_json(dict(failed=True, msg='invalid value for list'))
|
|
if enable and enable.lower() not in [ 'on', 'off', 'true', 'false', 'yes', 'no', 'enable', 'disable' ]:
|
|
fail_json(dict(failed=True, msg='invalid value for enable'))
|
|
|
|
|
|
# ===========================================
|
|
# find binaries locations on minion
|
|
_find_binaries()
|
|
|
|
|
|
# ===========================================
|
|
# get service status
|
|
|
|
rc, status_stdout, status_stderr = _run("%s %s status" % (SERVICE, name))
|
|
status = status_stdout + status_stderr
|
|
|
|
|
|
running = False
|
|
if status_stdout.find("not running") != -1:
|
|
running = False
|
|
elif status_stdout.find("running") != -1:
|
|
running = True
|
|
elif 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
|
|
|
|
if state or enable:
|
|
rc = 0
|
|
out = ''
|
|
err = ''
|
|
changed = False
|
|
|
|
if enable:
|
|
rc_enable, out_enable, err_enable = _do_enable(name, enable)
|
|
rc += rc_enable
|
|
out += out_enable
|
|
err += err_enable
|
|
|
|
if state:
|
|
# a state change command has been requested
|
|
|
|
# ===========================================
|
|
# determine if we are going to change anything
|
|
|
|
if not running and state == "started":
|
|
changed = True
|
|
elif running and state == "stopped":
|
|
changed = True
|
|
elif state == "restarted":
|
|
changed = True
|
|
|
|
# ===========================================
|
|
# run change commands if we need to
|
|
|
|
if changed:
|
|
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))
|
|
elif state == 'restarted':
|
|
rc1, stdout1, stderr1 = _run("%s %s stop" % (SERVICE, name))
|
|
rc2, stdout2, stderr2 = _run("%s %s start" % (SERVICE, name))
|
|
rc_state = rc and rc1 and rc2
|
|
stdout = stdout1 + stdout2
|
|
stderr = stderr1 + stderr2
|
|
|
|
out += stdout
|
|
err += stderr
|
|
rc = rc and rc_state
|
|
|
|
if rc != 0:
|
|
|
|
print json.dumps({
|
|
"failed" : 1,
|
|
"rc" : rc,
|
|
})
|
|
print >> sys.stderr, out + err
|
|
sys.exit(1)
|
|
|
|
|
|
# ===============================================
|
|
# success
|
|
|
|
result = {"changed": changed}
|
|
|
|
rc, stdout, stderr = _run("%s %s status" % (SERVICE, name))
|
|
if list_items and list_items in [ 'status' ]:
|
|
result['status'] = stdout
|
|
print json.dumps(result)
|
|
|
|
|
|
elif list_items is not None:
|
|
|
|
# solo list=status mode, don't change anything, just return
|
|
# suitable for /usr/bin/ansible usage or API, playbooks
|
|
# not so much
|
|
|
|
print json.dumps({
|
|
"status" : status
|
|
})
|
|
|
|
else:
|
|
|
|
print json.dumps(dict(failed=True, msg="expected state or list parameters"))
|
|
|
|
|
|
sys.exit(0)
|
|
|