Files
DamarKusumo 2b7027e37d Add openedx-tenant-api plugin
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 08:20:57 +07:00
..
2026-04-10 08:20:57 +07:00
2026-04-10 08:20:57 +07:00
2026-04-10 08:20:57 +07:00
2026-04-10 08:20:57 +07:00
2026-04-10 08:20:57 +07:00

Open edX Tenant API

REST API for programmatic tenant creation in Open edX with eox-tenant.

Features

  • Create tenants with automatic MFE configuration
  • List all provisioned tenants
  • Delete tenants
  • Health check endpoint
  • Audit logging of all tenant operations

Installation

1. Add to Tutor Config

Edit your Tutor config.yml:

MOUNTS:
  - /path/to/openedx-tenant-api

OPENEDX_EXTRA_PIP_REQUIREMENTS:
  - -e /mnt/openedx-tenant-api

2. Restart LMS

tutor dev restart lms

3. Install Package and Run Migrations

# Install in running container
docker exec tutor_dev-lms-1 sh -c "pip install -e /mnt/openedx-tenant-api --no-build-isolation"

# Create migrations
docker exec tutor_dev-lms-1 sh -c "cd /openedx/edx-platform && python manage.py lms makemigrations openedx_tenant_api"

# Run migrations
docker exec tutor_dev-lms-1 sh -c "cd /openedx/edx-platform && python manage.py lms migrate openedx_tenant_api"

API Endpoints

Endpoint Method Auth Required Description
/api/tenant/v1/health GET No Health check
/api/tenant/v1/list GET Yes (Admin) List all tenants
/api/tenant/v1/create POST Yes (Admin) Create new tenant
/api/tenant/v1/delete/{tenant_name} DELETE Yes (Admin) Delete tenant

Usage

Health Check

curl http://local.openedx.io:8000/api/tenant/v1/health

Response:

{
  "status": "healthy",
  "eox_tenant_installed": true,
  "tenant_count": 2
}

Create Tenant

Requires admin user authentication. Supports Basic Auth, JWT Bearer, or Session auth.

import requests

# Using Basic Authentication (simplest)
response = requests.post(
    'http://local.openedx.io:8000/api/tenant/v1/create',
    auth=('admin', 'your-password'),
    json={
        'tenant_name': 'talent1',
        'platform_name': 'Talent 1 Learning',
        'theme_name': 'indigo',
        'org_filter': ['org1']  # Optional
    }
)

print(response.json())
# Using cURL with Basic Auth
curl -X POST http://local.openedx.io:8000/api/tenant/v1/create \
  -u admin:your-password \
  -H "Content-Type: application/json" \
  -d '{
    "tenant_name": "talent1",
    "platform_name": "Talent 1 Learning",
    "theme_name": "indigo"
  }'

Response:

{
  "status": "success",
  "tenant_id": 123,
  "tenant_name": "talent1",
  "lms_url": "http://talent1.local.openedx.io:8000",
  "authn_url": "http://talent1.apps.local.openedx.io:1999/authn",
  "learner_dashboard_url": "http://talent1.apps.local.openedx.io:1996/learner-dashboard/",
  "message": "Tenant created successfully. Add DNS entries to your hosts file."
}

List Tenants

import requests

response = requests.get(
    'http://local.openedx.io:8000/api/tenant/v1/list',
    headers={'Authorization': 'Bearer YOUR_TOKEN'}
)

print(response.json())

Delete Tenant

import requests

response = requests.delete(
    'http://local.openedx.io:8000/api/tenant/v1/delete/talent1',
    headers={'Authorization': 'Bearer YOUR_TOKEN'}
)

print(response.json())

Testing via Django Shell

For testing without authentication:

docker exec tutor_dev-lms-1 sh -c "cd /openedx/edx-platform && python manage.py lms shell" << 'EOF'
import django
django.setup()

from django.db import transaction
from django.contrib.auth import get_user_model
from eox_tenant.models import TenantConfig, Route

User = get_user_model()
admin = User.objects.filter(is_superuser=True).first()

tenant_name = 'talent1'
platform_name = 'Talent 1 Learning'
theme_name = 'indigo'

external_key = f'{tenant_name}.local.openedx.io'
lms_domain = f'{tenant_name}.local.openedx.io'

# Generate MFE config
lms_configs = {
    'LMS_BASE': f'{lms_domain}:8000',
    'SITE_NAME': lms_domain,
    'PLATFORM_NAME': platform_name,
    'THEME_NAME': theme_name,
    'BASE_URL': f'http://{tenant_name}.apps.local.openedx.io',
    'LMS_BASE_URL': f'http://{lms_domain}:8000',
    'LEARNER_HOME_MICROFRONTEND_URL': f'http://{tenant_name}.apps.local.openedx.io:1996/learner-dashboard/',
    'AUTHN_MICROFRONTEND_URL': f'http://{tenant_name}.apps.local.openedx.io:1999/authn',
    # ... add other MFE URLs as needed
}

with transaction.atomic():
    tenant_config = TenantConfig.objects.create(
        external_key=external_key,
        lms_configs=lms_configs,
        theming_configs={'THEME_NAME': theme_name},
        meta={'created_by': admin.username}
    )
    Route.objects.create(domain=lms_domain, config=tenant_config)
    print(f'Tenant {tenant_name} created!')
EOF

Hosts File Configuration

After creating a tenant, add these entries to your hosts file:

127.0.0.1  talent1.local.openedx.io
127.0.0.1  talent1.apps.local.openedx.io
127.0.0.1  studio.talent1.local.openedx.io

MFE Configuration

The API automatically generates MFE URLs for the tenant:

  • Authn: http://{tenant}.apps.local.openedx.io:1999/authn
  • Learner Dashboard: http://{tenant}.apps.local.openedx.io:1996/learner-dashboard/
  • Account: http://{tenant}.apps.local.openedx.io:1997/account/
  • Profile: http://{tenant}.apps.local.openedx.io:1995/profile/u/
  • Learning: http://{tenant}.apps.local.openedx.io:2000/learning
  • Discussions: http://{tenant}.apps.local.openedx.io:2002/discussions
  • Gradebook: http://{tenant}.apps.local.openedx.io:1994/gradebook
  • Communications: http://{tenant}.apps.local.openedx.io:1984/communications
  • ORA Grading: http://{tenant}.apps.local.openedx.io:1993/ora-grading
  • Admin Console: http://{tenant}.apps.local.openedx.io:2025/admin-console
  • Course Authoring: http://{tenant}.apps.local.openedx.io:2001/authoring

Architecture

┌─────────────────┐     ┌──────────────────┐     ┌─────────────────┐
│   External App  │────▶│  Tenant API      │────▶│  eox-tenant     │
│   (Your System) │     │  (Django REST)   │     │  (TenantConfig) │
└─────────────────┘     └──────────────────┘     └─────────────────┘
                                │
                                ▼
                        ┌──────────────────┐
                        │  TenantProvisioningLog  │
                        │  (Audit Trail)   │
                        └──────────────────┘

License

MIT