SaaS Slave Module
The SaaS Slave feature (also referred to as "Subscription Replica" in some contexts) gives the master Odoo direct control over a customer's Odoo instance. When enabled, the master can query the customer's database, execute SQL, manage modules, sync limits, and more — all without logging into the customer's Odoo manually.
Note
The term "SaaS Slave" reflects internal field names (saas_slave_enabled, sadeem_saas_slave module) and may appear in logs and chatter messages. In customer-facing communication, prefer neutral terms like "remote management" or "subscription replica."
How It Works
When SAAS Slave is enabled on a subscription, Sadeem installs the sadeem_saas_slave module inside the customer's Odoo instance after build or restore. This module exposes a set of internal HTTP endpoints on the customer instance that the master calls to perform management actions.
Master Odoo → HTTP → sadeem_saas_slave endpoints on customer's Odoo
/sadeem/query/execute
/sadeem/sync/model_limits
/sadeem/get/logins
... etc.
All communication is server-to-server — the operator triggers actions from the subscription form in the master, and the master calls the customer's Odoo internally.
Enabling SAAS Slave
On the subscription form, go to the Configuration tab (visible in Advanced Mode) and enable the SAAS Slave toggle.
Warning
Enabling SAAS Slave after the subscription is already running requires the sadeem_saas_slave module to be installed manually on the customer's Odoo, or you can trigger a restore which re-installs it automatically.
When a subscription is built or a Restore Local is completed, Sadeem automatically installs sadeem_saas_slave on the customer's instance if the toggle is on.
Actions Unlocked by SAAS Slave
All of the following buttons on the subscription form are hidden unless SAAS Slave is enabled.
Get Resource Usage
Button: Get Resource Usage (visible when Running)
Queries the customer's instance for current resource consumption — CPU, memory, and storage. Results are posted to the subscription chatter.
Manage Modules
Button: Manage Modules (visible when Running, Operator role)
Opens the Module Management wizard. Operators can install or uninstall Odoo modules on the customer's instance remotely. The available modules are constrained by the subscription's Package (module limit).
Diagnosis & Fix
Button: Diagnosis & Fix (visible in Building, Build Failed, or Running states, Operator role)
Runs a full diagnostic on the subscription — checks DNS, Nginx proxy, Docker stack (or DBFilter database), and port assignments. Automatically fixes any detected issues. Useful when a subscription is stuck in Build Failed or has drifted from its expected state.
Warning
Diagnosis & Fix makes changes that cannot be reverted. Always review the Build Fail Message before running it.
Connect As
Button: Connect As (visible when Running, Manager role)
Opens the Login As wizard. Allows operators to log in to the customer's Odoo as any user — useful for support and debugging without needing the customer's password.
Enable / Disable Mobile Notifications
Buttons: Enable Notifications / Disable Notifications (visible when Running, Operator role)
Pushes or removes mobile push notification configuration on the customer's instance. Supports ntfy and Firebase Cloud Messaging (FCM).
SQL Console
Tab: SQL Console (visible when Running, Advanced Mode, Operator role)
Allows operators to execute raw SQL queries directly against the customer's database. The query is sent to the customer's Odoo via the slave endpoint and results are displayed inline.
Danger
SQL queries executed here are not reversible. Use with extreme caution.
Sync Model Limits
Triggered automatically when the subscription's package or model limits change. Pushes the updated limits to the customer's instance via /sadeem/sync/model_limits so the customer's Odoo enforces the correct quotas in real time.
Can also be triggered manually from the subscription form (Operator role).
Restore Local
Button: Restore Local in the Backup tab (visible when Running)
Opens the restore wizard to load a backup from a file upload or URL into the customer's database. After restore, Sadeem automatically re-installs sadeem_saas_slave on the restored database.
See Migrate from Odoo.sh for a full restore walkthrough.
Database Drop on Cancel
When a subscription is cancelled, Sadeem drops the customer's database on the remote server only if SAAS Slave is enabled. Without it, the database is left in place and must be removed manually.
Summary Table
| Action | Requires Slave | Where |
|---|---|---|
| Get Resource Usage | Yes | Header button |
| Manage Modules | Yes | Header button |
| Diagnosis & Fix | Yes | Header button |
| Connect As (Login As) | Yes | Header button |
| Enable/Disable Notifications | Yes | Header button |
| SQL Console tab | Yes | Tab (Advanced Mode) |
| Sync Model Limits | Yes | Automatic + manual |
| Restore Local | Yes | Backup tab |
| Drop database on cancel | Yes | Automatic on cancel |
config.json Reference
The sadeem_saas_slave module reads its configuration from a config.json file located in the module's root directory (e.g. shared_addons/sadeem_saas_slave/config.json). This file is not written automatically — it must be created and maintained by the operator when setting up the server. All customer instances on the same Docker image share the same config.json, so you only need to set it up once per image.
{
"disable_uninstall": true,
"backend_url": "http://<master-odoo>",
"website": "http://<master-odoo>",
"secret": "<fernet-key>",
"secret_path": "",
"backend_ips": []
}
Field Descriptions
| Field | Type | Description |
|---|---|---|
disable_uninstall |
boolean | When true, prevents the customer from uninstalling the sadeem_saas_slave module from the Odoo Apps menu. Set to true in production. |
backend_url |
string | Internal URL of the master Odoo instance. Used by the slave to post resource usage reports back to the master (e.g. GET /sadeem_subscription_details). Must be reachable from the customer's container/server. |
website |
string | Public or internal URL of the master Odoo. Used for customer-facing links inside the slave instance. |
secret |
string | Fernet symmetric encryption key. The master uses this key to encrypt tokens it sends with every slave API call (e.g. database names, login tokens, timestamps). The slave decrypts these tokens with the same key to verify the request. Must match the sadeem_saas_secret_key system parameter on the master exactly. |
secret_path |
string | Alternative to secret — path to a file whose first line contains the Fernet key. If both secret and secret_path are set, secret_path takes priority. Leave empty to use the inline secret field instead. |
backend_ips |
array of strings | IP allowlist for incoming slave API calls. Only requests from these IPs (plus 127.0.0.1) are accepted. If the array is empty, all IPs are allowed. Set this to the master server's IP(s) to restrict access in production. |
The secret Field — How It Works
All sensitive data the master sends to the slave (database names, login credentials, expiry timestamps) is encrypted using Fernet symmetric encryption before transmission. The slave decrypts each token with the same key and also validates that the token has not expired (tokens are valid for 5 minutes by default).
How the key is created:
When sadeem_saas_base is first installed on the master Odoo, a Fernet key is generated automatically via Fernet.generate_key() and stored in the master's system parameters under the key sadeem_saas_secret_key (Settings → Technical → System Parameters).
The operator must copy this key into config.json manually when setting up the server.
How to get the secret key manually:
If you need to configure a slave instance manually (e.g., after a manual restore):
- On the master Odoo, go to Settings → Technical → System Parameters.
- Search for
sadeem_saas_secret_key. - Copy the value (a base64-encoded string ending in
=). - Paste it into the
secretfield ofconfig.jsonon the customer's instance. - Restart Odoo on the customer's instance to apply the change.
Warning
The secret key must be identical on both master and slave. If they differ, all slave API calls (backups, module management, SQL console, Connect As) will fail with decryption errors. If a slave stops responding after a key rotation or manual restore, verify the key matches.
Danger
Never share or commit config.json to a public repository — it contains the encryption key that protects all slave operations.