Skip to content

Instantly share code, notes, and snippets.

@brutus
Last active July 3, 2017 16:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save brutus/ba3b110c3041777e2e976b61e924b18c to your computer and use it in GitHub Desktop.
Save brutus/ba3b110c3041777e2e976b61e924b18c to your computer and use it in GitHub Desktop.
A very basic Ansible module for toast.
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
Ansible module to interact with `toast`_.
To use this from Ansible, copy it in your `library`_::
cd path/to/library
git clone https://gist.github.com/brutus/ba3b110c3041777e2e976b61e924b18c toast
And use it in your playbook or roles like this::
# install tar
- toast:
name: tar
# update tar
- toast:
name: tar
state: latest
# uninstall tar
- toast:
name: tar
state: absent
It returns some JSON like this (eg: install `tar` while it is already
installed)::
{
"action": "nothing",
"changed": false,
"invocation": {
"module_args": {
"name": "tar",
"state": "present"
},
"module_name": "toast"
},
"status_new": {
"name": "tar",
"state": "present",
"version": "1.29"
},
"status_old": {
"name": "tar",
"state": "present",
"version": "1.29"
}
}
Install new package sources
---------------------------
To add a new URL as package source, use a `add` as *state* and the URL as *name*, e.g. for the `tree`_ utility::
# add package for `tree`
- toast:
name: ftp://mama.indstate.edu/linux/tree/
state: add
.. _toast: http://www.toastball.net/toast/
.. _library: http://docs.ansible.com/ansible/intro_configuration.html#library
.. _tree: http://mama.indstate.edu/users/ice/tree/
"""
from __future__ import absolute_import
from __future__ import unicode_literals
import re
from ansible.module_utils.basic import AnsibleModule
def main():
REGEX_VERSION = re.compile(r'version (?P<version>[0-9\.]+): .+')
def get_status(name):
"""
Returns a dict with toast status information for *name*.
The *name*, *state* and *version* will be returned.
If the return code of the toast command (`rc`) is 0, the *name* is
found in toasts DB and the output should be similar to this::
toast
version 1.486: stored
urls:
http://www.toastball.net/toast/toast-1.486.tar.gz
build 1: armed
"""
state = 'absent'
version = None
err_msg = 'failed to parse output: {0}'
# run command
cmd = ['toast', 'status', name]
(rc, stdout, stderr) = module.run_command(cmd, check_rc=False)
result = [line.strip() for line in stdout.split('\n') if line]
if rc == 0: # means the *name* is in the DB
# verify name
if result[0] != name:
module.fail_json(msg=err_msg.format(result))
# check state
build_string = result[-1]
if (
build_string.startswith('build') and
build_string.endswith('armed')
):
state = 'present'
# check version
match = REGEX_VERSION.match(result[1])
if match:
version = match.group('version')
else:
module.fail_json(msg=err_msg.format(result))
return {
'name': name,
'state': state,
'version': version,
}
def get_package_status(name):
"""
Returns the state for the package with *name*.
The *state* is either `present` or `absent`.
"""
cmd = ['toast', 'status', name]
(rc, stdout, stderr) = module.run_command(cmd, check_rc=False)
if rc == 0:
return 'present'
else:
return 'absent'
def install(name):
"""
Calls toast to install *name*.
"""
cmd = ['toast', 'arm', name]
module.run_command(cmd, check_rc=True)
def upgrade(name):
"""
Calls toast to upgrade *name*.
"""
cmd = ['toast', 'upgrade', name]
module.run_command(cmd, check_rc=True)
def uninstall(name):
"""
Calls toast to uninstall *name*.
"""
cmd = ['toast', 'disarm', name]
module.run_command(cmd, check_rc=True)
def add_package(url):
"""
Calls toast to add a new package for *url*.
"""
cmd = ['toast', 'add', url]
module.run_command(cmd, check_rc=True)
# setup module
args = {
'name': dict(required=True),
'state': dict(
choices=['present', 'absent', 'latest', 'add'],
default='present',
),
}
module = AnsibleModule(
argument_spec=args,
supports_check_mode=True,
)
# interact with toast
name = module.params['name']
req_state = module.params['state']
# add package?
if req_state == 'add':
action = 'add'
status_old = get_package_status(name)
if module.check_mode or status_old == 'present':
status_new = status_old
else:
add_package(name)
status_new = get_package_status(name)
# install / upgrade / uninstall
else:
status_old = get_status(name)
state = status_old['state']
if req_state == 'absent':
action = 'uninstall' if state == 'present' else ''
elif req_state == 'latest':
action = 'upgrade' if state == 'present' else 'install'
else: # present
action = '' if state == 'present' else 'install'
if module.check_mode:
status_new = status_old
else:
if action == 'uninstall':
uninstall(name)
elif action == 'upgrade':
upgrade(name)
else: # install
install(name)
status_new = get_status(name)
# return results as JSON
module.exit_json(
changed=status_old != status_new,
status_old=status_old,
status_new=status_new,
action=action or 'nothing',
)
if __name__ == '__main__':
main()
@brutus
Copy link
Author

brutus commented Dec 29, 2016

To use this from Ansible, copy it in your library and use it in your playbook or roles like this:

# install tar
- toast:
  name: tar

# update tar
- toast:
  name: tar
  state: latest

# uninstall tar
- toast:
  name: tar
  state: absent

It returns some JSON like this (eg: install tar while it is already installed):

{
    "action": "nothing", 
    "changed": false, 
    "invocation": {
        "module_args": {
            "name": "tar", 
            "state": "present"
        }, 
        "module_name": "toast"
    }, 
    "status_new": {
        "name": "tar", 
        "state": "present", 
        "version": "1.29"
    }, 
    "status_old": {
        "name": "tar", 
        "state": "present", 
        "version": "1.29"
    }
}

@andreasmischke
Copy link

I guess it has to be name: tar in the update example

# update tar
- toast:
  name: tar    # was "name: toast"
  state: latest

@brutus
Copy link
Author

brutus commented Jul 3, 2017

I guess it has to be name: tar in the update example

Correct. Fixed it. Thanks for spotting and report!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment