• Stars
    star
    133
  • Rank 272,600 (Top 6 %)
  • Language
  • License
    MIT License
  • Created over 7 years ago
  • Updated about 7 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

💥 Ansible module development with examples and walk-throughs

Ansible Development by Example

Why?

Ansible is an awesome tool for configuration management. It is also a highly utilized one, and there are so many ways to contribute as a community.

What is this?

There is no doubt that Ansible is a complex tool, with lots of inner-workings, yet it is easy to work with as an end user. But on the other end of that, contributing to Ansible with code can sometimes be a daunting task.

This documentation is a way to show step-by-step how to develop Ansible modules, both new module development as well as bug fixes and debugging.

Environment setup

  1. Clone the Ansible repository: $ git clone https://github.com/ansible/ansible.git
  2. Change directory into the repository root dir: $ cd ansible
  3. Create a virtual environment: $ python3 -m venv venv (or for Python 2 $ virtualenv venv. Note, this requires you to install the virtualenv package: $ pip install virtualenv)
  4. Activate the virtual environment: $ . venv/bin/activate
  5. Install development requirements: $ pip install -r requirements.txt
  6. Run the environment setup script for each new dev shell process: $ . hacking/env-setup

After the initial setup above, every time you are ready to start developing Ansible you should be able to just run the following from the root of the Ansible repo: $ . venv/bin/activate && . hacking/env-setup

💡 Starting new development now? Fixing a bug? Create a new branch: $ git checkout -b my-new-branch. If you are planning on contributing back to the main Ansible repostiry, fork the Ansible repository into your own GitHub account and developing against your new non-devel branch in your fork. When you believe you have a good working code change, submit a pull request to the Ansible repository.

💡 💡 Submitting a new module to the upstream Ansible repo? Run through sanity checks first: $ ansible-test sanity -v --docker --python 2.7 MODULE_NAME (this requires docker to be installed and running. If you'd rather not use a container for this you can choose to use --tox instead of --docker)

New module development

If you are creating a new module that doesn't exist, you would start working on a whole new file. Here is an example:

  • Navigate to the directory that you want to develop your new module in. E.g. $ cd lib/ansible/modules/cloud/azure/
  • Create your new module file: $ touch my_new_test_module.py
  • Paste this simple into the new module file: (explanation in comments)
#!/usr/bin/python

ANSIBLE_METADATA = {
    'metadata_version': '1.0',
    'status': ['preview'],
    'supported_by': 'curated'
}

DOCUMENTATION = '''
---
module: my_sample_module

short_description: This is my sample module

version_added: "2.4"

description:
    - "This is my longer description explaining my sample module"

options:
    name:
        description:
            - This is the message to send to the sample module
        required: true
    new:
        description:
            - Control to demo if the result of this module is changed or not
        required: false

extends_documentation_fragment
    - azure

author:
    - Your Name (@yourhandle)
'''

EXAMPLES = '''
# Pass in a message
- name: Test with a message
  my_new_test_module:
    name: hello world

# pass in a message and have changed true
- name: Test with a message and changed output
  my_new_test_module:
    name: hello world
    new: true

# fail the module
- name: Test failure of the module
  my_new_test_module:
    name: fail me
'''

RETURN = '''
original_message:
    description: The original name param that was passed in
    type: str
message:
    description: The output message that the sample module generates
'''

from ansible.module_utils.basic import AnsibleModule

def run_module():
    # define the available arguments/parameters that a user can pass to
    # the module
    module_args = dict(
        name=dict(type='str', required=True),
        new=dict(type='bool', required=False, default=False)
    )

    # seed the result dict in the object
    # we primarily care about changed and state
    # change is if this module effectively modified the target
    # state will include any data that you want your module to pass back
    # for consumption, for example, in a subsequent task
    result = dict(
        changed=False,
        original_message='',
        message=''
    )

    # the AnsibleModule object will be our abstraction working with Ansible
    # this includes instantiation, a couple of common attr would be the
    # args/params passed to the execution, as well as if the module
    # supports check mode
    module = AnsibleModule(
        argument_spec=module_args,
        supports_check_mode=True
    )

    # if the user is working with this module in only check mode we do not
    # want to make any changes to the environment, just return the current
    # state with no modifications
    if module.check_mode:
        return result

    # manipulate or modify the state as needed (this is going to be the
    # part where your module will do what it needs to do)
    result['original_message'] = module.params['name']
    result['message'] = 'goodbye'

    # use whatever logic you need to determine whether or not this module
    # made any modifications to your target
    if module.params['new']:
        result['changed'] = True

    # during the execution of the module, if there is an exception or a
    # conditional state that effectively causes a failure, run
    # AnsibleModule.fail_json() to pass in the message and the result
    if module.params['name'] == 'fail me':
        module.fail_json(msg='You requested this to fail', **result)

    # in the event of a successful module execution, you will want to
    # simple AnsibleModule.exit_json(), passing the key/value results
    module.exit_json(**result)

def main():
    run_module()

if __name__ == '__main__':
    main()

Local/direct module testing

You may want to test the module on the local machine without targeting a remote host. This is a great way to quickly and easily debug a module that can run locally.

  • Create an arguments file in /tmp/args.json with the following content: (explanation below)
{
  "ANSIBLE_MODULE_ARGS": {
    "name": "hello",
    "new": true
  }
}
  • If you are using a virtual environment (highly recommended for development) activate it: $ . venv/bin/activate
  • Setup the environment for development: $ . hacking/env-setup
  • Run your test module locally and directly: $ python ./my_new_test_module.py /tmp/args.json

This should be working output that resembles something like the following:

{"changed": true, "state": {"original_message": "hello", "new_message": "goodbye"}, "invocation": {"module_args": {"name": "hello", "new": true}}}

💡 The arguments file is just a basic json config file that you can use to pass the module your parameters to run the module it

Playbook module testing

If you want to test your new module, you can now consume it with an Ansible playbook.

  • Create a playbook in any directory: $ touch testmod.yml
  • Add the following to the new playbook file
---
- name: test my new module
  connection: local
  hosts: localhost

  tasks:
    - name: run the new module
      my_new_test_module:
        name: 'hello'
        new: true
      register: testout

    - name: dump test output
      debug:
        msg: '{{ testout }}'
  • Run the playbook and analyze the output: $ ansible-playbook ./testmod.yml

Debugging (local)

If you want to break into a module and step through with the debugger, locally running the module you can do:

  1. Set a breakpoint in the module: import pdb; pdb.set_trace()
  2. Run the module on the local machine: $ python -m pdb ./my_new_test_module.py ./args.json

Debugging (remote)

In the event you want to debug a module that is running on a remote target (i.e. not localhost), one way to do this is the following:

  1. On your controller machine (running Ansible) set ANSIBLE_KEEP_REMOTE_FILES=1 (this tells Ansible to retain the modules it sends to the remote machine instead of removing them)
  2. Run your playbook targetting the remote machine and specify -vvvv (the verbose output will show you many things, including the remote location that Ansible uses for the modules)
  3. Take note of the remote path Ansible used on the remote host
  4. SSH into the remote target after the completion of the playbook
  5. Navigate to the directory (most likely it is going to be your ansible remote user defined or implied from the playbook: ~/.ansible/tmp/ansible-tmp-...)
  6. Here you should see the module that you executed from your Ansible controller, but this is the zipped file that Ansible sent to the remote host. You can run this by specifying python my_test_module.py (not necessary)
  7. To debug, though, we will want to extra this zip out to the original module format: python my_test_module.py explode (Ansible will expand the module into ./debug-dir)
  8. Navigate to ./debug-dir (notice that unzipping has caused the generation of ansible_module_my_test_module.py)
  9. Modify or set a breakpoint in the unzipped module
  10. Ensure that the unzipped module is executable: $ chmod 755 ansible_module_my_test_module.py
  11. Run the unzipped module directly passing the args file: $ ./ansible_module_my_test_module.py args (args is the file that contains the params that were originally passed. Good for repro and debugging)

Unit testing

Unit tests for modules will be appropriately located in ./test/units/modules. You must first setup your testing environment. In my case, I'm using Python 3.5.

  • Install the requirements (outside of your virtual environment): $ pip3 install -r ./test/runner/requirements/units.txt
  • To run all tests do the following: $ ansible-test units --python 3.5 (you must run . hacking/env-setup prior to this)

💡 Ansible uses pytest for unit testing

To run pytest against a single test module, you can do the following (provide the path to the test module appropriately):

$ pytest -r a --cov=. --cov-report=html --fulltrace --color yes test/units/modules/.../test_my_new_test_module.py

Communication and development support

Join the IRC channel #ansible-devel on freenode for discussions surrounding Ansible development.

For questions and discussions pertaining to using the Ansible product, use the #ansible channel.

Credit

A huge thank you to the Ansible team at Red Hat for providing not only a great product but also the willingness to help out contributors!

More Repositories

1

manual-approval

Pause your GitHub Actions workflow and request manual approval from set approvers before continuing
Go
373
star
2

awesome-tech-conferences

📢 A curated list of upcoming technical conferences
327
star
3

remote-jobs-hiring-without-whiteboards

💡 Intersection of the two famous lists for remote-jobs and hiring-without-whiteboards
Python
323
star
4

cli-debugging-cheatsheets

🔥 Collection of command-line debugging cheatsheets for multiple languages and runtimes
256
star
5

create-react-app-with-redux

🌟 Simple redux implementation added to an app created with create-react-app
JavaScript
159
star
6

pycli

💻 Basic structure for a simple Python CLI
Python
110
star
7

otel-shopping-cart

Sample application illustrating multiple aspects of observability with OpenTelemetry
Go
83
star
8

k8s-controller-core-resource

Base sample for a custom controller in Kubernetes working with core resources
Go
82
star
9

k8s-controller-custom-resource

Base sample for a custom controller in Kubernetes working with custom resources
Go
62
star
10

electron-basic-ui-layout

🐙 Common UI layout for an Electron/React app
JavaScript
54
star
11

jersey

🍝 A to-do/backlog CLI with Trello for a backend
Python
41
star
12

azblogfilter

Retrieve Azure blog update posts with the capability to filter on keywords in the title or categories of posts. Allows for easy automation!
Go
28
star
13

electron-flexbox-ui-layout

🐳 Common UI layout for an Electron/React app using Flexbox
JavaScript
26
star
14

go-systemd-time

📅 Go implementation of systemd relative time adjustments
Go
23
star
15

az-aks-ssh

SSH into Azure Kubernetes Service (AKS) nodes
Shell
22
star
16

react-laboratory

🔬 Minimal boilerplate to experiment and test with React without having to worry about the server
JavaScript
21
star
17

redditwatcher

📻 Reddit streaming CLI
Shell
19
star
18

python-flask-docker-compose-debugging

🐛 Sample application to help illustrate how to break into the debugger in a Python Flask application running as a container in Docker Compose
Python
18
star
19

kubernetes-mutating-webhook

Example showing how to implement a basic mutating webhook
Go
17
star
20

verpy

🐍 Python application versioning tool
Python
15
star
21

az-consumption-summary

Azure consumption summary and reporting for the terminal
Python
13
star
22

jwt-creator

Utility to quickly and easily create and verify JSON web tokens (JWT)
Go
13
star
23

pipin

🍓 Raspberry Pi pin controller CLI
JavaScript
12
star
24

pymail

📬 Command-line email client
Python
12
star
25

sherlock

☁️ Integration testing sandbox environment provisioning tool for Microsoft Azure
JavaScript
12
star
26

vscode-tips

💡 Visual Studio Code tips and quick reference
12
star
27

kubectl-example

kubectl plugin to dump example helper resource templates
Go
12
star
28

linux-core-temperature-monitor

🔥 Script (meant to run via cron) to monitor, log, and alert when the CPU is throttled due to overheating
Python
11
star
29

psql.nvim

Plugin to work with PostgreSQL directly from Neovim
Lua
10
star
30

venvdetect

🐍 Detect available Python virtual environments in your current directory
Python
9
star
31

terraform-azure-linux-vm

🐧 Provision an Azure Linux VM with Terraform
HCL
9
star
32

boiler-room-custodian

🐅 mop up those boilerplates
JavaScript
8
star
33

python3-random-quote

Python
6
star
34

kubernetes-aad-msi

Authenticate Kubernetes applications to cloud resources with Azure Active Directory
Go
6
star
35

pywave

🌊 CLI to fetch and parse buoy data
Python
6
star
36

shark-mail

🐟 Filesystem-based email CLI
JavaScript
5
star
37

tweetify

🐦 Node.js module that formats text to tweet
JavaScript
4
star
38

kubernetes-validating-webhook

Example showing how to implement a basic Kubernetes validating webhook
Go
4
star
39

trstringer.github.io

Build a Jekyll blog in minutes, without touching the command line.
SCSS
3
star
40

peachy-cli

🍑 CLI for cross-platform and cross-data-source querying and data manipulation
JavaScript
3
star
41

stackoverflow-digest

Get a digest of StackOverflow questions.
Python
2
star
42

go-template-cli-simple

Go template for a simple CLI
Go
2
star
43

require-label-prefix

GitHub Action to either warn or add a default label when no label with a prefix exists on an issue
Go
2
star
44

kuberetes-log-dump

Dump all Kubernetes pod logs (current and previous)
Shell
2
star
45

aks-deploy-from-github-actions

Example showing how to deploy to AKS (Azure Kubernetes Service) from GitHub Actions
Makefile
2
star
46

az-cli-helpers

Wrapper shell functions to make Azure resource management easier
Shell
2
star
47

azure-logger

📘 Node.js module that makes logging to Azure extremely easy
JavaScript
2
star
48

pyllo-world

Hello world with CI
Python
2
star
49

psqlcm

Local connection manager for PostgreSQL
Go
2
star
50

surfchartdl

🌊 Surf chart downloader
Python
2
star
51

platform-chaos-fn-startstop

azure-chaos extension to trigger start/stop events against an Azure web app
JavaScript
2
star
52

stocks-cli

💰 Stock price lookup CLI
JavaScript
2
star
53

sql-log-shipping

Utility for log shipping within SQL Server
PowerShell
1
star
54

pip-requirements

Wrapper shell functions for auto-creating Python dependency requirements files based on environment
1
star
55

trstringer

1
star
56

tstringer.github.io

🏄 My blog
CSS
1
star
57

char-art

💻 Making character art has never been easier!
JavaScript
1
star
58

nodejs-101-presentation

🚀 Slide deck for an introduction to Node.js and JavaScript
JavaScript
1
star
59

discuss-this

🌇 Node.js application/API for wordly discussions
JavaScript
1
star
60

sql-server-versions-powershell

PowerShell Module to consume the SQL Server Versions API
PowerShell
1
star
61

k8s-prometheus-grafana-dashboard-deployment

Shell
1
star
62

sorting-algorithm-stability

Demo application highlighting sorting algorithm stability output
Go
1
star
63

cloud-init-update

Cloud-init update process.
Python
1
star
64

xevents-helper

Helper website to assist with constructing Extended Events sessions for SQL Server
C#
1
star
65

discuss-this-web-job

⏰ The web job in charge of handling the routine discuss this calls
JavaScript
1
star
66

trill

🐤 Easily and quickly tweet long and short tweets with flexibility
JavaScript
1
star
67

peacherine

🍑 Cross-platform (node.js) and multi-datasource query module
JavaScript
1
star
68

pywave2

🌊 Get swell buoy data
Python
1
star
69

cicd-basics

JavaScript
1
star
70

httpbin2

Web server for testing, demo'ing, learning, and many other uses. Great for microservice environments and more!
Go
1
star