nosh system module: fixes and improvements (#32014)

* nosh system module: fixes and improvements

documentation:
* fleshed out and fixed to better follow the official guidelines

consistency:
* the following facts will now always be returned on success: name,
service_path, enabled, preset, user, status
* state is only returned when the state option is used
* state and status will be null if the service is not loaded by the end
of the task

* [nosh]: PEP8 fix
This commit is contained in:
tacatac 2017-10-23 15:19:22 +02:00 committed by Brian Coca
parent 465fe5802b
commit 4ffd60a406

View file

@ -18,9 +18,10 @@ module: nosh
author: author:
- "Thomas Caravia" - "Thomas Caravia"
version_added: "2.5" version_added: "2.5"
short_description: Manage services with nosh. short_description: Manage services with nosh
description: description:
- Controls services on remote hosts using the nosh toolset. - Control running and enabled state for system-wide or user services.
- BSD and Linux systems are supported.
options: options:
name: name:
required: true required: true
@ -30,7 +31,7 @@ options:
required: false required: false
choices: [ started, stopped, reset, restarted, reloaded ] choices: [ started, stopped, reset, 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. commands unless necessary.
C(restarted) will always bounce the service. C(restarted) will always bounce the service.
C(reloaded) will send a SIGHUP or start the service. C(reloaded) will send a SIGHUP or start the service.
@ -40,24 +41,27 @@ options:
required: false required: false
choices: [ "yes", "no" ] choices: [ "yes", "no" ]
description: description:
- Whether the service is enabled or not, independently of *.preset file - Enable or disable the service, independently of C(*.preset) file
preference or running state. Mutually exclusive with C(preset). Will take preference or running state. Mutually exclusive with I(preset). Will take
effect prior to the C(reset) state. effect prior to I(state=reset).
preset: preset:
required: false required: false
choices: [ "yes", "no" ] choices: [ "yes", "no" ]
default: no
description: description:
- Enable or disable the service according to local preferences in *.preset files. - Enable or disable the service according to local preferences in *.preset files.
Mutually exclusive with C(enabled). Only has an effect if set to true. Will take Mutually exclusive with I(enabled). Only has an effect if set to true. Will take
effect prior to the C(reset) state. effect prior to I(state=reset).
user: user:
required: false required: false
default: no default: 'no'
choices: [ "yes", "no" ] choices: [ "yes", "no" ]
description: description:
- Run system-control talking to the service manager of the calling user, rather than - Run system-control talking to the calling user's service manager, rather than
the service manager of the system. the system-wide service manager.
requirements:
- A system with an active nosh service manager, see Notes for further information.
notes:
- Information on the nosh utilities suite may be found at U(https://jdebp.eu/Softwares/nosh/).
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -83,8 +87,22 @@ EXAMPLES = '''
- name: for package installers, set nginx running state according to local enable settings, preset and reset - name: for package installers, set nginx running state according to local enable settings, preset and reset
nosh: name=nginx preset=True state=reset nosh: name=nginx preset=True state=reset
- name: reboot the host if nosh is the system manager, would need a "wait_for*" step at least, not recommended as-is - name: reboot the host if nosh is the system manager, would need a "wait_for*" task at least, not recommended as-is
nosh: name=reboot state=started nosh: name=reboot state=started
- name: using conditionals with the module facts
tasks:
- name: obtain information on tinydns service
nosh: name=tinydns
register: result
- name: fail if service not loaded
fail: msg="The {{ result.name }} service is not loaded"
when: not result.status
- name: fail if service is running
fail: msg="The {{ result.name }} service is running"
when: result.status and result.status['DaemontoolsEncoreState'] == "running"
''' '''
RETURN = ''' RETURN = '''
@ -98,8 +116,23 @@ service_path:
returned: success returned: success
type: string type: string
sample: "/var/sv/sshd" sample: "/var/sv/sshd"
enabled:
description: whether the service is enabled at system bootstrap
returned: success
type: boolean
sample: True
preset:
description: whether the enabled status reflects the one set in the relevant C(*.preset) file
returned: success
type: boolean
sample: False
state:
description: service process run state, C(None) if the service is not loaded and will not be started
returned: if state option is used
type: string
sample: "reloaded"
status: status:
description: a dictionary with the key=value pairs returned by `system-control show-json SERVICE` or Loaded=False if the service is not loaded description: a dictionary with the key=value pairs returned by `system-control show-json` or C(None) if the service is not loaded
returned: success returned: success
type: complex type: complex
contains: { contains: {
@ -152,6 +185,11 @@ status:
"../sshdgenkeys" "../sshdgenkeys"
] ]
} }
user:
description: whether the user-level service manager is called
returned: success
type: boolean
sample: False
''' '''
@ -217,14 +255,14 @@ def handle_enabled(module, result, service_path):
These options are set to "mutually exclusive" but the explicit 'enabled' option will These options are set to "mutually exclusive" but the explicit 'enabled' option will
have priority if the check is bypassed. have priority if the check is bypassed.
""" """
enabled = service_is_enabled(module, service_path)
# computed prior in control flow
preset = result['preset']
enabled = result['enabled']
# preset, effect only if option set to true (no reverse preset) # preset, effect only if option set to true (no reverse preset)
if module.params['preset']: if module.params['preset']:
action = 'preset' action = 'preset'
preset = enabled is service_is_preset_enabled(module, service_path)
result['preset'] = preset
result['enabled'] = enabled
# run preset if needed # run preset if needed
if preset != module.params['preset']: if preset != module.params['preset']:
@ -243,8 +281,6 @@ def handle_enabled(module, result, service_path):
else: else:
action = 'disable' action = 'disable'
result['enabled'] = enabled
# change enable/disable if needed # change enable/disable if needed
if enabled != module.params['enabled']: if enabled != module.params['enabled']:
result['changed'] = True result['changed'] = True
@ -253,6 +289,7 @@ def handle_enabled(module, result, service_path):
if rc != 0: if rc != 0:
module.fail_json(msg="Unable to %s service %s: %s" % (action, service_path, out + err)) module.fail_json(msg="Unable to %s service %s: %s" % (action, service_path, out + err))
result['enabled'] = not enabled result['enabled'] = not enabled
result['preset'] = not preset
def handle_state(module, result, service_path): def handle_state(module, result, service_path):
@ -264,28 +301,25 @@ def handle_state(module, result, service_path):
""" """
# default to desired state, no action # default to desired state, no action
result['state'] = module.params['state'] result['state'] = module.params['state']
state = module.params['state']
action = None action = None
# case for enabled/preset + reset + check_mode: use anticipated enabled status # computed prior in control flow, possibly modified by handle_enabled()
# otherwise test real enabled status enabled = result['enabled']
if module.check_mode and (module.params['enabled'] is not None or module.params['preset']):
enabled = result['enabled']
else:
enabled = service_is_enabled(module, service_path)
# service not loaded -> not started by manager, no status information # service not loaded -> not started by manager, no status information
if not service_is_loaded(module, service_path): if not service_is_loaded(module, service_path):
if module.params['state'] in ['started', 'restarted', 'reloaded']: if state in ['started', 'restarted', 'reloaded']:
action = 'start' action = 'start'
result['state'] = 'started' result['state'] = 'started'
elif module.params['state'] == 'reset': elif state == 'reset':
if enabled: if enabled:
action = 'start' action = 'start'
result['state'] = 'started' result['state'] = 'started'
else: else:
result['state'] = 'stopped' result['state'] = None
else: else:
result['state'] = 'stopped' result['state'] = None
# service is loaded # service is loaded
else: else:
@ -293,14 +327,14 @@ def handle_state(module, result, service_path):
result['status'] = get_service_status(module, service_path) result['status'] = get_service_status(module, service_path)
running = service_is_running(result['status']) running = service_is_running(result['status'])
if module.params['state'] == 'started': if state == 'started':
if not running: if not running:
action = 'start' action = 'start'
elif module.params['state'] == 'stopped': elif state == 'stopped':
if running: if running:
action = 'stop' action = 'stop'
# reset = start/stop according to enabled status # reset = start/stop according to enabled status
elif module.params['state'] == 'reset': elif state == 'reset':
if enabled is not running: if enabled is not running:
if running: if running:
action = 'stop' action = 'stop'
@ -309,14 +343,14 @@ def handle_state(module, result, service_path):
action = 'start' action = 'start'
result['state'] = 'started' result['state'] = 'started'
# start if not running, 'service' module constraint # start if not running, 'service' module constraint
elif module.params['state'] == 'restarted': elif state == 'restarted':
if not running: if not running:
action = 'start' action = 'start'
result['state'] = 'started' result['state'] = 'started'
else: else:
action = 'condrestart' action = 'condrestart'
# start if not running, 'service' module constraint # start if not running, 'service' module constraint
elif module.params['state'] == 'reloaded': elif state == 'reloaded':
if not running: if not running:
action = 'start' action = 'start'
result['state'] = 'started' result['state'] = 'started'
@ -342,7 +376,7 @@ def main():
state=dict(choices=['started', 'stopped', 'reset', 'restarted', 'reloaded'], type='str'), state=dict(choices=['started', 'stopped', 'reset', 'restarted', 'reloaded'], type='str'),
enabled=dict(type='bool'), enabled=dict(type='bool'),
preset=dict(type='bool'), preset=dict(type='bool'),
user=dict(type='bool'), user=dict(type='bool', default=False),
), ),
supports_check_mode=True, supports_check_mode=True,
mutually_exclusive=[['enabled', 'preset']], mutually_exclusive=[['enabled', 'preset']],
@ -354,12 +388,17 @@ def main():
result = { result = {
'name': service, 'name': service,
'changed': False, 'changed': False,
'status': {}, 'status': None,
} }
# check service can be found (or fail) and get path # check service can be found (or fail) and get path
service_path = get_service_path(module, service) service_path = get_service_path(module, service)
# get preliminary service facts
result['service_path'] = service_path result['service_path'] = service_path
result['user'] = module.params['user']
result['enabled'] = service_is_enabled(module, service_path)
result['preset'] = result['enabled'] is service_is_preset_enabled(module, service_path)
# set enabled state, service need not be loaded # set enabled state, service need not be loaded
if module.params['enabled'] is not None or module.params['preset']: if module.params['enabled'] is not None or module.params['preset']:
@ -372,8 +411,6 @@ def main():
# get final service status if possible # get final service status if possible
if service_is_loaded(module, service_path): if service_is_loaded(module, service_path):
result['status'] = get_service_status(module, service_path) result['status'] = get_service_status(module, service_path)
else:
result['status'] = {'Loaded': False}
module.exit_json(**result) module.exit_json(**result)