Passer au contenu principal

Expertise (Ansible)

Modules et plugins custom

Les modules communautaires couvrent la majorité des besoins. Il arrive cependant qu'une API interne ou une logique métier complexe nécessite un module sur mesure.

Structure d'un module Python

#!/usr/bin/python
# library/my_module.py
from ansible.module_utils.basic import AnsibleModule

def run_module():
    argument_spec = dict(
        name=dict(type="str", required=True),
        state=dict(type="str", default="present", choices=["present", "absent"]),
        url=dict(type="str", required=True),
        token=dict(type="str", required=True, no_log=True),
    )
    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)
    name = module.params["name"]
    state = module.params["state"]

    # Vérifier l'état actuel (idempotence)
    current = get_resource(module.params["url"], name)

    if state == "present" and current is None:
        if module.check_mode:
            module.exit_json(changed=True, msg=f"Would create {name}")
        create_resource(module.params["url"], name)
        module.exit_json(changed=True, msg=f"Created {name}")
    elif state == "absent" and current is not None:
        if module.check_mode:
            module.exit_json(changed=True, msg=f"Would delete {name}")
        delete_resource(module.params["url"], name)
        module.exit_json(changed=True, msg=f"Deleted {name}")
    else:
        module.exit_json(changed=False)

if __name__ == "__main__":
    run_module()

Placer dans library/ au niveau du projet. Disponible immédiatement dans les playbooks.

Filter plugins

# filter_plugins/my_filters.py
def mask_secret(value, visible=4):
    if len(value) <= visible:
        return "*" * len(value)
    return "*" * (len(value) - visible) + value[-visible:]

class FilterModule:
    def filters(self):
        return {"mask_secret": mask_secret}
{{ db_password | mask_secret(visible=4) }}

Lookup plugins

# lookup_plugins/internal_vault.py
from ansible.plugins.lookup import LookupBase

class LookupModule(LookupBase):
    def run(self, terms, variables=None, **kwargs):
        return [fetch_secret(term) for term in terms]
- ansible.builtin.set_fact:
    db_password: "{{ lookup('internal_vault', 'myapp/db_password') }}"

Tests unitaires

# Test rapide
python library/my_module.py <<< '{"ANSIBLE_MODULE_ARGS": {"name": "test", "state": "present", "url": "http://api", "token": "tok"}}'

# Tests formels
ansible-test units --python 3.11