Skip to content

Instantly share code, notes, and snippets.

@mgedmin
Last active November 24, 2015 06:20
Show Gist options
  • Save mgedmin/aec4678b25c2734f0d57 to your computer and use it in GitHub Desktop.
Save mgedmin/aec4678b25c2734f0d57 to your computer and use it in GitHub Desktop.
"changelog" module for Ansible, wrapping new-changelog-entry from pov-admin-tools
# action_plugins/changelog.py
import time
try:
# Ansible 2
from ansible.plugins.action import ActionBase
class ActionModule(ActionBase):
'''Set default value for 'append' from the 'changelog_started' fact'''
def run(self, tmp=None, task_vars=dict()):
changelog_started = bool(task_vars.get('changelog_started', False))
changelog_last_update = int(task_vars.get('changelog_last_update', 0))
if changelog_last_update and changelog_last_update < time.time() - 300:
changelog_started = False
module_args = self._task.args.copy()
module_args.setdefault('append', changelog_started)
return self._execute_module(module_args=module_args, tmp=tmp, task_vars=task_vars)
except ImportError:
# Ansible 1
from ansible.runner.return_data import ReturnData
from ansible.runner.action_plugins.normal import ActionModule as _ActionModule
class ActionModule(_ActionModule):
'''Set default value for 'append' from the 'changelog_started' fact'''
def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs):
if module_args == 'start=yes' or complex_args.get('start'):
# optimization
return ReturnData(conn=conn, comm_ok=True, result=dict(ansible_facts=dict(changelog_started=False)))
if self.runner.noop_on_check(inject):
return ReturnData(conn=conn, comm_ok=True, result=dict(skipped=True, msg='check mode not supported for this module'))
changelog_started = inject.get('changelog_started', False)
changelog_last_update = inject.get('changelog_last_update', 0)
if changelog_last_update and changelog_last_update < time.time() - 300:
changelog_started = False
complex_args.setdefault('append', changelog_started)
return super(ActionModule, self).run(conn, tmp, module_name, module_args, inject, complex_args=complex_args, **kwargs)
#!/usr/bin/python
# library/changelog.py
import os
import subprocess
import time
DOCUMENTATION = '''
---
module: changelog
short_description: appends a message to /root/Changelog
description:
- The M(changelog) module takes single a string message and appends it
to /root/Changelog on the remote host, with a date and time header.
- This requires pov-admin-tools to be installed on the remote.
options:
msg:
description:
- the message
required: true
default: null
append:
description:
- append the message to the existing entry instead of starting a new entry
required: false
choices: [ true, false ]
default: false for the 1st invocation on each host, true for all subsequent invocations
blank_line_above:
description:
- prepend a blank line above the message, unless this is the 1st invocation
required: false
choices: [ true, false ]
default: false
start:
description:
- reset the state so the next invocation is considered to be 1st invocation
- run this first if you use fact caching, otherwise changelogs from
multiple playbook runs will be clumped together
choices: [ true, false ]
required: false
default: false
author:
- Marius Gedminas <[email protected]>
'''
EXAMPLES = '''
# Prerequisite: install pov-admin-tools from ppa:pov
- apt_repository: repo='ppa:pov' state=present
- apt: name=pov-admin-tools state=present
# Reset the changelog state
- changelog: start=yes
# Record new installed package iff it was installed
- apt: name=postfix state=present
record: apt_result
- changelog: msg="apt-get install postfix"
when: apt_result|changed
# A multi-line changelog message
- changelog:
args:
blank_line_above: yes
msg: |
#
# Banner message
#
apt-get foo bar
# NB: the "|"-literal YAML syntax adds a blank line afterwards
- changelog:
args:
msg:
- "# multiple"
- "# messages"
- "# with no blank line after them, unlike the example above"
'''
def main():
module = AnsibleModule(
argument_spec=dict(
msg=dict(required=False),
start=dict(type='bool', default=False),
append=dict(type='bool', default=False),
blank_line_above=dict(type='bool', default=False),
),
)
start = module.params['start']
if start:
module.exit_json(
ansible_facts=dict(
changelog_started=False,
)
)
msg = module.params['msg']
if msg is None:
module.fail_json(msg="message is required".format(msg))
if isinstance(msg, list):
msg = "\n ".join(msg)
else:
msg = msg.replace('\n', '\n ')
append = module.params['append']
blank_line_above = module.params['blank_line_above']
if append and blank_line_above:
msg = '\n ' + msg
if msg in ('-a', '-e', '/root/Changelog') or os.path.exists(msg):
module.fail_json(msg="message cannot be '{}' due to the way new-changelog-message parses its arguments".format(msg))
args = ['new-changelog-entry']
if append:
args += ['-a']
args += [msg]
try:
cmd = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = cmd.communicate()
rc = cmd.returncode
except (OSError, IOError) as e:
module.fail_json(rc=e.errno, msg=str(e), cmd=args)
module.exit_json(
message=msg,
rc=rc,
out=out,
err=err,
changed=True,
ansible_facts=dict(
changelog_started=True,
changelog_last_update=time.time(),
)
)
from ansible.module_utils.basic import * # noqa
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment