SOGo Initialization Process
- 1. Introduction
- 2. Overview
- 3. Detailed Execution Flow
- 4. Flow Diagram
- 5. Possible Issues and Scenarios
- 6. Exceptions
1. Introduction
This document describes in detail the initialization process of the SOGo6 application during startup. This process is triggered in the /workspace/app/run.py file by the call:
sogo_state, cache = init_sogo()
This function determines whether SOGo can start correctly and in what state.
2. Overview
The initialization process verifies three essential components:
-
PostgreSQL Database - Verification of connectivity and table structure
-
Redis Cache - Verification of connectivity and basic operations
-
Celery Agent - Agent verification (TODO - not currently implemented)
At the end of these verifications, SOGo can be in one of the following three states:
| State | Value | Description |
|---|---|---|
|
0 |
SOGo cannot function properly. Problems with database, Redis, or agent. |
|
1 |
SOGo can run but has no system configuration or default domain settings (first installation). |
|
2 |
SOGo can function properly with complete configuration. |
3. Detailed Execution Flow
3.1. 1. Entry Point: init_sogo()
File: /workspace/app/config/init_config.py
def init_sogo() -> tuple[int, ClientRedis]:
"""
Init SOGo application
return True if SOGo is ok and already configured, False instead
raises error if the initialization has problems
"""
sogo_state = 0
init_module = ModuleInitSogo(process_config)
init_module.check_sogo_database()
cache_client = init_module.check_redis()
#TODO
#check agent
if init_module.errors:
raise AggravatedException(f"Sogo cannot be initiated because: {init_module.errors}")
sogo_state = cs.SOGO_NOT_INIT
#No errors, check if SOGo already has a configuration
if check_basic_config():
sogo_state = cs.SOGO_OK
return sogo_state, cache_client
The function returns:
-
sogo_state: An integer representing SOGo’s state (0, 1, or 2) -
cache_client: AClientRedisinstance for cache operations
3.2. 2. Initialization Module Creation
init_module = ModuleInitSogo(process_config)
Creates an instance of ModuleInitSogo with process parameters. This class contains:
-
process_settings: Process configuration needed to start SOGo -
init_ok: Boolean, True means SOGo is correctly initialized -
first_init: Boolean, True if this is the first time SOGo is launched -
errors: List of strings containing detected errors
3.3. 3. Database Verification
3.3.1. 3.1. Method: check_sogo_database()
File: /workspace/app/module/ModuleInitSogo.py
This method verifies connectivity and structure of the PostgreSQL database.
3.1.1. Database Client Instantiation
fake_process_settings_db = self.process_settings.SOGO_P_DB_TYPE
sogo_db_type = f"Client{fake_process_settings_db}"
sogo_db_manager: ClientSQL = import_and_instantiate_manager(
module_path="app.manager.db",
module_and_class_name=sogo_db_type,
module_args=self.process_settings.get_db_settings()
)
The database type is retrieved from process_settings and used to dynamically instantiate the correct manager (e.g., ClientPostgresql).
3.1.2. Table Structure Verification
The method loops through all tables defined in ALL_TABLES (from /workspace/app/config/db/tables.py):
-
TABLE_SETTINGS- System and default domain settings -
TABLE_DOMAIN- Domain-specific settings -
TABLE_RULES- Configuration rules -
TABLE_USER- User profiles
For each table:
for table in ALL_TABLES:
db_table_info = sogo_db_manager.get_table_info(table.name)
if db_table_info:
# Check columns
for column in table.columns:
if not column.name in db_table_info:
self.errors.append(f"Table {table.name}'s column {column.name} was not found in database")
if db_table_info[column.name] not in column.data_type_check:
self.errors.append(f"Table {table.name}'s column {column.name} has different data_type")
table_ok.append(table.name)
else:
# Missing table
temp_error.append(f"Table {table.name} missing")
3.1.3. Three Possible Scenarios
| Scenario | Action |
|---|---|
No tables exist |
|
All tables exist and are correct |
|
Some tables exist, others don’t |
|
3.4. 4. Redis Verification
3.4.1. 4.1. Method: check_redis()
File: /workspace/app/module/ModuleInitSogo.py
def check_redis(self) -> ClientRedis:
redis_conf = self.process_settings.get_redis_settings()
cache_client = ClientRedis(**redis_conf)
# Connectivity test
cache_client.ping()
# Write, read, and delete test
cache_client.set("init", "simplestring", 60)
if ret:= cache_client.get("init", str) != "simplestring":
self.errors.append(f"Cache client did not read the correct string {ret}")
cache_client.delete("init")
return cache_client
3.4.2. 4.2. Tests Performed
-
Connectivity test:
cache_client.ping()-
Verifies that Redis is accessible
-
Raises an exception if Redis is inaccessible
-
-
Write test:
cache_client.set("init", "simplestring", 60)-
Writes a test value with 60-second TTL
-
-
Read test:
cache_client.get("init", str)-
Reads the value and verifies it matches
-
-
Delete test:
cache_client.delete("init")-
Cleans up the test key
-
If any of these operations fail, an error is added to self.errors.
3.6. 6. Error Evaluation
if init_module.errors:
raise AggravatedException(f"Sogo cannot be initiated because: {init_module.errors}")
If errors have been collected during previous verifications, an AggravatedException is raised. This exception is considered critical and stops SOGo’s start.
3.7. 7. Initial State
If no errors were detected, SOGo is at minimum in the SOGO_NOT_INIT state:
sogo_state = cs.SOGO_NOT_INIT
3.8. 8. Basic Configuration Verification
3.8.1. 8.1. Method: check_basic_config()
File: /workspace/app/config/init_config.py
def check_basic_config() -> bool:
config_module = ModuleAdminConfig(process_config)
system_settings = config_module.get_system_settings()
default_domain_settings = config_module.get_default_domain_settings()
if system_settings and default_domain_settings:
return True
return False
This function verifies that SOGo has a viable configuration:
-
System settings (
system_settings) -
Default domain settings (
default_domain_settings)
3.8.2. 8.2. Settings Retrieval
8.2.2. System Settings Retrieval
system_settings = config_module.get_system_settings()
The get_system_settings() method:
-
Connects to the database
-
Executes a query on the
sogo_settingstable -
Retrieves the
settings_systemcolumn
8.2.3. Default Domain Settings Retrieval
default_domain_settings = config_module.get_default_domain_settings()
The get_default_domain_settings() method:
-
Connects to the database
-
Executes a query on the
sogo_settingstable -
Retrieves the
settings_domain_defaultcolumn
8.2.4. Internal Mechanism: _get_setting_from_table_settings()
def _get_setting_from_table_settings(self, column_tuple: tuple) -> tuple:
self.sogo_db_manager.connect()
cond_select = NotEqualCondition(param_name=tbl.COL_SETTINGS_UNIQUE.name, param_value=0)
result = list(self.sogo_db_manager.select_from_table(
table_name=tbl.TABLE_SETTINGS.name,
column_tuple=column_tuple,
condition=cond_select
))
size = len(result)
The sogo_settings table is designed to contain a single row:
| Number of rows | Behavior |
|---|---|
|
|
|
|
|
|
4. Flow Diagram
┌─────────────────────────────┐
│ init_sogo() called │
└──────────┬──────────────────┘
│
v
┌─────────────────────────────┐
│ Create ModuleInitSogo │
└──────────┬──────────────────┘
│
v
┌─────────────────────────────┐
│ check_sogo_database() │
│ │
│ • Verify DB connection │
│ • Verify table structure │
│ • Create tables if needed │
└──────────┬──────────────────┘
│
v
┌─────────────────────────────┐
│ check_redis() │
│ │
│ • Test ping │
│ • Test set/get/delete │
└──────────┬──────────────────┘
│
v
┌─────────────────────────────┐
│ check_agent() │
│ (TODO - not implemented) │
└──────────┬──────────────────┘
│
v
┌─────────────────────────────┐
│ Errors collected? │
└──────────┬──────────────────┘
│
┌──────┴──────┐
│ │
YES NO
│ │
v v
┌─────────┐ ┌──────────────────┐
│ ERROR │ │ sogo_state = │
│ │ │ SOGO_NOT_INIT │
│ Raise │ └────────┬─────────┘
│ Aggrava-│ │
│ ted │ v
│ Exception│ ┌──────────────────┐
└─────────┘ │ check_basic_ │
│ config() │
│ │
│ • get_system_ │
│ settings() │
│ • get_default_ │
│ domain_ │
│ settings() │
└────────┬─────────┘
│
┌──────┴──────┐
│ │
Config exists Config empty
│ │
v v
┌─────────────┐ ┌─────────────┐
│ sogo_state =│ │ sogo_state │
│ SOGO_OK │ │ remains │
│ │ │ SOGO_NOT_ │
│ │ │ INIT │
└──────┬──────┘ └──────┬──────┘
│ │
v v
┌──────────────────────────┐
│ Return (sogo_state, │
│ cache_client) │
└──────────────────────────┘
5. Possible Issues and Scenarios
5.1. Scenario 1: Successful First Installation
Context: Empty database, functional Redis
Flow:
-
Empty database detected
-
All tables are created
-
Redis responds correctly
-
No errors collected
-
check_basic_config()returnsFalse(empty table) -
Final state:
SOGO_NOT_INIT
Meaning: SOGo is ready to receive its initial configuration via the administration interface.
5.2. Scenario 2: Normal Startup of Configured SOGo
Context: Database with structure and data, functional Redis
Flow:
-
All tables exist and are correct
-
Redis responds correctly
-
No errors collected
-
check_basic_config()returnsTrue -
Final state:
SOGO_OK
Meaning: SOGo is fully operational.
5.3. Scenario 3: Redis Inaccessible
Context: Database OK, Redis offline
Flow:
-
Database verified successfully
-
cache_client.ping()fails -
Error added to
init_module.errors -
Exception raised:
AggravatedException
Message: "Sogo cannot be initiated because: [Redis error]"
5.4. Scenario 4: Corrupted Database Structure
Context: Some tables exist, others are missing
Flow:
-
Some tables detected
-
Other tables missing
-
Errors added for each missing table
-
Exception raised:
AggravatedException
Message: "Sogo cannot be initiated because: [Table X missing, Table Y missing]"
5.5. Scenario 5: Missing Column or Incorrect Type
Context: Tables present but incorrect structure
Flow:
-
Tables detected
-
Column verification reveals missing columns or incorrect types
-
Errors collected for each anomaly
-
Exception raised:
AggravatedException
Message: "Sogo cannot be initiated because: [Table X’s column Y was not found, Table Z’s column W has different data_type]"
5.6. Scenario 6: sogo_settings Table with Multiple Rows
Context: Data corruption - multiple rows in sogo_settings
Flow:
-
Initial verifications OK
-
check_basic_config()called -
_get_setting_from_table_settings()detects multiple rows -
Exception raised:
AggravatedException
Message: "Table sogo_settings has more than one row (X) which is not normal. Please check manually this table"