Skip to content

Module Architecture

flowchart TD
    BASE["sadeem_saas_base\nSAAS Base"]
    NPM["sadeem_nginx_proxy_manager\nNginx Proxy Manager"]
    CF["sadeem_cloudflare\nCloudflare"]

    RS["sadeem.root.server (inherit)\ninstall Portainer via SSH\ncreate admin + API key"]
    P["sadeem.portainer\nServer URL · API key\nstack & container operations"]
    ENV["sadeem.portainer.environment\nDocker host · capacity tracking\nNginx · Cloudflare defaults"]
    IMG["sadeem.portainer.image\nDocker image config\nenvironment assignment strategy"]
    IMGTAG["sadeem.portainer.image.tag\nversion tags per image"]
    IMGENV["sadeem.portainer.image.environment\nimage to environment mapping"]
    PG["sadeem.postgresql.server\nPostgres server config\nadded by portainer module"]
    EXT[/Portainer API\nAPI key auth/]

    BASE --> RS
    NPM --> P
    CF --> P

    RS --> A1([action_install_portainer\ndeploy via SSH + create admin + API key])
    RS --> A2([action_install_portainer_master\ndeploy as Portainer master node])

    P --> A3([action_confirm\nvalidate API key → active])
    P --> A4([action_open_portainer_panel\nopen Portainer web UI])
    P --> A5([action_create_stack\ndeploy new Docker stack])
    P --> A6([action_update_stack\nredeploy with new compose config])
    P --> A7([action_stack_actions\nstart or stop stack])
    P --> A8([action_delete_stack\nremove stack from Docker host])
    P --> A9([action_check_stack_status\nGET stack + container states → chatter])
    P --> A10([action_docker_actions\nrestart / start / stop container])
    P --> A11([action_docker_exec\nexecute command in container])

    ENV --> A12([get_best_environment\npick env by sequence or lowest usage])
    ENV --> A13([get_environment_info\nsync live capacity from Portainer])

    IMG --> IMGTAG
    IMG --> IMGENV
    IMGENV --> ENV
    P --> ENV
    P --> PG

    A3 --> EXT
    A5 --> EXT
    A6 --> EXT
    A7 --> EXT
    A8 --> EXT
    A9 --> EXT
    A10 --> EXT
    A11 --> EXT

Module Description

Integrates Odoo with the Portainer API for Docker infrastructure orchestration.

Area What it does
Portainer Servers Connect via API key; install Portainer (agent or master) on root servers via SSH with auto admin setup
Environments Track Docker hosts with real-time container capacity; carry Nginx/Cloudflare/domain defaults for subscriptions
Stack Management Create, update, start, stop, delete Docker stacks; check stack and container health
Container Control Restart, start, stop, and exec commands in containers
Image Config Define Docker images with version tags and environment assignment strategies
Environment Selection get_best_environment() picks optimal Docker host by sequence or lowest usage

Dependencies

  • mail
  • sadeem_saas_base
  • sadeem_nginx_proxy_manager
  • sadeem_cloudflare

Menus

SAAS Management
└─ Infrastructure
    └─ Portainer
        ├─ Portainer Servers
        ├─ Environments
        ├─ Image Config
        └─ Image Tags

Key Fields

Portainer Server (sadeem.portainer)

Field Type Description
portainer_link Char URL of the Portainer server (required)
ip Char IP address of the Portainer server (required)
portainer_access_token Char Portainer API key for authentication
state Selection Server status: draft, confirm, cancel
server_id Many2one Linked sadeem.root.server (for SSH operations)
skip_ssl_verify Boolean Skip SSL certificate verification when calling Portainer API (default: True)
master_portainer Boolean Whether this is a master/central Portainer node

Portainer Environment (sadeem.portainer.environment)

Field Type Description
portainer_environment_id Integer Portainer's internal environment/endpoint ID (required)
portainer_id Many2one Parent Portainer server (required)
ip Char IP of the Docker host (required)
next_port Integer Next available port to assign to new containers (default: 10000)
max_running_container_count Integer Configured capacity limit for this environment
available_container_capacity Integer Computed remaining slots (maxcontainer_run)
container_run / container_stop / container_pause / container_total Integer Live container counts (synced from Portainer)
state Selection Capacity status: normal, over
postgresql_server_external Boolean Whether to use an external PostgreSQL server
postgresql_server_id Many2one External PostgreSQL server for this environment
cloudflare_dns Boolean Whether Cloudflare DNS is managed for this environment
cloudflare_account_id Many2one Cloudflare connector for DNS record creation
cloudflare_domain_zone_id Char Cloudflare Zone ID for the environment's domain
cloudflare_create_record Boolean Auto-create DNS records for new subscriptions
cloudflare_proxied_record Boolean Whether auto-created DNS records are proxied
domain_for_new_sub Char Base domain used when generating subscription subdomains
subdomain_start Char Prefix for generated subdomains
nginx_default_cert_id Integer Default SSL certificate ID on the NPM server
nginx_proxy_server_id Many2one NPM connector for this environment

Docker Image Config (sadeem.portainer.image)

Field Type Description
odoo_version Char Version label displayed to clients (required)
config_file Char Path to the Docker Compose configuration file (required)
image_tags Many2many Linked version tags for this image
environment_id Many2one Default environment for this image (optional)
select_environment_by Selection Environment selection strategy: sequence or used (low usage)
image_environment_id One2many Per-environment assignment overrides

Image Environment Mapping (sadeem.portainer.image.environment)

Field Type Description
image_id Many2one Image this mapping belongs to (required)
environment_id Many2one Target environment
sequence Integer Priority order for environment selection
max_running_container_count Integer Capacity override for this image in this environment
available_container_capacity Integer Computed available capacity

Lifecycle & States

Portainer Server States

State Meaning
draft API key not yet verified
confirm API key valid, server is active
cancel Server disabled

Transitions: - draftconfirm: action_confirm — validates portainer_link and portainer_access_token are set - confirmdraft: action_reset_draft - Any → cancel: action_cancel

Environment Capacity States

State Meaning
normal Running containers below max capacity
over Running containers at or above max capacity

Updated automatically when get_environment_info syncs container counts from Portainer.

Key Actions

Action Model Description
action_install_portainer sadeem.root.server (inherit) Deploys Portainer agent via SSH on the root server; creates admin user and API key
action_install_portainer_master sadeem.root.server (inherit) Deploys Portainer as master node
action_confirm sadeem.portainer Validates API credentials; moves to confirm state
action_open_portainer_panel sadeem.portainer Returns URL action to open Portainer web UI
action_create_stack sadeem.portainer Deploys a new Docker stack from a compose string
action_update_stack sadeem.portainer Redeploys an existing stack with new compose config
action_stack_actions sadeem.portainer Starts or stops a Docker stack
action_delete_stack sadeem.portainer Removes a stack from the Docker host
action_check_stack_status sadeem.portainer Gets live stack and container states from Portainer; posts to chatter
action_docker_actions sadeem.portainer Restart / start / stop a specific container
action_docker_exec sadeem.portainer Executes a shell command inside a running container
get_environment_info sadeem.portainer.environment Syncs live container counts and resource info from Portainer
get_best_environment sadeem.portainer.image Selects optimal environment by sequence or lowest container usage

Warnings & Important Notes

  • Missing API credentials: action_confirm raises UserError('Missing required data') if portainer_link or portainer_access_token is not set.
  • SSL verification skipped by default: skip_ssl_verify=True on the portainer server — change this in production if using valid certs.
  • Port tracking: next_port on the environment is incremented each time a subscription is provisioned; it must be initialized correctly to avoid port conflicts.
  • Capacity tracking: available_container_capacity is computed as max_running_container_count − container_run; the environment moves to over state when this reaches zero.
  • Environment selection strategy: select_environment_by = 'sequence' picks the first available environment in order; 'used' picks the one with lowest running container count.
  • PostgreSQL server inheritance: Fields on sadeem.postgresql.server are extended by this module (added portainer_id linking).