This directory contains Tutor plugin configuration for easy deployment of both backend and frontend plugins in a Tutor-based Open edX deployment.
- Overview
- Plugin Configuration
- Installation Steps
- Development vs Production
- Configuration Options
- Troubleshooting
- Advanced Configuration
This Tutor plugin simplifies the deployment of the sample plugin by:
- Backend Integration: Automatically installs the Django app plugin
- Frontend Integration: Configures MFE slots for the custom components
- Environment Setup: Handles configuration across different deployment environments
- Dependency Management: Ensures all required packages are installed
What is Tutor?: Tutor is the official Docker-based deployment method for Open edX, providing simple commands for installation, configuration, and maintenance.
Official Documentation:
File: sample_plugin.py
The current configuration demonstrates basic Tutor plugin structure:
from tutormfe.hooks import PLUGIN_SLOTS
PLUGIN_SLOTS.add_items([
# Replace the course_list
(
"learner-dashboard",
"custom_course_list",
"""
{
op: PLUGIN_OPERATIONS.Insert,
type: DIRECT_PLUGIN,
priority: 50,
RenderWidget: CourseList
}"""
),
])Note: The current implementation is a basic template. For full functionality, this needs to be expanded with proper backend installation and frontend package management.
A fully functional Tutor plugin should include:
from tutor import hooks
# Plugin metadata
__version__ = "1.0.0"
# Backend plugin installation
@hooks.Filters.IMAGES_BUILD_MOUNTS.add()
def _mount_sample_plugin(mounts):
"""Mount the sample plugin source code for development."""
mounts.append(("sample-plugin-backend", "/openedx/sample-plugin-backend"))
return mounts
@hooks.Filters.LMS_ENV.add()
@hooks.Filters.CMS_ENV.add()
def _add_plugin_settings(env):
"""Add plugin-specific environment variables."""
env["SAMPLE_PLUGIN_ENABLED"] = True
return env
# Install backend plugin
@hooks.Filters.IMAGES_BUILD.add()
def _install_backend_plugin(build_config):
"""Install the backend plugin during image build."""
build_config.add_dockerfile_commands(
"RUN pip install -e /openedx/sample-plugin-backend"
)
return build_config
# Frontend plugin configuration
from tutormfe.hooks import PLUGIN_SLOTS
PLUGIN_SLOTS.add_items([
(
"learner-dashboard",
"course_list_slot",
"""
{
op: PLUGIN_OPERATIONS.Replace,
widget: {
id: 'custom_course_list',
type: DIRECT_PLUGIN,
priority: 50,
RenderWidget: CourseList
}
}"""
),
])- Tutor Installation: Follow Tutor installation guide
- Plugin Source: Have the sample plugin source code available
- Tutor MFE Plugin: Install tutor-mfe plugin if customizing frontend
# Method 1: Install from local directory
pip install -e /path/to/sample-plugin/tutor/
# Method 2: Copy plugin file (simpler for development)
mkdir -p "$(tutor plugins printroot)"
cp sample_plugin.py "$(tutor plugins printroot)/sample_plugin.py"# Enable the plugin
tutor plugins enable sample_plugin
# Verify plugin is enabled
tutor plugins list# For development deployment
tutor dev launch
# For production deployment
tutor local launch# If using tutor-mfe plugin for frontend customization
tutor plugins enable mfe
tutor local launch# Check backend plugin
tutor dev exec lms python manage.py shell -c "from sample_plugin.models import CourseArchiveStatus; print('Backend plugin loaded')"
# Check frontend plugin (visit learner dashboard in browser)
# Should see custom course list with archive functionalityCharacteristics:
- Uses
tutor devcommands - Mounts source code for live editing
- Faster iteration cycles
- Debug logging enabled
Setup Pattern:
# Mount backend plugin source
tutor dev mount /path/to/sample-plugin/backend:/openedx/sample-plugin-backend
# Start development environment
tutor dev launch
# Install plugin in development mode
tutor dev exec lms pip install -e ../sample-plugin-backend
tutor dev exec lms python manage.py migrate
tutor dev restart lmsCharacteristics:
- Uses
tutor localcommands - Builds plugins into Docker images
- Optimized for performance
- Production logging levels
Setup Pattern:
# Enable plugin
tutor plugins enable sample_plugin
# Build and deploy
tutor local launch| Aspect | Development | Production |
|---|---|---|
| Installation | pip install -e (editable) |
Built into image |
| Code Changes | Live reload | Requires rebuild |
| Performance | Slower (debug mode) | Optimized |
| Database | SQLite/development DB | Production database |
| Logging | Verbose | Production level |
# In tutor plugin
@hooks.Filters.LMS_ENV.add()
def _add_backend_settings(env):
"""Configure backend plugin settings."""
env.update({
# Plugin-specific settings
"SAMPLE_PLUGIN_API_RATE_LIMIT": "100/minute",
"SAMPLE_PLUGIN_ARCHIVE_RETENTION": "365",
# Open edX Filters configuration
"OPEN_EDX_FILTERS_CONFIG": {
"org.openedx.learning.course.about.render.started.v1": {
"pipeline": [
"sample_plugin.pipeline.ChangeCourseAboutPageUrl"
],
"fail_silently": False,
}
}
})
return env# Configure MFE slots
PLUGIN_SLOTS.add_items([
(
"learner-dashboard", # Target MFE
"course_list_slot", # Slot identifier
"""
{
op: PLUGIN_OPERATIONS.Replace, // Operation type
widget: {
id: 'custom_course_list', // Unique widget ID
type: DIRECT_PLUGIN, // Plugin type
priority: 50, // Load priority
RenderWidget: CourseList // Component reference
}
}"""
),
])# Different settings for different environments
@hooks.Filters.LMS_ENV.add()
def _configure_by_environment(env):
"""Apply environment-specific configuration."""
if env.get("TUTOR_DEV", False):
# Development settings
env["SAMPLE_PLUGIN_DEBUG"] = True
env["SAMPLE_PLUGIN_API_RATE_LIMIT"] = "1000/minute"
else:
# Production settings
env["SAMPLE_PLUGIN_DEBUG"] = False
env["SAMPLE_PLUGIN_API_RATE_LIMIT"] = "60/minute"
return envPlugin Not Loading:
# Check if plugin is enabled
tutor plugins list
# Check plugin syntax
python -m py_compile sample_plugin.py
# Verify plugin location
tutor plugins printroot
ls -la "$(tutor plugins printroot)/"Backend Plugin Not Installing:
# Check build logs
tutor images build lms
# Manual installation for debugging
tutor dev exec lms pip install -e ../sample-plugin-backend
tutor dev exec lms python -c "import sample_plugin; print('Success')"
# Check migrations
tutor dev exec lms python manage.py showmigrations sample_pluginFrontend Plugin Not Appearing:
# Check MFE configuration
tutor dev exec learner-dashboard env | grep PLUGIN
# Verify plugin slots
tutor dev logs learner-dashboard
# Check browser console for JavaScript errorsSettings Not Applied:
# Check environment variables
tutor dev exec lms env | grep SAMPLE_PLUGIN
# Verify Django settings
tutor dev exec lms python manage.py shell -c "from django.conf import settings; print(getattr(settings, 'SAMPLE_PLUGIN_DEBUG', 'Not set'))"# View plugin configuration
tutor plugins show sample_plugin
# Check generated configuration
tutor config printvalue PLUGINS
# Inspect environment variables
tutor dev exec lms env | grep -E "(SAMPLE_PLUGIN|OPEN_EDX)"
# Check plugin installation
tutor dev exec lms pip list | grep sample
# View logs
tutor dev logs lms
tutor dev logs learner-dashboard- Tutor Documentation: Plugin Development Guide
- Community: Tutor Community Forum
- GitHub: Tutor Repository Issues
# Configure multiple MFEs
PLUGIN_SLOTS.add_items([
# Learner Dashboard
(
"learner-dashboard",
"course_list_slot",
"""{ /* CourseList configuration */ }"""
),
# Course Authoring (if applicable)
(
"course-authoring",
"course_outline_slot",
"""{ /* Course outline customization */ }"""
),
])@hooks.Filters.IMAGES_BUILD.add()
def _build_custom_image(build_config):
"""Build custom image with additional dependencies."""
# Add system packages
build_config.add_dockerfile_commands(
"RUN apt-get update && apt-get install -y your-package"
)
# Install Python packages
build_config.add_dockerfile_commands(
"RUN pip install your-python-package"
)
# Copy additional files
build_config.add_dockerfile_commands(
"COPY custom-config.yml /openedx/config/"
)
return build_config@hooks.Actions.LMS_READY.add()
@hooks.Actions.CMS_READY.add()
def _run_plugin_migrations():
"""Run plugin migrations when platform is ready."""
from django.core.management import call_command
call_command("migrate", "sample_plugin")# In setup.py or pyproject.toml for your Tutor plugin
dependencies = [
"tutor>=15.0.0",
"tutor-mfe", # If using MFE customization
]@hooks.Filters.CONFIG_UNIQUE.add()
def _validate_plugin_config(config):
"""Validate plugin configuration."""
# Check required settings
if not config.get("SAMPLE_PLUGIN_API_KEY"):
raise ValueError("SAMPLE_PLUGIN_API_KEY is required")
# Validate setting values
rate_limit = config.get("SAMPLE_PLUGIN_API_RATE_LIMIT", "60/minute")
if not re.match(r"^\d+/(minute|hour|day)$", rate_limit):
raise ValueError(f"Invalid rate limit format: {rate_limit}")
return configThis Tutor plugin configuration provides a foundation for deploying the sample plugin in production Open edX environments. The modular approach allows you to adapt the configuration for different deployment scenarios while maintaining consistency across environments.