Example – Simple module

To demonstrate the ease of writing Python-based modules, let's create a simple module. The purpose of this module will be to remotely copy a source file to a destination file, a simple task that we can build up from. To start our module, we need to create the module file. For easy access to our new module, we'll create the file in the library/ subdirectory of the working directory we've already been using. We'll call this module remote_copy.py, and to start it off, we'll need to put in a sha-bang line to indicate that this module is to be executed with Python:

#!/usr/bin/python 
# 

For Python-based modules, the convention is to use /usr/bin/python as the listed executable. When executed on a remote system, the configured Python interpreter for the remote host is used to execute the module, so fret not if your Python doesn't exist in this path. Next, we'll import a Python library we'll use later in the module, called shutil:

import shutil 

Now we're ready to create our main function. The main function is essentially the entry point to the module, where the arguments to the module will be defined and where the execution will start. When creating modules in Python, we can take some shortcuts in this main function to bypass a lot of boilerplate code and get straight to the argument definitions.

We do this by creating an AnsibleModule object and giving it an argument_spec dictionary for the arguments:

def main(): 
    module = AnsibleModule( 
        argument_spec = dict( 
            source=dict(required=True, type='str'), 
            dest=dict(required=True, type='str') 
        ) 
    ) 

In our module, we're providing two arguments. The first argument is source, which we'll use to define the source file for the copy. The second argument is dest, the destination for the copy. Both of these arguments are marked as required, which will raise an error when executed if one of the two is not provided. Both arguments are of the type string. The location of the AnsibleModule class has not yet been defined, as that happens later in the file.

With a module object at our disposal, we can now create the code that will do the actual work on the remote host. We'll make use of shutil.copy and our provided arguments to accomplish the copy:

    shutil.copy(module.params['source'], 
                module.params['dest']) 

The shutil.copy function expects a source and a destination, which we've provided by accessing module.params. The module.params dictionary holds all of the parameters for the module. Having completed the copy, we are now ready to return the results to Ansible. This is done via another AnsibleModule method, exit_json. This method expects a set of key=value arguments and will format it appropriately for a JSON return. Since we're always performing a copy, we will always return a change for simplicity's sake:

    module.exit_json(changed=True) 

This line will exit the function, and thus the module. This function assumes a successful action and will exit the module with the appropriate return code for success: 0. We're not done with our module's code though; we still have to account for the AnsibleModule location. This is where a bit of magic happens, where we tell Ansible what other code to combine with our module to create a complete work that can be transported:

from ansible.module_utils.basic import * 

That's all it takes! That one line gets us access to all of the basic module_utils, a decent set of helper functions and classes. There is one last thing we should put into our module: a couple of lines of code telling the interpreter to execute the main() function when the module file is executed:

if __name__ == '__main__': 
    main() 

Now our module file is complete and we can test it with a playbook. We'll call our playbook simple_module.yaml and store it in the same directory as the library/ directory, where we've just written our module file. We'll run the play on localhost for simplicity's sake and use a couple of filenames in /tmp for the source and destination. We'll also use a task to ensure that we have a source file to begin with:

--- 
- name: test remote_copy module 
  hosts: localhost 
  gather_facts: false 
 
  tasks: 
  - name: ensure foo
file:
path: /tmp/rcfoo
state: touch

- name: do a remote copy
remote_copy:
source: /tmp/rcfoo
dest: /tmp/rcbar

To run this playbook, we'll reference our mastery-hosts file. If the remote_copy module file is written to the correct location, everything will work just fine, and the screen output will look as follows:

Our first task touches the /tmp/rcfoo path to ensure that it exists, and then our second task makes use of remote_copy to copy /tmp/rcfoo to /tmp/rcbar. Both tasks are successful, resulting in a change each time.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.136.233.153