Ansible modules for Moodle which allows operators to manage Users, Courses and course assignments.
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-21 13:16:50 +02:00
modules add initial moodle modules for Ansible 2026-09-21 13:16:50 +02:00
README.md add initial moodle modules for Ansible 2026-09-21 13:16:50 +02:00

Ansible Moodle Modules

A growing collection of Ansible modules for managing Moodle through the Moodle Web Services REST API.

Each module focuses on a single Moodle resource (users, courses, ...) and follows the same design: a small stdlib-only REST client, idempotent create/update behaviour, and full check_mode support. The collection is built to grow — new resources (cohorts, groups, roles, ...) can be added as additional moodle_* modules without changing how existing modules work.

Available Modules

Module Description
moodle_users Create/update Moodle users, reset passwords, enrol into courses
moodle_courses Create/update/delete Moodle courses, manage categories and customized topics/sections with content

More modules may be added over time (see Adding New Modules).

Features

moodle_users

  • Create Moodle users through the Moodle REST API
  • Update existing Moodle users
  • Search for existing users
  • Reset user passwords
  • Assign users to Moodle courses
  • Check existing course enrolments
  • Use Moodle course shortname when assigning courses

moodle_courses

  • Create, update, and delete Moodle courses
  • Assign a course to a category by name or ID
  • Configure course format, visibility, start date, and summary
  • Define customized topics/sections, each with its own name and HTML content
  • Idempotent updates: only changed fields/topics are pushed to Moodle

Shared

  • Support Moodle API authentication using a web service token
  • Full check_mode (dry-run) support
  • Designed for use with Ansible playbooks and roles

Requirements

  • Ansible
  • Python 3
  • A running Moodle instance
  • Moodle REST Web Services enabled
  • A Moodle external service
  • A Moodle web service token
  • A Moodle user with the required capabilities

Moodle Configuration

The modules communicate with Moodle through the REST API.

Before using any module, REST Web Services must be enabled and an external service must be configured.

Enable Web Services

In Moodle, navigate to:

Site administration
  -> Advanced features
  -> Enable web services

Enable web services if they are not already enabled.

Enable REST Protocol

Navigate to:

Site administration
  -> Plugins
  -> Web services
  -> Protocols

Enable:

REST protocol

Create an External Service

Navigate to:

Site administration
  -> Plugins
  -> Web services
  -> External services

Create or use a single external service shared by all moodle_* modules, for example:

api

The service must contain the functions listed below for every module you intend to use. There is no need to create a separate service per module — add the functions for whichever modules you use to the same service.

Required Moodle Web Service Functions

The following functions must be added to the external service. The "Used by" column indicates which module(s) require the function, so you only need to enable the rows relevant to the modules you actually use.

Function Used by Description Required Capability
core_course_get_courses_by_field users, courses Get courses matching a specific field such as ID, shortname, ID number, or category None
core_course_get_categories courses Search Moodle categories None
core_course_create_courses courses Create new courses moodle/course:create
core_course_update_courses courses Update existing courses, including format options such as number of sections moodle/course:update, moodle/course:changecategory, moodle/course:changefullname
core_course_delete_courses courses Delete courses moodle/course:delete
core_course_get_contents courses Get a course's sections/topics and their content moodle/course:update
core_course_edit_section courses Update a section/topic's name and summary/content moodle/course:update
core_enrol_get_enrolled_users users Get enrolled users by course ID moodle/user:viewdetails, moodle/user:viewhiddendetails, moodle/course:useremail, moodle/user:update, moodle/site:accessallgroups
core_enrol_get_enrolled_users_with_capability users Return enrolled users with a specified capability None
core_get_user_dates users Return formatted timestamps None
core_user_create_users users Create users moodle/user:create
core_user_get_course_user_profiles users Get course user profiles moodle/user:viewdetails, moodle/user:viewhiddendetails, moodle/course:useremail, moodle/user:update, moodle/site:accessallgroups
core_user_get_users users Search for users matching parameters moodle/user:viewdetails, moodle/user:viewhiddendetails, moodle/course:useremail, moodle/user:update
core_user_get_users_by_field users Retrieve users using a unique field moodle/user:viewdetails, moodle/user:viewhiddendetails, moodle/course:useremail, moodle/user:update
core_user_update_user_device_public_key users Store a mobile user public key None
core_user_update_user_preferences users Update user preferences moodle/user:editownmessageprofile, moodle/user:editmessageprofile
core_user_update_users users Update users moodle/user:update
core_webservice_get_site_info users, courses Return site and user information and available web service functions None
enrol_manual_enrol_users users Manually enrol users into courses enrol/manual:enrol

The exact capabilities required depend on the Moodle version and the permissions assigned to the user associated with the API token.

Moodle Role Permissions

The Moodle user used by the API token must have the permissions required by the functions above.

At minimum, the following capabilities are required:

moodle/user:create
moodle/user:update
enrol/manual:enrol
moodle/course:create
moodle/course:update
moodle/course:delete

Only include moodle/course:* capabilities if you intend to use moodle_courses, and only include the user/enrolment capabilities if you intend to use moodle_users.

Depending on the Moodle configuration and the functions being used, additional user-view and course permissions may be required.

The easiest way to verify the permissions is to inspect the role assigned to the API user:

Site administration
  -> Users
  -> Permissions
  -> Define roles

Select the role assigned to the API user and verify the required capabilities.

Create a Moodle Token

Navigate to:

Site administration
  -> Plugins
  -> Web services
  -> Manage tokens

Create a token for the Moodle user and select the external service configured above.

For example:

Service: api
User: ansible

Store the generated token securely.

It is recommended to use Ansible Vault rather than storing the API token directly in a playbook.

Example:

moodle_api_key: "..."

The value can then be encrypted using Ansible Vault. The same token and external service can be reused across all moodle_* modules.

Installation

Place the modules in the Ansible module path of your project.

For example:

library/
├── moodle_users.py
└── moodle_courses.py

A possible Ansible project structure:

.
├── inventory
├── group_vars
│   └── all.yml
├── library
│   ├── moodle_users.py
│   └── moodle_courses.py
├── roles
│   └── moodle
│       └── tasks
│           └── main.yml
└── site.yml

Ansible automatically searches the local library/ directory for custom modules.

You can verify that Ansible can find the modules with:

ansible-doc moodle_users
ansible-doc moodle_courses

Usage

moodle_users

- name: Create user with additional information
  moodle_users:
    host: "https://moodle.gyptazy.com"
    validate_certs: false
    api_key: "{{ moodle_api_key }}"
    user: "{{ user }}"
    password: "{{ password }}"
    firstname: "{{ user_firstname }}"
    lastname: "{{ user_lastname }}"
    email: "{{ email }}"
    course: "proxmox-training"

If the specified user does not exist, the module creates the user and assigns the user to the specified course.

moodle_courses

- name: Create a course with customized topics
  moodle_courses:
    host: "https://moodle.gyptazy.com"
    validate_certs: false
    api_key: "{{ moodle_api_key }}"
    shortname: "proxmox-training"
    fullname: "Proxmox VE Training"
    category: "Virtualization"
    summary: "Introduction into Proxmox VE."
    topics:
      - name: "Introduction"
        content: "<p>Welcome to the Proxmox VE training.</p>"
      - name: "Installation"
        content: "<p>How to install Proxmox VE on bare metal.</p>"

If the specified course does not exist, the module creates it in the given category with the given topics/sections. On subsequent runs, only fields and topics that actually differ are updated.

Both modules communicate with Moodle using the configured REST API token and can be combined in the same playbook, typically creating the course first and then creating/enrolling users into it.

Variables

moodle_users

Parameter Required Description
host Yes Moodle base URL
api_key Yes Moodle REST API token
user Yes Moodle username
password Yes Password for the Moodle user
firstname No User's first name (default: Moodle)
lastname No User's last name (default: User)
email No User's email address
email_domain No Default email domain when email is not set
course No Moodle course shortname used for enrolment
reset No Reset the password when the user already exists (default: false)
roleid No Moodle role ID used for course enrolment (default: 5)
timeout No HTTP request timeout in seconds (default: 30)
validate_certs No Whether TLS certificates should be validated

moodle_courses

Parameter Required Description
host Yes Moodle base URL
api_key Yes Moodle REST API token
shortname Yes Moodle course shortname, used as the idempotency key
fullname No Full display name of the course (required when creating a course)
category No Category name to place the course in (mutually exclusive with categoryid)
categoryid No Category ID to place the course in (mutually exclusive with category)
summary No Course summary/description
format No Moodle course format (default: topics)
visible No Whether the course is visible to students (default: true)
startdate No Course start date as a unix timestamp
topics No List of {name, content} dicts defining the course's topics/sections
state No present or absent (default: present)
timeout No HTTP request timeout in seconds (default: 30)
validate_certs No Whether TLS certificates should be validated

Shared parameter notes

host

The base URL of the Moodle instance.

host: "https://moodle.example.com"

api_key

The Moodle Web Service token.

api_key: "{{ moodle_api_key }}"

The token should preferably be stored in Ansible Vault.

validate_certs

Controls TLS certificate validation.

validate_certs: true

For production environments, certificate validation should normally remain enabled. For development or testing environments, it can be disabled:

validate_certs: false

moodle_courses-specific notes

category / categoryid

Either the category name or its numeric ID can be used to place the course. Only one of the two may be set.

category: "Virtualization"
categoryid: 3

topics

Each entry defines one topic/section, matched to Moodle sections by position (the first entry becomes section 1, etc. — section 0 is Moodle's general/announcements section and is left untouched).

topics:
  - name: "Introduction"
    content: "<p>Welcome to the training.</p>"
  - name: "Advanced Topics"
    content: "<p>Deep-dive material.</p>"

state

Set to absent to delete a course by shortname:

state: absent

Example Playbook

A complete example combining both modules — creating a course and then a user enrolled into it:

---
- name: Manage Moodle courses and users
  hosts: localhost
  gather_facts: false

  vars:
    moodle_host: "https://moodle.example.com"
    moodle_api_key: "{{ vault_moodle_api_key }}"

  tasks:
    - name: Create Moodle course with customized topics
      moodle_courses:
        host: "{{ moodle_host }}"
        validate_certs: true
        api_key: "{{ moodle_api_key }}"
        shortname: "proxmox-training"
        fullname: "Proxmox VE Training"
        category: "Virtualization"
        summary: "Introduction into Proxmox VE."
        topics:
          - name: "Introduction"
            content: "<p>Welcome to the Proxmox VE training.</p>"
          - name: "Installation"
            content: "<p>How to install Proxmox VE on bare metal.</p>"

    - name: Create Moodle user and enrol into course
      moodle_users:
        host: "{{ moodle_host }}"
        validate_certs: true
        api_key: "{{ moodle_api_key }}"
        user: "john.doe"
        password: "{{ vault_moodle_user_password }}"
        firstname: "John"
        lastname: "Doe"
        email: "john.doe@example.com"
        course: "proxmox-training"

Ansible Vault

Sensitive values such as the Moodle API token and user passwords should not be stored in plaintext.

Create an encrypted variables file:

ansible-vault create group_vars/all/vault.yml

Example:

vault_moodle_api_key: "your-moodle-api-token"
vault_moodle_user_password: "your-user-password"

Use the variables from the playbook:

api_key: "{{ vault_moodle_api_key }}"
password: "{{ vault_moodle_user_password }}"

Run the playbook with:

ansible-playbook site.yml --ask-vault-pass

Troubleshooting

Access control exception (accessexception)

Example:

Moodle API error: Access control exception (accessexception)

This usually indicates that the Moodle user associated with the API token does not have sufficient permissions to execute the requested web service function.

Check:

  1. The API token is associated with the expected Moodle user.
  2. The token uses the correct external service.
  3. The required function has been added to the external service.
  4. The Moodle user has the required capabilities.
  5. The user is allowed to access the relevant course/category.
  6. The external service is enabled.
  7. REST Web Services are enabled.

The most important permissions per module:

# moodle_users
moodle/user:create
moodle/user:update
enrol/manual:enrol

# moodle_courses
moodle/course:create
moodle/course:update
moodle/course:delete

HTTP 403

Example:

Moodle HTTP error 403

A HTTP 403 can indicate that the request is being rejected before or during Moodle's Web Service authorization.

Check the API endpoint and token.

The REST endpoint normally has the following format:

https://moodle.example.com/webservice/rest/server.php

Verify that the token is passed as:

wstoken=<token>

and that the requested function is passed as:

wsfunction=<function>

Function not found

If Moodle returns an error indicating that a function is unavailable, verify that the function has been added to the external service.

Navigate to:

Site administration
  -> Plugins
  -> Web services
  -> External services

Select the service and inspect its functions.

For this collection, make sure the required functions listed in the Required Moodle Web Service Functions section are present for the module(s) you are using.

Course cannot be found

The course (in moodle_users) or shortname (in moodle_courses) parameter should contain the Moodle course shortname.

For example:

course: "proxmox-training"
shortname: "proxmox-training"

Verify the course shortname in Moodle rather than using the course's display name.

Category cannot be found

The category parameter in moodle_courses must match the category's exact name in Moodle. If the category name is uncertain or shared across multiple categories, use categoryid instead.

Testing the Moodle API

The Moodle REST API can be tested independently of Ansible with curl.

Example:

curl -s \
  -X POST \
  "https://moodle.example.com/webservice/rest/server.php" \
  --data-urlencode "wstoken=${MOODLE_API_KEY}" \
  --data-urlencode "wsfunction=core_course_get_courses_by_field" \
  --data-urlencode "moodlewsrestformat=json" \
  --data-urlencode "field=shortname" \
  --data-urlencode "value=proxmox-training"

This is useful for determining whether an issue is caused by Moodle permissions/API configuration or by an Ansible module itself.

Security Considerations

The Moodle API token provides access to the functions assigned to the external service.

For production deployments:

  • Use a dedicated Moodle API user.
  • Grant only the required capabilities.
  • Grant only the required web service functions.
  • Store API tokens in Ansible Vault or another secret-management system.
  • Use HTTPS.
  • Keep validate_certs: true.
  • Avoid printing API tokens or passwords in Ansible output.
  • Do not commit API tokens or passwords to Git.

API Workflow

The modules use the Moodle REST API to perform the following general workflows:

Ansible
   |
   v
moodle_users Ansible module
   |
   v
Moodle REST API
   |
   +--> Search existing user
   |
   +--> Create/update user
   |
   +--> Find course by shortname
   |
   +--> Check course enrolment
   |
   +--> Enrol user
   |
   v
Moodle
Ansible
   |
   v
moodle_courses Ansible module
   |
   v
Moodle REST API
   |
   +--> Resolve category (by name or ID)
   |
   +--> Find course by shortname
   |
   +--> Create/update/delete course
   |
   +--> Get course sections/topics
   |
   +--> Create/update topics (name + content)
   |
   v
Moodle

Adding New Modules

This repository is intended to grow into a small suite of Moodle modules beyond users and courses (for example cohorts, groups, or roles). When adding a new module:

  1. Name it moodle_<resource>.py (e.g. moodle_cohorts.py) and place it in modules/.
  2. Reuse the existing MoodleAPI/MoodleAPIError pattern (a small stdlib-only REST client) rather than introducing new HTTP dependencies.
  3. Support check_mode and idempotent create/update behaviour, matching resources by their natural Moodle key (e.g. shortname, username) rather than internal IDs.
  4. Reuse the same host, api_key, timeout, and validate_certs parameters and semantics as the existing modules.
  5. Add the module's required web service functions to the Required Moodle Web Service Functions table, tagging them with the new module name in the "Used by" column.
  6. Document the new module in this README: add it to Available Modules, give it its own ## Features and ## Variables subsection, and extend the Example Playbook if useful.

Author

Contributing

Contributions, bug reports, and improvements are welcome.

When submitting changes:

  1. Keep modules compatible with supported Ansible versions.
  2. Preserve existing module parameters unless there is a strong reason to change them.
  3. Add or update documentation for new parameters or new modules.
  4. Test changes against a real Moodle instance where possible.
  5. Do not include API tokens, passwords, or other credentials in commits.