- Python 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| modules | ||
| README.md | ||
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
shortnamewhen 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:
- The API token is associated with the expected Moodle user.
- The token uses the correct external service.
- The required function has been added to the external service.
- The Moodle user has the required capabilities.
- The user is allowed to access the relevant course/category.
- The external service is enabled.
- 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:
- Name it
moodle_<resource>.py(e.g.moodle_cohorts.py) and place it inmodules/. - Reuse the existing
MoodleAPI/MoodleAPIErrorpattern (a small stdlib-only REST client) rather than introducing new HTTP dependencies. - Support
check_modeand idempotent create/update behaviour, matching resources by their natural Moodle key (e.g.shortname,username) rather than internal IDs. - Reuse the same
host,api_key,timeout, andvalidate_certsparameters and semantics as the existing modules. - 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.
- Document the new module in this README: add it to Available Modules, give it its own
## Featuresand## Variablessubsection, and extend the Example Playbook if useful.
Author
- Florian Paul Azim Hoberg @gyptazy (florian.hoberg@credativ.de / gyptazy@gyptazy.com)
Contributing
Contributions, bug reports, and improvements are welcome.
When submitting changes:
- Keep modules compatible with supported Ansible versions.
- Preserve existing module parameters unless there is a strong reason to change them.
- Add or update documentation for new parameters or new modules.
- Test changes against a real Moodle instance where possible.
- Do not include API tokens, passwords, or other credentials in commits.