Features
Environments
Clone Environment

Environment Cloning with Sanitization

Environment cloning allows you to duplicate entire Odoo environments, including database, filestore, and source code, with powerful data sanitization capabilities to protect sensitive information when creating staging or development environments.

Overview

The cloning system provides:

  • Complete Environment Duplication: Database, filestore, custom addons, and configuration
  • Data Sanitization Presets: Pre-configured sanitization levels for different use cases
  • Cross-Server Cloning: Clone environments to different servers within your organization
  • Granular Control: 15+ sanitization options with impact previews
  • Background Processing: Asynchronous cloning with real-time progress tracking
  • Automatic Verification: Post-clone validation to ensure successful duplication

Common Use Cases

  1. Production to Staging: Clone production with sanitized data for testing
  2. Staging to Development: Create development environments from staging
  3. Testing Scenarios: Duplicate environments for testing upgrades or migrations
  4. Training Environments: Create isolated environments with anonymized data
  5. Disaster Recovery: Quick environment restoration with data protection

Cloning Workflow

Step-by-Step Process

The clone operation follows a 10-step process:

  1. Pre-Checks (2%)

    • Resource availability validation
    • Quota checks (CPU, RAM, disk, environment count)
    • Server connectivity verification
    • Permission validation
  2. Source Validation (5%)

    • Verify source environment is running or stopped
    • Check container and database exist
    • Validate environment is deployed
  3. Target Creation (10%)

    • Create new environment record or prepare existing target
    • Generate unique subdomain for new environments
    • Allocate resources from quota
  4. Copying Addons (18%)

    • Copy custom Odoo modules from source to target
    • Handle same-server (cp) and cross-server (tar transfer) scenarios
    • Preserve file permissions and ownership
  5. Database Backup (25%)

    • Execute pg_dump on source PostgreSQL container
    • Create compressed dump file (-Fc -Z9 format)
    • Store dump path for restore phase
  6. Filestore Backup (40%)

    • Archive source filestore using tar/gzip
    • Verify archive integrity
    • Handle missing filestore gracefully
  7. Database Restore (55%)

    • Transfer dump to target server (if cross-server)
    • Create target database
    • Execute pg_restore with --no-owner --no-acl
    • Handle restoration warnings vs errors
  8. Filestore Restore (70%)

    • Transfer filestore archive to target (if cross-server)
    • Extract to target container's /var/lib/odoo/filestore/
    • Rename filestore directory if database names differ
    • Set correct ownership (odoo:odoo) and permissions
  9. Data Sanitization (85%)

    • Apply selected sanitization options via SQL
    • Execute Odoo-specific data masking
    • Track execution results and affected rows
    • Always clear asset bundles (required after clone)
  10. Verification (95%)

    • Verify target container is running
    • Check database connectivity
    • Validate key Odoo tables exist (res_users, ir_module_module)
    • Count active users
  11. Completion (100%)

    • Mark environment as active and running
    • Send notification to user
    • Broadcast completion event via SSE

UI Workflow

From the environment list or detail page:

  1. Click Clone button on the environment card
  2. Configure clone settings:
    • Target Name: Name for the cloned environment
    • Environment Type: Development, Staging, or Production
    • Target Server: Same server or select compatible server
    • Domain: Optional custom domain
  3. Select Sanitization Preset:
    • Recommended (default)
    • Minimal
    • Full
    • None
  4. (Optional) Customize sanitization options
  5. Review impact preview showing affected record counts
  6. Click Start Clone
  7. Monitor real-time progress in the clone operation modal
  8. Receive notification on completion

Sanitization Presets

The system provides four preset configurations optimized for different scenarios.

Recommended (Default)

Best for: Production → Staging clones

Safe defaults that prevent data leaks while preserving functionality for testing.

Enabled Options (12):

  • Disable outgoing mail servers
  • Clear mail queue
  • Anonymize customer emails
  • Anonymize phone numbers
  • Clear API keys and secrets
  • Clear OAuth provider credentials
  • Clear payment provider credentials
  • Clear OAuth access tokens
  • Clear webhook URLs
  • Clear integration credentials
  • Update base URL to staging domain
  • Clear asset bundles (required)

Impact:

  • Prevents accidental emails to real customers
  • Removes production credentials
  • Anonymizes customer PII
  • Preserves user accounts for testing
{
  "disable_mail_servers": true,
  "clear_mail_queue": true,
  "anonymize_emails": true,
  "anonymize_phones": true,
  "clear_api_keys": true,
  "clear_oauth_providers": true,
  "clear_payment_providers": true,
  "clear_oauth_tokens": true,
  "clear_webhook_urls": true,
  "clear_integration_credentials": true,
  "update_base_url": true,
  "clear_asset_bundles": true
}

Minimal

Best for: Quick staging clones where data is already sanitized

Only prevents email sending and clears asset bundles.

Enabled Options (3):

  • Disable outgoing mail servers
  • Clear mail queue
  • Clear asset bundles (required)

Impact:

  • Prevents emails only
  • Keeps all other data intact
  • Fastest sanitization (< 5 seconds)
{
  "disable_mail_servers": true,
  "clear_mail_queue": true,
  "clear_asset_bundles": true
}

Full

Best for: Development environments requiring maximum data protection

All 15+ sanitization options enabled.

Enabled Options (All):

  • All options from Recommended preset
  • Disable email templates
  • Anonymize addresses
  • Anonymize company names
  • Reset user passwords to known value
  • Disable 2FA/TOTP
  • Disable scheduled actions (crons)
  • Clear scheduled messages

Impact:

  • Maximum data protection
  • All credentials removed
  • All PII anonymized
  • Cron jobs disabled
  • User passwords reset to staging123
{
  "disable_mail_servers": true,
  "clear_mail_queue": true,
  "disable_mail_templates": true,
  "anonymize_emails": true,
  "anonymize_phones": true,
  "anonymize_addresses": true,
  "anonymize_company_names": true,
  "clear_api_keys": true,
  "update_base_url": true,
  "reset_passwords": true,
  "reset_password_value": "staging123",
  "disable_2fa": true,
  "disable_crons": true,
  "clear_scheduled_messages": true,
  "clear_asset_bundles": true
}

None

Best for: Exact production replica (use with caution)

No sanitization applied (except asset bundles which are always cleared).

Enabled Options (1):

  • Clear asset bundles (required)

Impact:

  • Identical copy of production
  • All credentials active
  • Risk of data leaks
  • Use only in secure, isolated environments
{
  "clear_asset_bundles": true
}

Sanitization Options Reference

Email & Communications

Disable Outgoing Mail Servers

  • Priority: HIGH
  • Category: Email
  • Default: Enabled in Recommended
  • SQL: UPDATE ir_mail_server SET active = false;
  • Impact: Disables all outgoing SMTP servers to prevent sending real emails
  • Use Case: Essential for staging to avoid customer contact

Clear Mail Queue

  • Priority: HIGH
  • Category: Email
  • Default: Enabled in Recommended
  • SQL: DELETE FROM mail_mail WHERE state IN ('outgoing', 'exception');
  • Impact: Deletes pending and failed emails
  • Use Case: Remove queued production emails

Disable Mail Templates

  • Priority: LOW
  • Category: Email
  • Default: Disabled
  • SQL: UPDATE mail_template SET active = false WHERE active = true;
  • Impact: Deactivates all email templates
  • Use Case: Extra protection against template-based emails

Customer Data

Anonymize Customer Emails

  • Priority: HIGH
  • Category: Customer Data
  • Default: Enabled in Recommended
  • SQL:
    UPDATE res_partner SET
      email = CONCAT('user_', id, '@staging.local')
    WHERE email IS NOT NULL
      AND id NOT IN (SELECT partner_id FROM res_users WHERE active = true);
  • Impact: Replaces customer emails with user_123@staging.local format
  • Note: Preserves emails of active Odoo users for login
  • Use Case: Prevent accidental customer emails, GDPR compliance

Anonymize Phone Numbers

  • Priority: MEDIUM
  • Category: Customer Data
  • Default: Enabled in Recommended
  • SQL:
    UPDATE res_partner SET
      phone = CONCAT('555-', LPAD(id::text, 4, '0')),
      mobile = NULL
    WHERE (phone IS NOT NULL OR mobile IS NOT NULL)
      AND id NOT IN (SELECT partner_id FROM res_users WHERE active = true);
  • Impact: Replaces phones with 555-0001 format, clears mobile
  • Use Case: PII protection, prevent accidental SMS

Anonymize Addresses

  • Priority: LOW
  • Category: Customer Data
  • Default: Disabled
  • SQL:
    UPDATE res_partner SET
      street = CONCAT('Street ', id),
      street2 = NULL,
      city = 'Staging City',
      zip = '00000'
    WHERE street IS NOT NULL
      AND id NOT IN (SELECT partner_id FROM res_users WHERE active = true);
  • Impact: Replaces real addresses with generic values
  • Use Case: Extra PII protection for regulated industries

Anonymize Company Names

  • Priority: LOW
  • Category: Customer Data
  • Default: Disabled
  • SQL:
    UPDATE res_partner SET
      name = CONCAT('Company ', id)
    WHERE is_company = true
      AND id NOT IN (SELECT company_id FROM res_users WHERE active = true);
  • Impact: Replaces company names with Company 123 format
  • Use Case: Extra confidentiality for B2B databases

Security & Integrations

Clear API Keys and Secrets

  • Priority: HIGH
  • Category: Security
  • Default: Enabled in Recommended
  • SQL:
    UPDATE ir_config_parameter SET value = ''
    WHERE key ILIKE '%api_key%'
      OR key ILIKE '%secret%'
      OR key ILIKE '%token%'
      OR key ILIKE '%password%'
      OR key ILIKE '%credential%';
  • Impact: Removes all API keys, tokens, passwords from system parameters
  • Use Case: Prevent staging from accessing production APIs
  • Examples Cleared: Payment gateway keys, SMS provider tokens, analytics IDs

Update Base URL

  • Priority: HIGH
  • Category: Security
  • Default: Enabled in Recommended
  • SQL:
    UPDATE ir_config_parameter
    SET value = &#123;system_url&#125;
    WHERE key = 'web.base.url';
  • Impact: Updates web.base.url to staging domain
  • Use Case: Fix absolute URLs in emails, QR codes, links

Clear OAuth Provider Credentials

  • Priority: HIGH
  • Category: Security
  • Default: Enabled in Recommended
  • SQL:
    UPDATE auth_oauth_provider SET
      client_id = '',
      client_secret = '',
      enabled = false
    WHERE client_id IS NOT NULL OR client_secret IS NOT NULL;
  • Impact: Removes OAuth credentials for Google, Microsoft, GitHub logins
  • Use Case: Prevent staging users from logging in via production OAuth apps

Clear Payment Provider Credentials

  • Priority: HIGH
  • Category: Security
  • Default: Enabled in Recommended
  • SQL:
    UPDATE payment_provider SET
      state = 'disabled',
      stripe_secret_key = NULL,
      stripe_publishable_key = NULL,
      paypal_email_account = NULL,
      paypal_seller_account = NULL,
      authorize_login = NULL,
      authorize_transaction_key = NULL,
      ogone_pspid = NULL,
      ogone_userid = NULL,
      ogone_password = NULL
    WHERE state != 'disabled';
  • Impact: Disables and clears credentials for Stripe, PayPal, Authorize.net, etc.
  • Use Case: Prevent staging from processing real payments

Clear OAuth Access Tokens

  • Priority: HIGH
  • Category: Security
  • Default: Enabled in Recommended
  • SQL:
    DELETE FROM auth_oauth_token;
    UPDATE res_users SET oauth_access_token = NULL WHERE oauth_access_token IS NOT NULL;
  • Impact: Removes stored OAuth access/refresh tokens
  • Use Case: Prevent staging from accessing production user accounts

Clear Webhook URLs

  • Priority: MEDIUM
  • Category: Security
  • Default: Enabled in Recommended
  • SQL:
    UPDATE ir_config_parameter SET value = ''
    WHERE key ILIKE '%webhook%'
      OR key ILIKE '%callback_url%'
      OR key ILIKE '%notify_url%';
  • Impact: Removes webhook URLs to prevent staging from triggering production webhooks
  • Use Case: Prevent staging events from notifying production systems

Clear Integration Credentials

  • Priority: MEDIUM
  • Category: Security
  • Default: Enabled in Recommended
  • SQL:
    UPDATE ir_config_parameter SET value = ''
    WHERE key ILIKE '%sms_%'
      OR key ILIKE '%shipping_%'
      OR key ILIKE '%analytics_%'
      OR key ILIKE '%google_analytics%'
      OR key ILIKE '%facebook_%'
      OR key ILIKE '%twitter_%'
      OR key ILIKE '%sendgrid_%'
      OR key ILIKE '%twilio_%'
      OR key ILIKE '%mailgun_%';
  • Impact: Removes third-party service credentials
  • Use Case: Prevent staging from using production integrations

Reset User Passwords

  • Priority: LOW
  • Category: Security
  • Default: Disabled
  • SQL:
    UPDATE res_users SET
      password = &#123;password_hash&#125;
    WHERE active = true;
  • Impact: Resets all user passwords to staging123 (pbkdf2_sha512 hash)
  • Use Case: Known password for all users in development
  • Note: Use with caution, creates security risk

Disable 2FA/TOTP

  • Priority: LOW
  • Category: Security
  • Default: Disabled
  • SQL:
    DELETE FROM auth_totp_device;
    UPDATE res_users SET totp_secret = NULL WHERE totp_secret IS NOT NULL;
  • Impact: Removes all two-factor authentication devices
  • Use Case: Simplify testing by removing 2FA requirement

Automation

Clear Asset Bundles

  • Priority: HIGH (ALWAYS ENABLED)
  • Category: Automation
  • Default: Always enabled (cannot be disabled)
  • SQL:
    DELETE FROM ir_attachment
    WHERE name LIKE 'web.assets_%.min.%'
      OR name LIKE 'web.assets_%.css'
      OR name LIKE 'web.assets_%.js'
      OR res_model = 'ir.ui.view' AND res_field = 'arch_db';
  • Impact: Deletes compiled CSS/JS bundles, forces regeneration
  • Use Case: Required after clone to prevent broken UI from stale assets
  • Note: This option is ALWAYS applied regardless of preset

Disable Scheduled Actions

  • Priority: MEDIUM
  • Category: Automation
  • Default: Disabled
  • SQL:
    UPDATE ir_cron SET active = false
    WHERE name NOT ILIKE '%Garbage%'
      AND name NOT ILIKE '%Cleanup%';
  • Impact: Deactivates all cron jobs except garbage collection
  • Use Case: Prevent staging from running production automation
  • Note: Preserves system cleanup crons

Clear Scheduled Messages

  • Priority: MEDIUM
  • Category: Automation
  • Default: Disabled
  • SQL:
    DELETE FROM mail_mail WHERE state = 'outgoing' AND scheduled_date > NOW();
    DELETE FROM sms_sms WHERE state = 'outgoing';
  • Impact: Deletes future scheduled emails and SMS
  • Use Case: Remove planned customer communications

Clone API Reference

Clone Environment

Initiates an asynchronous clone operation.

Endpoint: POST /api/v1/environments/&#123;environment_id&#125;/clone

Rate Limit: 5 clones per hour per user

Request Body:

{
  "target": {
    "create_new": true,
    "name": "Staging Environment",
    "environment_type": "staging",
    "vm_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "domain": "staging.example.com"
  },
  "sanitization_preset": "recommended",
  "sanitization_options": null,
  "include_filestore": true
}

Request Schema:

FieldTypeRequiredDescription
targetObjectYesTarget configuration
target.create_newBooleanYestrue to create new env, false to overwrite
target.nameStringIf create_newName for new environment (1-100 chars)
target.environment_typeStringIf create_newdevelopment, staging, or production
target.vm_idUUIDOptionalTarget server (defaults to source server)
target.domainStringOptionalCustom domain for environment
target.target_environment_idUUIDIf !create_newExisting environment to overwrite
sanitization_presetEnumOptionalrecommended, minimal, full, none (default: recommended)
sanitization_optionsObjectOptionalCustom options (overrides preset)
include_filestoreBooleanOptionalInclude filestore (default: true)

Response (202 Accepted):

{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "source_environment_id": "12345678-1234-1234-1234-123456789012",
  "target_environment_id": null,
  "status": "pending",
  "progress": {
    "current_step": "queued",
    "progress_percent": 0,
    "message": "Clone operation queued",
    "steps_completed": 0,
    "total_steps": 10
  },
  "sanitization_options": {
    "disable_mail_servers": true,
    "clear_mail_queue": true,
    "anonymize_emails": true,
    "clear_api_keys": true,
    "update_base_url": true,
    "clear_asset_bundles": true
  },
  "sanitization_result": null,
  "started_at": null,
  "completed_at": null,
  "duration_seconds": null,
  "error_message": null,
  "error_step": null
}

Status Codes:

  • 202 Accepted: Clone operation queued successfully
  • 400 Bad Request: Invalid request (missing fields, invalid state)
  • 403 Forbidden: User doesn't have permission
  • 404 Not Found: Source environment not found
  • 429 Too Many Requests: Rate limit exceeded
  • 500 Internal Server Error: Failed to queue clone task

Error Examples:

{
  "detail": "Cannot clone environment in state 'deploying'. Environment must be running or stopped."
}
{
  "detail": "CPU quota exceeded. Need 2 cores, but only 1 available (using 15/16)."
}

Get Clone Operation Status

Retrieve the current status and progress of a clone operation.

Endpoint: GET /api/v1/clone-operations/&#123;clone_op_id&#125;

Response (200 OK):

{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "source_environment_id": "12345678-1234-1234-1234-123456789012",
  "target_environment_id": "87654321-4321-4321-4321-210987654321",
  "status": "sanitizing",
  "progress": {
    "current_step": "sanitizing",
    "progress_percent": 85,
    "message": "Applying data sanitization",
    "steps_completed": 9,
    "total_steps": 10
  },
  "sanitization_options": {
    "disable_mail_servers": true,
    "clear_mail_queue": true,
    "anonymize_emails": true,
    "clear_api_keys": true
  },
  "sanitization_result": null,
  "started_at": "2024-12-11T10:30:00Z",
  "completed_at": null,
  "duration_seconds": null,
  "error_message": null,
  "error_step": null
}

Status Values:

  • pending: Queued, not yet started
  • pre_checks: Running pre-flight checks
  • validating: Validating source environment
  • creating_target: Creating target environment
  • copying_addons: Copying custom modules
  • backing_up_database: Creating database dump
  • backing_up_filestore: Archiving filestore
  • restoring_database: Restoring database to target
  • restoring_filestore: Extracting filestore to target
  • sanitizing: Applying data sanitization
  • verifying: Verifying clone integrity
  • completed: Clone successful
  • failed: Clone failed
  • cancelled: Clone cancelled by user

Get Clone Options

Get available sanitization options with impact counts.

Endpoint: GET /api/v1/environments/&#123;environment_id&#125;/clone/options

Response (200 OK):

{
  "available_options": [
    {
      "key": "disable_mail_servers",
      "name": "Disable outgoing mail servers",
      "description": "Prevents staging from sending real emails by disabling all mail servers",
      "category": "email",
      "priority": "high",
      "default_enabled": true,
      "impact_preview": "3 mail server(s) will be disabled",
      "impact_count": 3
    },
    {
      "key": "clear_mail_queue",
      "name": "Clear mail queue",
      "description": "Delete all pending and failed emails from the mail queue",
      "category": "email",
      "priority": "high",
      "default_enabled": true,
      "impact_preview": "847 pending email(s) will be deleted",
      "impact_count": 847
    }
  ],
  "presets": {
    "recommended": [
      "disable_mail_servers",
      "clear_mail_queue",
      "anonymize_emails",
      "anonymize_phones",
      "clear_api_keys",
      "update_base_url",
      "clear_asset_bundles"
    ],
    "minimal": [
      "disable_mail_servers",
      "clear_mail_queue",
      "clear_asset_bundles"
    ],
    "full": ["disable_mail_servers", "...all options..."],
    "none": ["clear_asset_bundles"]
  },
  "default_preset": "recommended"
}

List Clone Operations

Get recent clone operations for an environment.

Endpoint: GET /api/v1/environments/&#123;environment_id&#125;/clone-operations

Query Parameters:

  • limit (optional): Max results (default: 10)

Response (200 OK):

[
  {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "source_environment_id": "12345678-1234-1234-1234-123456789012",
    "target_environment_id": "87654321-4321-4321-4321-210987654321",
    "status": "completed",
    "progress_percent": 100,
    "started_at": "2024-12-11T10:30:00Z",
    "completed_at": "2024-12-11T10:45:23Z",
    "created_by": "user-uuid",
    "create_date": "2024-12-11T10:29:45Z"
  }
]

Get Compatible Servers

Get list of servers compatible for cross-server cloning.

Endpoint: GET /api/v1/environments/&#123;environment_id&#125;/clone/compatible-servers

Response (200 OK):

[
  {
    "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "name": "Production Server 2",
    "ip_address": "46.101.96.153",
    "available_cpu": 8,
    "available_ram_mb": 16384,
    "available_disk_gb": 120,
    "current_environments": 3,
    "recommended": true,
    "incompatibility_reason": null
  },
  {
    "id": "c2d3e4f5-g6h7-i8j9-k0l1-m2n3o4p5q6r7",
    "name": "Dev Server 1",
    "ip_address": "165.22.65.97",
    "available_cpu": 1,
    "available_ram_mb": 1024,
    "available_disk_gb": 25,
    "current_environments": 8,
    "recommended": false,
    "incompatibility_reason": "Insufficient RAM (available: 1024MB, required: 2048MB)"
  }
]

Cancel Clone Operation

Cancel a running clone operation.

Endpoint: POST /api/v1/clone-operations/&#123;clone_op_id&#125;/cancel

Response (200 OK):

{
  "status": "cancelled",
  "clone_operation_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}

Cancelable States:

  • pending
  • validating
  • creating_target

Error Response (400 Bad Request):

{
  "detail": "Cannot cancel clone operation with status 'sanitizing'"
}

Cross-Server Cloning

Clone environments to different servers within your organization.

How It Works

  1. Source Backup: Create database dump and filestore archive on source server
  2. Network Transfer: Download files to PaaSPortal backend, upload to target server
  3. Target Restore: Extract database and filestore on target server
  4. Sanitization: Apply sanitization on target database
  5. Verification: Validate clone integrity on target

Transfer Process

Same Server:

  • Database: Direct PostgreSQL restore (no file transfer)
  • Filestore: Direct extraction (no file transfer)
  • Addons: cp -a or rsync

Cross-Server:

  • Database: pg_dump → SFTP download → SFTP upload → pg_restore
  • Filestore: tar -czf → SFTP download → SFTP upload → tar -xzf
  • Addons: tar -czf → local temp → SFTP upload → tar -xzf

Network Requirements

  • SSH access to both source and target servers
  • Sufficient disk space on source server for temporary dump/archive files
  • Sufficient network bandwidth for transfer (1-10 GB typical)
  • Temporary local storage on PaaSPortal backend (cleaned up after transfer)

Performance Considerations

Environment SizeSame ServerCross-ServerNetwork Impact
Small (< 1 GB)2-5 min5-10 min1-2 GB transfer
Medium (1-5 GB)5-15 min15-30 min5-10 GB transfer
Large (> 5 GB)15-45 min45-90 min10+ GB transfer

Selecting Target Server

The system automatically filters compatible servers:

Compatibility Checks:

  • Server is online/running
  • Sufficient CPU cores available
  • Sufficient RAM available
  • Sufficient disk space available
  • Server belongs to same organization

Example: To clone a 2-core, 4GB RAM environment:

✓ Server A: 8 cores available, 16GB RAM → Compatible
✗ Server B: 1 core available, 8GB RAM → Insufficient CPU
✗ Server C: 4 cores, 2GB RAM → Insufficient RAM

Resource Allocation & Quotas

Default Resource Copying

By default, the cloned environment inherits resources from the source:

  • CPU Cores: Same as source
  • RAM (MB): Same as source
  • Disk (GB): Same as source
  • Environment Variables: Copied
  • Odoo Configuration: Copied
  • Settings: Copied

Override Options

When creating a new environment, you can override:

{
  "target": {
    "create_new": true,
    "name": "Dev Environment",
    "cpu_cores": 1,
    "ram_mb": 1024,
    "disk_gb": 10
  }
}

Quota Validation

Before cloning, the system validates:

  1. Environment Limit: Number of active environments in organization
  2. CPU Quota: Total allocated CPU cores
  3. RAM Quota: Total allocated RAM in MB
  4. Disk Quota: Total allocated disk in GB

Example Validation:

Organization Limits:
  Max Environments: 10
  Max CPU Cores: 16
  Max RAM: 32768 MB (32 GB)
  Max Disk: 500 GB

Current Usage:
  Environments: 8/10 ✓
  CPU: 14/16 cores ✓
  RAM: 28672/32768 MB ✓
  Disk: 350/500 GB ✓

Clone Request:
  Source: 2 cores, 4096 MB, 20 GB

Validation:
  Environments: 8 + 1 = 9/10 ✓
  CPU: 14 + 2 = 16/16 ✓
  RAM: 28672 + 4096 = 32768/32768 ✓
  Disk: 350 + 20 = 370/500 GB ✓

Result: Clone ALLOWED

Quota Exceeded Example:

{
  "detail": "CPU quota exceeded. Need 2 cores, but only 1 available (using 15/16)."
}

Overwriting Existing Environment

When overwriting (create_new: false):

  • Target environment's resources are freed from quota
  • Source environment's resources are allocated
  • Net quota change = source resources - target resources

Example:

Target Environment: 4 cores, 8GB RAM
Source Environment: 2 cores, 4GB RAM

Before Clone:
  Total: 20 cores, 40 GB RAM

After Clone:
  Total: 20 - 4 + 2 = 18 cores
  Total: 40 - 8 + 4 = 36 GB RAM

Permissions & Access Control

Required Permissions

To Clone an Environment:

  • org.environments.clone (organization-level)
  • Access to source environment's organization
  • If cross-server: Access to target server's organization

To View Clone Operations:

  • org.environments.list (organization-level)
  • Access to environment's organization

To Cancel Clone Operations:

  • org.environments.clone (organization-level)
  • Must be member of environment's organization

Permission Validation

The system validates access at multiple levels:

  1. Source Environment Access:

    • User is member of source environment's organization
    • User has org.environments.clone permission
  2. Target Server Access (if cross-server):

    • Target server belongs to same organization
    • User has access to target organization
  3. Target Environment Access (if overwriting):

    • User has access to target environment
    • Target environment belongs to same organization

Role Requirements

Minimum Roles:

  • Organization Member: Cannot clone
  • Project Member: Cannot clone
  • Project Admin: Can clone within project
  • Organization Admin: Can clone all environments
  • Organization Owner: Can clone all environments
  • Portal Admin: Can clone all environments

Best Practices

When to Use Each Preset

Recommended

  • Production → Staging: Default choice
  • Staging → Development: If staging has real data
  • Any clone with customer data: GDPR/privacy compliance
  • Shared development environments: Multiple developers

Minimal

  • Staging → Staging: Copy between staging environments
  • Development → Development: Quick duplicates
  • Already sanitized data: Re-cloning from clean source
  • Production → Anything: Too risky without anonymization

Full

  • Production → Development: Maximum protection
  • Regulated industries: Healthcare, finance, legal
  • Training environments: User training with anonymized data
  • External contractors: Sharing with third parties

None

  • Production → DR Server: Disaster recovery replica
  • Isolated secure networks: Air-gapped environments
  • Shared servers: Risk of credential reuse
  • Public networks: Security risk

Data Privacy Considerations

GDPR Compliance:

  • Always use Recommended or Full preset when cloning production data
  • Document sanitization in your DPIA (Data Protection Impact Assessment)
  • Consider right to be forgotten (GDPR Article 17)

PCI DSS Compliance:

  • Use Full preset to remove payment card data
  • Enable clear_payment_providers option
  • Verify no payment tokens remain after sanitization

HIPAA Compliance:

  • Use Full preset with all anonymization options
  • Enable address anonymization for healthcare data
  • Document sanitization procedures for audits

Testing with Cloned Environments

Before Testing:

  1. ✅ Verify sanitization completed successfully
  2. ✅ Check mail servers are disabled
  3. ✅ Confirm base URL updated to staging domain
  4. ✅ Test with a known user account

During Testing:

  1. ✅ Monitor for any production data leaks
  2. ✅ Check email logs (should be empty)
  3. ✅ Verify API calls go to staging endpoints
  4. ✅ Test payment flows with sandbox credentials

After Testing:

  1. ✅ Review test results
  2. ✅ Document any issues found
  3. ✅ Clean up test data if needed
  4. ✅ Consider destroying clone if no longer needed

Performance Optimization

Faster Clones:

  • Use same server instead of cross-server when possible
  • Use Minimal preset if data is already sanitized
  • Clone during off-peak hours for production
  • Ensure sufficient disk space on source server

Disk Space Management:

  • Temporary dump files are cleaned up automatically
  • Ensure source server has 2x database size in /tmp
  • Monitor disk usage during large clones

Network Optimization:

  • Use servers in same datacenter for cross-server clones
  • Consider compressing filestore before clone
  • Schedule large transfers during low-traffic periods

Troubleshooting

Clone Failures

Error: "Source environment not found"

Cause: Environment was deleted or user lacks access

Solution:

  1. Verify environment exists in database
  2. Check user is member of environment's organization
  3. Confirm user has org.environments.list permission

Error: "Cannot clone environment in state 'deploying'"

Cause: Source environment must be running or stopped

Solution:

  1. Wait for environment to finish deploying
  2. Stop environment if safe to do so
  3. Check environment status: GET /api/v1/environments/{id}

Error: "CPU quota exceeded"

Cause: Organization has reached CPU allocation limit

Solution:

  1. Delete unused environments to free quota
  2. Reduce resource allocation on existing environments
  3. Upgrade organization plan for higher quota
  4. Use overwrite mode to replace existing environment

Error: "pg_dump failed"

Cause: Database dump failed (permissions, disk space, corruption)

Solution:

  1. Check PostgreSQL container is running:
    docker ps | grep _db
  2. Verify disk space on source server:
    df -h /tmp
  3. Check PostgreSQL logs:
    docker logs {env_id}_db
  4. Test manual dump:
    docker exec {env_id}_db pg_dump -U odoo -Fc {db_name} > test.dump

Error: "Failed to copy dump to container"

Cause: Docker container not accessible or disk full

Solution:

  1. Verify target container is running:
    docker inspect {container_name}
  2. Check disk space on target server:
    df -h
  3. Restart container if needed:
    docker restart {container_name}

Sanitization Issues

Issue: Emails still being sent from cloned environment

Cause: Mail servers not disabled or external SMTP configured

Solution:

  1. Verify disable_mail_servers was enabled
  2. Check ir_mail_server table:
    SELECT id, name, active FROM ir_mail_server;
  3. Manually disable:
    UPDATE ir_mail_server SET active = false;
  4. Check for external SMTP in odoo.conf

Issue: User cannot login after clone

Cause: Password reset enabled or 2FA removed

Solution:

  1. If reset_passwords was enabled, use reset password: staging123
  2. Check user exists:
    SELECT id, login, active FROM res_users WHERE login = 'admin';
  3. Reset specific user password:
    docker exec {container_name} odoo shell -d {db_name}
    env['res.users'].browse(2).write({'password': 'newpassword'})

Issue: UI broken after clone

Cause: Asset bundles not cleared (should never happen - always forced)

Solution:

  1. Manually clear assets:
    DELETE FROM ir_attachment
    WHERE name LIKE 'web.assets_%';
  2. Restart Odoo container:
    docker restart {container_name}
  3. Clear browser cache and reload

Cross-Server Transfer Issues

Error: "Failed to transfer dump to target server"

Cause: Network connectivity, SSH access, or firewall

Solution:

  1. Test SSH connectivity:
    ssh user@target-server
  2. Check firewall rules allow SSH (port 22)
  3. Verify SSH key authentication working
  4. Check network bandwidth and latency
  5. Retry transfer with manual SFTP:
    sftp user@target-server
    put /tmp/clone_db_*.dump

Error: "Insufficient storage on target server"

Cause: Not enough disk space for dump/archive

Solution:

  1. Check target server disk space:
    df -h
  2. Clean up old Docker volumes:
    docker volume prune
  3. Remove old temporary files:
    rm -f /tmp/clone_*
  4. Increase target server disk size

Verification Failures

Error: "Target container is not running"

Cause: Container failed to start or crashed during restore

Solution:

  1. Check container status:
    docker ps -a | grep {container_name}
  2. View container logs:
    docker logs {container_name}
  3. Check Odoo configuration in /opt/paasportal/{env_id}/odoo.conf
  4. Manually start container:
    docker start {container_name}

Error: "Cannot connect to database"

Cause: PostgreSQL not ready or database restore failed

Solution:

  1. Check PostgreSQL container:
    docker ps | grep {env_id}_db
  2. Test database connectivity:
    docker exec {env_id}_db psql -U odoo -d {db_name} -c 'SELECT 1'
  3. View PostgreSQL logs:
    docker logs {env_id}_db
  4. Check network connectivity:
    docker network inspect paasportal_net_{env_id}

Error: "Missing Odoo tables"

Cause: Database restore incomplete or corrupted

Solution:

  1. Check table count:
    docker exec {env_id}_db psql -U odoo -d {db_name} -c "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'public'"
  2. Verify key tables:
    docker exec {env_id}_db psql -U odoo -d {db_name} -c "\dt res_users ir_module_module"
  3. If tables missing, re-run clone operation
  4. Check source database integrity before retrying

Advanced Examples

Clone with Custom Sanitization

Clone production to staging with custom sanitization:

curl -X POST "https://api.paasportal.io/api/v1/environments/{env_id}/clone" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "target": {
      "create_new": true,
      "name": "Staging - Dec 2024",
      "environment_type": "staging",
      "vm_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
    },
    "sanitization_preset": null,
    "sanitization_options": {
      "disable_mail_servers": true,
      "clear_mail_queue": true,
      "anonymize_emails": true,
      "anonymize_phones": true,
      "anonymize_addresses": true,
      "clear_api_keys": true,
      "clear_oauth_providers": true,
      "clear_payment_providers": true,
      "update_base_url": true,
      "reset_passwords": true,
      "reset_password_value": "Dev2024!",
      "disable_crons": true,
      "clear_asset_bundles": true
    },
    "include_filestore": true
  }'

Overwrite Existing Environment

Replace an existing staging environment with fresh production data:

curl -X POST "https://api.paasportal.io/api/v1/environments/{source_id}/clone" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "target": {
      "create_new": false,
      "target_environment_id": "87654321-4321-4321-4321-210987654321"
    },
    "sanitization_preset": "recommended",
    "include_filestore": true
  }'

Cross-Server Clone to Development

Clone to a different server with full sanitization:

curl -X POST "https://api.paasportal.io/api/v1/environments/{prod_id}/clone" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "target": {
      "create_new": true,
      "name": "Development",
      "environment_type": "development",
      "vm_id": "c2d3e4f5-g6h7-i8j9-k0l1-m2n3o4p5q6r7",
      "domain": "dev.example.com"
    },
    "sanitization_preset": "full",
    "include_filestore": true
  }'

Monitor Clone Progress

Poll clone operation status:

# Start clone
CLONE_OP_ID=$(curl -X POST "https://api.paasportal.io/api/v1/environments/{env_id}/clone" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{"target": {"create_new": true, "name": "Clone"}, "sanitization_preset": "recommended"}' \
  | jq -r '.id')
 
# Poll status every 10 seconds
while true; do
  STATUS=$(curl -s "https://api.paasportal.io/api/v1/clone-operations/${CLONE_OP_ID}" \
    -H "Authorization: Bearer {token}" \
    | jq -r '.status')
 
  if [[ "$STATUS" == "completed" ]]; then
    echo "Clone completed successfully!"
    break
  elif [[ "$STATUS" == "failed" ]]; then
    echo "Clone failed!"
    break
  else
    echo "Status: $STATUS"
    sleep 10
  fi
done

Get Sanitization Impact Preview

Preview affected records before cloning:

curl -X GET "https://api.paasportal.io/api/v1/environments/{env_id}/clone/options" \
  -H "Authorization: Bearer {token}" \
  | jq '.available_options[] | {
      name: .name,
      impact: .impact_preview,
      count: .impact_count
    }'

Example Output:

{
  "name": "Disable outgoing mail servers",
  "impact": "3 mail server(s) will be disabled",
  "count": 3
}
{
  "name": "Clear mail queue",
  "impact": "847 pending email(s) will be deleted",
  "count": 847
}
{
  "name": "Anonymize customer emails",
  "impact": "12,453 customer email(s) will be anonymized",
  "count": 12453
}

Database Schema

CloneOperation Model

ColumnTypeDescription
idUUIDPrimary key
source_environment_idUUIDSource environment FK (CASCADE)
target_environment_idUUIDTarget environment FK (SET NULL)
backup_idUUIDBackup record FK (SET NULL, optional)
task_idUUIDBackground task FK (SET NULL, optional)
statusEnumCurrent status (see CloneStatus enum)
progress_percentIntegerProgress 0-100
current_stepStringCurrent step name
sanitization_optionsJSONEnabled sanitization options
sanitization_resultJSONExecution results with affected rows
target_nameStringTarget environment name (if create_new)
target_env_typeStringTarget environment type
target_vm_idUUIDTarget server FK
target_domainStringTarget domain (optional)
started_atTimestampClone start time
completed_atTimestampClone completion time
duration_secondsIntegerTotal duration
error_messageTextError message if failed
error_stepStringStep where error occurred
error_detailsJSONStack trace and error details
created_byUUIDUser who initiated clone
create_dateTimestampRecord creation time

CloneStatus Enum

class CloneStatus(str, enum.Enum):
    PENDING = "pending"
    PRE_CHECKS = "pre_checks"
    VALIDATING = "validating"
    CREATING_TARGET = "creating_target"
    COPYING_ADDONS = "copying_addons"
    BACKING_UP_DATABASE = "backing_up_database"
    BACKING_UP_FILESTORE = "backing_up_filestore"
    RESTORING_DATABASE = "restoring_database"
    RESTORING_FILESTORE = "restoring_filestore"
    SANITIZING = "sanitizing"
    VERIFYING = "verifying"
    COMPLETED = "completed"
    FAILED = "failed"
    CANCELLED = "cancelled"

SanitizationOptions Schema

class SanitizationOptions(BaseModel):
    # Email & Communications
    disable_mail_servers: bool = True
    clear_mail_queue: bool = True
    disable_mail_templates: bool = False
 
    # Customer Data
    anonymize_emails: bool = True
    anonymize_phones: bool = True
    anonymize_addresses: bool = False
    anonymize_company_names: bool = False
 
    # Security & Integrations
    clear_api_keys: bool = True
    update_base_url: bool = True
    reset_passwords: bool = False
    reset_password_value: str = "staging123"
    disable_2fa: bool = False
 
    # Automation
    disable_crons: bool = False
    clear_scheduled_messages: bool = False
    clear_asset_bundles: bool = True  # Always True

Related Documentation


Summary

Environment cloning with sanitization provides a powerful way to duplicate Odoo environments while protecting sensitive data. Key takeaways:

Four Sanitization Presets: Recommended (default), Minimal, Full, None ✅ 15+ Sanitization Options: Granular control over data masking ✅ Cross-Server Support: Clone between servers in your organization ✅ Real-Time Progress: Track clone status with 10 detailed steps ✅ Automatic Verification: Post-clone integrity checks ✅ Quota Integration: Respects organization resource limits ✅ Production-Ready: Battle-tested sanitization SQL for Odoo databases

For production → staging clones, always use the Recommended preset to prevent data leaks and maintain GDPR compliance.