Ansible Modules

From Scratch

By Xavi Soler

All code used in this presentation is at:

Ansible Modules

Ansible modules are reusable units of magic that can be used by the Ansible API, or by the ansible or ansible-playbook programs.

Ansible Modules   =   Units of Magic

Using the CLI

$ ansible webservers -m apt -a "name=nginx state=present"

Using Playbooks

- name: install nginx
  apt: name=nginx state=present

What Modules Do?

Receive arguments as a filepath


Do something

Usually idempotent actions to ensure state

Return JSON

ie: {"changed":"true"}, other additional info to be used as variables later in the playbook

Modules Development

  • Ansible modules can be developed in any programming language
  • All modules available in modules-core and modules-extras are developed in Python
  • from ansible.module_utils.basic import *

Ansible Library

  • $ANSIBLE_LIBRARY is the environment variable that defines the paths where Ansible modules can be found
  • The /library/ directory in the root of your playbook will be checked as well and it's a good place for project-specific modules

Our First Module

$ find .
# sync time using ntp
diff=$(ntpd -q | tail -n 1 | cut -d' ' -f4)
echo -n "{\"changed\":\"true\",\"diff\":\"$diff\"}"
- hosts:
  sudo: True
    - timesync:

a shell script!

Our First Module

a shell script!

$ ansible-playbook playbook.yml -v

PLAY [] ************************************************************** 

GATHERING FACTS *************************************************************** 
ok: []

TASK: [timesync ] ************************************************************* 
changed: [] => {"changed": "true", "diff": "+0.000726s"}

PLAY RECAP ********************************************************************                  : ok=2    changed=1    unreachable=0    failed=0

Our Second Module

do nothing + print input parameters!

$ find .
# outputs its own input params
jq -R 'split(" ") | map(split("=") | {key: .[0], value: .[1]}) | from_entries' $1
- hosts:
    - print_params: name=xavi twitter=@xavi_xsb github=xsb

Our Second Module

do nothing + print input parameters!

$ ansible-playbook playbook.yml -v

PLAY [] **************************************************************

GATHERING FACTS ***************************************************************
ok: []

TASK: [print_params name=xavi twitter=@xavi_xsb github=xsb] *******************
ok: [] => {"github": "xsb", "name": "xavi", "twitter": "@xavi_xsb"}

PLAY RECAP ********************************************************************                  : ok=2    changed=0    unreachable=0    failed=0

Modules in Python

We will implement a simple module:

1) Uploads a file to GitHub Gist

2) Return URL

TASK: [gist] ********************************************* 
changed: [] => {"changed": true,
                         "filename": "",
                         "url": ""}

import urllib2
import json

def copy_to_gist(public, filename, content):
    data = {"public":public,'files':{filename:{'content':content}}}

    req = urllib2.Request('')
    req.add_header('Content-Type', 'application/json')
    response = urllib2.urlopen(req, json.dumps(data))
    return response


def main():

    module = AnsibleModule(
        argument_spec = dict(
            src    = dict(required=True, type='str'),
            public = dict(required=False, default='false', 
                          choices=['true', 'false']),
        supports_check_mode = False
    src = module.params['src']
    filename = os.path.basename(src)
    public = module.params['public']
    f = open(os.path.expanduser(src))
    content =

        response = copy_to_gist(public, filename, content)
    except Exception as e:
        module.fail_json(msg=str(e), changed=False)

    j = json.load(response)
    module.exit_json(changed=True, filename=filename, url=j['html_url'])


# import module snippets
from ansible.module_utils.basic import *

if __name__ == '__main__':


Testing Modules

$ git clone git:// --recursive
$ source ansible/hacking/env-setup
$ chmod +x ansible/hacking/test-module
$ ansible/hacking/test-module -m ./ -a "key=value"



module: gist
author: "Xavi S.B. @xsb"
short_description: create Github Gists
  - Copy files to Github Gist
      - File Path
    required: true
      - Is this Gist public or not?
    required: false
    default: false
    choices: [ "true", "false" ]


# Upload a config file
- gist: src=/etc/pacman.conf public=false
RETURN = '''
  description: gist url
  returned: success
  type: string


Ansible Modules From Scratch

By Xavi Soler

Ansible Modules From Scratch

  • 537

More from Xavi Soler