mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
removed unused code, added comment explaining
files is really a placeholder for common code for separate service modules, was copy of current service module and this seemed to confuse people so this update should clear that up
This commit is contained in:
parent
1c7890bf86
commit
38b975800d
1 changed files with 2 additions and 195 deletions
|
@ -4,7 +4,7 @@
|
||||||
# still belong to the author of the module, and may assign their own license
|
# still belong to the author of the module, and may assign their own license
|
||||||
# to the complete work.
|
# to the complete work.
|
||||||
#
|
#
|
||||||
# Copyright (c) Ansible Inc, 2015
|
# Copyright (c) Ansible Inc, 2016
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
# Redistribution and use in source and binary forms, with or without modification,
|
# Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
@ -27,197 +27,4 @@
|
||||||
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#
|
#
|
||||||
|
|
||||||
import platform
|
# This file is a placeholder for common code for the future split 'service' modules.
|
||||||
import os
|
|
||||||
import shlex
|
|
||||||
import select
|
|
||||||
import subprocess
|
|
||||||
import json
|
|
||||||
|
|
||||||
from ansible.module_utils.six import text_type, binary_type
|
|
||||||
|
|
||||||
class Service(object):
|
|
||||||
"""
|
|
||||||
This is the generic Service manipulation class that is subclassed based on system.
|
|
||||||
A subclass should override the following methods:
|
|
||||||
- action
|
|
||||||
- enable
|
|
||||||
- status
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, module):
|
|
||||||
|
|
||||||
# states
|
|
||||||
self.running = None
|
|
||||||
self.enabled = None
|
|
||||||
self.action = None
|
|
||||||
|
|
||||||
# outcome
|
|
||||||
self.changed = False
|
|
||||||
|
|
||||||
# options
|
|
||||||
self.module = module
|
|
||||||
|
|
||||||
# alias running to started
|
|
||||||
if self.module.params['state'] == 'running':
|
|
||||||
self.module.params['state'] = 'started'
|
|
||||||
|
|
||||||
|
|
||||||
# ===========================================
|
|
||||||
# Platform specific methods (must be replaced by subclass).
|
|
||||||
|
|
||||||
def action(self):
|
|
||||||
self.module.fail_json(msg="action not implemented on target service")
|
|
||||||
|
|
||||||
def status(self): # this should also set self.enabled
|
|
||||||
self.module.fail_json(msg="status not implemented on target service")
|
|
||||||
|
|
||||||
def enable(self):
|
|
||||||
self.module.fail_json(msg="enable not implemented on target service")
|
|
||||||
|
|
||||||
# ===========================================
|
|
||||||
# Generic methods that should be used on all services.
|
|
||||||
|
|
||||||
def execute_command(self, cmd, daemonize=False):
|
|
||||||
|
|
||||||
# Most things don't need to be daemonized
|
|
||||||
if not daemonize:
|
|
||||||
return self.module.run_command(cmd)
|
|
||||||
|
|
||||||
# This is complex because daemonization is hard for people.
|
|
||||||
# What we do is daemonize a part of this module, the daemon runs the
|
|
||||||
# command, picks up the return code and output, and returns it to the
|
|
||||||
# main process.
|
|
||||||
pipe = os.pipe()
|
|
||||||
pid = os.fork()
|
|
||||||
if pid == 0:
|
|
||||||
os.close(pipe[0])
|
|
||||||
# Set stdin/stdout/stderr to /dev/null
|
|
||||||
fd = os.open(os.devnull, os.O_RDWR)
|
|
||||||
if fd != 0:
|
|
||||||
os.dup2(fd, 0)
|
|
||||||
if fd != 1:
|
|
||||||
os.dup2(fd, 1)
|
|
||||||
if fd != 2:
|
|
||||||
os.dup2(fd, 2)
|
|
||||||
if fd not in (0, 1, 2):
|
|
||||||
os.close(fd)
|
|
||||||
|
|
||||||
# Make us a daemon. Yes, that's all it takes.
|
|
||||||
pid = os.fork()
|
|
||||||
if pid > 0:
|
|
||||||
os._exit(0)
|
|
||||||
os.setsid()
|
|
||||||
os.chdir("/")
|
|
||||||
pid = os.fork()
|
|
||||||
if pid > 0:
|
|
||||||
os._exit(0)
|
|
||||||
|
|
||||||
# Start the command
|
|
||||||
if isinstance(cmd, (text_type, binary_type)):
|
|
||||||
cmd = shlex.split(cmd)
|
|
||||||
p = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, preexec_fn=lambda: os.close(pipe[1]))
|
|
||||||
stdout = ""
|
|
||||||
stderr = ""
|
|
||||||
fds = [p.stdout, p.stderr]
|
|
||||||
# Wait for all output, or until the main process is dead and its output is done.
|
|
||||||
while fds:
|
|
||||||
rfd, wfd, efd = select.select(fds, [], fds, 1)
|
|
||||||
if not (rfd + wfd + efd) and p.poll() is not None:
|
|
||||||
break
|
|
||||||
if p.stdout in rfd:
|
|
||||||
dat = os.read(p.stdout.fileno(), 4096)
|
|
||||||
if not dat:
|
|
||||||
fds.remove(p.stdout)
|
|
||||||
stdout += dat
|
|
||||||
if p.stderr in rfd:
|
|
||||||
dat = os.read(p.stderr.fileno(), 4096)
|
|
||||||
if not dat:
|
|
||||||
fds.remove(p.stderr)
|
|
||||||
stderr += dat
|
|
||||||
p.wait()
|
|
||||||
# Return a JSON blob to parent
|
|
||||||
os.write(pipe[1], json.dumps([p.returncode, stdout, stderr]))
|
|
||||||
os.close(pipe[1])
|
|
||||||
os._exit(0)
|
|
||||||
elif pid == -1:
|
|
||||||
self.module.fail_json(msg="unable to fork")
|
|
||||||
else:
|
|
||||||
os.close(pipe[1])
|
|
||||||
os.waitpid(pid, 0)
|
|
||||||
# Wait for data from daemon process and process it.
|
|
||||||
data = ""
|
|
||||||
while True:
|
|
||||||
rfd, wfd, efd = select.select([pipe[0]], [], [pipe[0]])
|
|
||||||
if pipe[0] in rfd:
|
|
||||||
dat = os.read(pipe[0], 4096)
|
|
||||||
if not dat:
|
|
||||||
break
|
|
||||||
data += dat
|
|
||||||
return json.loads(data)
|
|
||||||
|
|
||||||
def check_ps(self):
|
|
||||||
|
|
||||||
running = False
|
|
||||||
|
|
||||||
# Set ps flags
|
|
||||||
if platform.system() == 'SunOS':
|
|
||||||
psflags = '-ef'
|
|
||||||
else:
|
|
||||||
psflags = 'auxww'
|
|
||||||
|
|
||||||
# Find ps binary
|
|
||||||
psbin = self.module.get_bin_path('ps', True)
|
|
||||||
|
|
||||||
(rc, psout, pserr) = self.execute_command('%s %s' % (psbin, psflags))
|
|
||||||
# If rc is 0, set running as appropriate
|
|
||||||
if rc == 0:
|
|
||||||
lines = psout.split("\n")
|
|
||||||
for line in lines:
|
|
||||||
if self.module.params['pattern'] in line and not "pattern=" in line:
|
|
||||||
# so as to not confuse ./hacking/test-module
|
|
||||||
running = True
|
|
||||||
break
|
|
||||||
|
|
||||||
self.running = running
|
|
||||||
|
|
||||||
def result(self, msg=''):
|
|
||||||
return {
|
|
||||||
'name': self.module.name,
|
|
||||||
'state': self.status(),
|
|
||||||
'enabled': self.enabled,
|
|
||||||
'changed': self.changed,
|
|
||||||
'msg': msg,
|
|
||||||
}
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
|
|
||||||
if self.module.params['state'] is None and self.module.params['enabled'] is None:
|
|
||||||
self.module.fail_json(msg="Neither 'state' nor 'enabled' set")
|
|
||||||
|
|
||||||
# Set service startup state on request
|
|
||||||
if self.module.params['enabled'] is not None and self.enabled != self.module.params['enabled']:
|
|
||||||
self.changed = True
|
|
||||||
if not self.module.check_mode:
|
|
||||||
self.enable()
|
|
||||||
|
|
||||||
if self.module.params['state'] is not None and self.module.params['state'] != self.status():
|
|
||||||
self.changed = True
|
|
||||||
if not self.module.check_mode:
|
|
||||||
self.action()
|
|
||||||
|
|
||||||
return self.result()
|
|
||||||
|
|
||||||
|
|
||||||
def service_shared_arg_spec():
|
|
||||||
|
|
||||||
return dict(
|
|
||||||
name = dict(required=True),
|
|
||||||
state = dict(choices=['running', 'started', 'stopped', 'restarted', 'reloaded']),
|
|
||||||
enabled = dict(type='bool'),
|
|
||||||
)
|
|
||||||
# these are only needed/useful in init/rc systems
|
|
||||||
#arguments = dict(aliases=['args'], default=''),
|
|
||||||
#pattern = dict(required=False, default=None),
|
|
||||||
#sleep = dict(required=False, type='int', default=None),
|
|
||||||
#runlevel = dict(required=False, default='default'),
|
|
||||||
|
|
Loading…
Reference in a new issue