# -*- coding: utf-8 -*- """ Tenant Request Routing Pipeline (ដំណើរការ Request) ----------------------------------------------------- 1. User Request -> company1.domain-name.com 2. DNS Resolution -> Load Balancer IP 3. Load Balancer -> Route to available Worker 4. Worker -> Read database name from subdomain 5. Database Router -> Connect to correct tenant database 6. Process Request -> Return response Steps 1-3 happen OUTSIDE Odoo, at the infrastructure layer: - DNS: wildcard A/CNAME record *.domain-name.com -> Load Balancer IP - Load Balancer (nginx/HAProxy/Traefik) terminates TLS and forwards to one of N Odoo worker processes/pods, e.g.: nginx.conf snippet: server { listen 443 ssl; server_name *.domain-name.com; location / { proxy_pass http://odoo_workers; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } upstream odoo_workers { server worker-1:8069; server worker-2:8069; server worker-3:8069; } Steps 4-6 are implemented in Odoo itself via this controller, which reads the subdomain from the Host header and switches `request.session.db` before any other controller/model code executes. Odoo natively supports this via the `dbfilter` config option (odoo.conf): dbfilter = ^%h$ `%h` is replaced by the Host header at request time, so Odoo automatically maps "company1.domain-name.com" -> database "company1" PROVIDED the database name matches the first subdomain label. Since our generated db_name (see saas.database._generate_unique_db_name) IS the first label of the subdomain, `dbfilter = ^%h$` alone satisfies steps 4-5 for the standard Odoo multi-database filter mechanism. The explicit controller below is only needed if you want CUSTOM routing logic beyond dbfilter (e.g. custom error pages for suspended/expired tenants, or a non-Odoo-native subdomain naming scheme). """ from odoo import http from odoo.http import request class TenantRouterController(http.Controller): @http.route('/saas/tenant-status', type='json', auth='public') def tenant_status(self, **kw): """Optional health endpoint the Load Balancer / monitoring system can call to verify a tenant database is reachable and active before routing traffic to it (step 3-4 sanity check). """ host = request.httprequest.host.split(':')[0] subdomain_label = host.split('.')[0] database = request.env['saas.database'].sudo().search( [('db_name', '=', subdomain_label)], limit=1 ) if not database: return {'status': 'not_found'} subscription = database.trial_request_id.subscription_id if subscription and subscription.expiry_date and subscription.expiry_date < http.fields.Datetime.now(): return {'status': 'expired', 'db_name': database.db_name} return { 'status': 'active' if database.state == 'ready' else database.state, 'db_name': database.db_name, 'worker_node': database.worker_node, }