diff --git a/.env b/.env index 7ac8fc25ef..726043414a 100644 --- a/.env +++ b/.env @@ -38,6 +38,7 @@ _APP_REDIS_HOST=redis _APP_REDIS_PORT=6379 _APP_REDIS_PASS= _APP_REDIS_USER= +_APP_DB_ADAPTER=mariadb _APP_DB_HOST=mariadb _APP_DB_PORT=3306 _APP_DB_SCHEMA=appwrite diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 509e1f5b29..ada8b8c85d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -163,6 +163,11 @@ jobs: strategy: fail-fast: false matrix: + db_adapter: [ + MARIADB, + POSTGRESQL + ] + service: [ Account, Avatars, @@ -216,12 +221,33 @@ jobs: - name: Run ${{ matrix.service }} tests with Project table mode run: | echo "Using project tables" + export _APP_DATABASE_SHARED_TABLES= export _APP_DATABASE_SHARED_TABLES_V1= + # Set DB Adapter Specific ENV Vars using if-elif + if [ "${{ matrix.db_adapter }}" = "MARIADB" ]; then + export _APP_DB_ADAPTER=mariadb + export _APP_DB_HOST=mariadb + export _APP_DB_PORT=3306 + export _APP_DB_SCHEMA=appwrite + elif [ "${{ matrix.db_adapter }}" = "POSTGRESQL" ]; then + export _APP_DB_ADAPTER=postgresql + export _APP_DB_HOST=postgresql + export _APP_DB_PORT=5432 + export _APP_DB_SCHEMA=appwrite + else + echo "Unknown DB adapter: ${{ matrix.db_adapter }}" + exit 1 + fi + docker compose exec -T \ -e _APP_DATABASE_SHARED_TABLES \ -e _APP_DATABASE_SHARED_TABLES_V1 \ + -e _APP_DB_ADAPTER \ + -e _APP_DB_HOST \ + -e _APP_DB_PORT \ + -e _APP_DB_SCHEMA \ -e _APP_E2E_RESPONSE_FORMAT="${{ github.event.inputs.response_format }}" \ appwrite test /usr/src/code/tests/e2e/Services/${{ matrix.service }} --debug --exclude-group abuseEnabled,screenshots diff --git a/app/config/variables.php b/app/config/variables.php index 36f691e534..0303cd7977 100644 --- a/app/config/variables.php +++ b/app/config/variables.php @@ -358,6 +358,15 @@ return [ 'question' => '', 'filter' => '' ], + [ + 'name' => '_APP_DB_ADAPTER', + 'description' => 'Which database adapter to use. Must be one of: mariadb, postgresql.', + 'introduction' => '1.6.0', + 'default' => 'mariadb', + 'required' => true, + 'question' => 'Choose your database (mariadb|postgresql)', + 'filter' => '' + ], [ 'name' => '_APP_TRUSTED_HEADERS', 'description' => 'This option allows you to set the list of trusted headers, the value is a comma‑separated list of HTTP header names, evaluated left-to-right for the first valid IP. Header names are treated case-insensitively.', diff --git a/app/init/registers.php b/app/init/registers.php index 2db7f487ca..feb3c6e11a 100644 --- a/app/init/registers.php +++ b/app/init/registers.php @@ -13,6 +13,7 @@ use Utopia\CLI\Console; use Utopia\Config\Config; use Utopia\Database\Adapter\MariaDB; use Utopia\Database\Adapter\MySQL; +use Utopia\Database\Adapter\Postgres; use Utopia\Database\Adapter\SQL; use Utopia\Database\PDO; use Utopia\Domains\Validator\PublicDomain; @@ -150,7 +151,7 @@ $register->set('pools', function () { $group = new Group(); $fallbackForDB = 'db_main=' . AppwriteURL::unparse([ - 'scheme' => 'mariadb', + 'scheme' => System::getEnv('_APP_DB_ADAPTER', 'mariadb'), 'host' => System::getEnv('_APP_DB_HOST', 'mariadb'), 'port' => System::getEnv('_APP_DB_PORT', '3306'), 'user' => System::getEnv('_APP_DB_USER', ''), @@ -170,19 +171,19 @@ $register->set('pools', function () { 'type' => 'database', 'dsns' => $fallbackForDB, 'multiple' => false, - 'schemes' => ['mariadb', 'mysql'], + 'schemes' => ['mariadb', 'mysql','postgresql'], ], 'database' => [ 'type' => 'database', 'dsns' => $fallbackForDB, 'multiple' => true, - 'schemes' => ['mariadb', 'mysql'], + 'schemes' => ['mariadb', 'mysql','postgresql'], ], 'logs' => [ 'type' => 'database', 'dsns' => System::getEnv('_APP_CONNECTIONS_DB_LOGS', $fallbackForDB), 'multiple' => false, - 'schemes' => ['mariadb', 'mysql'], + 'schemes' => ['mariadb', 'mysql','postgresql'], ], 'publisher' => [ 'type' => 'publisher', @@ -275,6 +276,17 @@ $register->set('pools', function () { ]); }); }, + 'postgresql' => function () use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnDatabase) { + return new PDOProxy(function () use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnDatabase) { + return new PDO("pgsql:host={$dsnHost};port={$dsnPort};dbname={$dsnDatabase}", $dsnUser, $dsnPass, array( + \PDO::ATTR_TIMEOUT => 3, // Seconds + \PDO::ATTR_PERSISTENT => false, + \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC, + \PDO::ATTR_EMULATE_PREPARES => true, + \PDO::ATTR_STRINGIFY_FETCHES => true + )); + }); + }, 'redis' => function () use ($dsnHost, $dsnPort, $dsnPass) { $redis = new \Redis(); @$redis->pconnect($dsnHost, (int)$dsnPort); @@ -297,6 +309,7 @@ $register->set('pools', function () { $adapter = match ($dsn->getScheme()) { 'mariadb' => new MariaDB($resource()), 'mysql' => new MySQL($resource()), + 'postgresql' => new Postgres($resource()), default => null }; @@ -351,10 +364,25 @@ $register->set('db', function () { $dbPort = System::getEnv('_APP_DB_PORT', ''); $dbUser = System::getEnv('_APP_DB_USER', ''); $dbPass = System::getEnv('_APP_DB_PASS', ''); - $dbScheme = System::getEnv('_APP_DB_SCHEMA', ''); + $dbSchema = System::getEnv('_APP_DB_SCHEMA', ''); + $dbAdapter = System::getEnv('_APP_DB_ADAPTER', 'mariadb'); + $dsn = ''; + + switch ($dbAdapter) { + case 'postgresql': + $dsn = "pgsql:host={$dbHost};port={$dbPort};dbname={$dbSchema}"; + break; + + case 'mysql': + case 'mariadb': + default: + $dsn = "mysql:host={$dbHost};port={$dbPort};dbname={$dbSchema};charset=utf8mb4"; + break; + } + return new PDO( - "mysql:host={$dbHost};port={$dbPort};dbname={$dbScheme};charset=utf8mb4", + $dsn, $dbUser, $dbPass, SQL::getPDOAttributes() diff --git a/app/views/install/compose.phtml b/app/views/install/compose.phtml index 0104a9d5a5..5f0030fa5e 100644 --- a/app/views/install/compose.phtml +++ b/app/views/install/compose.phtml @@ -12,6 +12,7 @@ $version = $this->getParam('version', ''); $organization = $this->getParam('organization', ''); $image = $this->getParam('image', ''); $enableAssistant = $this->getParam('enableAssistant', false); +$dbService = $this->getParam('database'); ?>services: traefik: image: traefik:3.6 @@ -70,8 +71,8 @@ $enableAssistant = $this->getParam('enableAssistant', false); - appwrite-sites:/storage/sites:rw - appwrite-builds:/storage/builds:rw depends_on: - - mariadb - redis + - # - clamav environment: - _APP_ENV @@ -108,6 +109,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_SMTP_HOST - _APP_SMTP_PORT - _APP_SMTP_SECURE @@ -223,8 +225,8 @@ $enableAssistant = $this->getParam('enableAssistant', false); networks: - appwrite depends_on: - - mariadb - redis + - environment: - _APP_ENV - _APP_WORKER_PER_CORE @@ -240,6 +242,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_USAGE_STATS - _APP_LOGGING_CONFIG @@ -253,7 +256,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); - appwrite depends_on: - redis - - mariadb + - environment: - _APP_ENV - _APP_WORKER_PER_CORE @@ -267,6 +270,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_LOGGING_CONFIG appwrite-worker-webhooks: @@ -279,7 +283,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); - appwrite depends_on: - redis - - mariadb + - environment: - _APP_ENV - _APP_WORKER_PER_CORE @@ -291,6 +295,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER @@ -307,7 +312,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); - appwrite depends_on: - redis - - mariadb + - volumes: - appwrite-uploads:/storage/uploads:rw - appwrite-cache:/storage/cache:rw @@ -328,6 +333,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_STORAGE_DEVICE - _APP_STORAGE_S3_ACCESS_KEY - _APP_STORAGE_S3_SECRET @@ -370,7 +376,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); - appwrite depends_on: - redis - - mariadb + - environment: - _APP_ENV - _APP_WORKER_PER_CORE @@ -384,6 +390,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_LOGGING_CONFIG appwrite-worker-builds: @@ -396,7 +403,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); - appwrite depends_on: - redis - - mariadb + - volumes: - appwrite-functions:/storage/functions:rw - appwrite-sites:/storage/sites:rw @@ -417,6 +424,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_LOGGING_CONFIG - _APP_VCS_GITHUB_APP_NAME - _APP_VCS_GITHUB_PRIVATE_KEY @@ -464,7 +472,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); - appwrite depends_on: - redis - - mariadb + - volumes: - appwrite-config:/storage/config:rw - appwrite-certificates:/storage/certificates:rw @@ -489,6 +497,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_LOGGING_CONFIG appwrite-worker-functions: @@ -501,7 +510,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); - appwrite depends_on: - redis - - mariadb + - - openruntimes-executor environment: - _APP_ENV @@ -518,6 +527,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_FUNCTIONS_TIMEOUT - _APP_SITES_TIMEOUT - _APP_COMPUTE_BUILD_TIMEOUT @@ -540,6 +550,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); - appwrite depends_on: - redis + - environment: - _APP_ENV - _APP_WORKER_PER_CORE @@ -551,6 +562,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER @@ -576,6 +588,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); - appwrite-uploads:/storage/uploads:rw depends_on: - redis + - environment: - _APP_ENV - _APP_WORKER_PER_CORE @@ -589,6 +602,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_LOGGING_CONFIG - _APP_SMS_FROM - _APP_SMS_PROVIDER @@ -626,7 +640,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); volumes: - appwrite-imports:/storage/imports:rw depends_on: - - mariadb + - environment: - _APP_ENV - _APP_WORKER_PER_CORE @@ -647,6 +661,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_LOGGING_CONFIG - _APP_MIGRATIONS_FIREBASE_CLIENT_ID - _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET @@ -661,6 +676,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); - appwrite depends_on: - redis + - environment: - _APP_ENV - _APP_WORKER_PER_CORE @@ -681,6 +697,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_MAINTENANCE_INTERVAL - _APP_MAINTENANCE_RETENTION_EXECUTION - _APP_MAINTENANCE_RETENTION_CACHE @@ -700,7 +717,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); - appwrite depends_on: - redis - - mariadb + - environment: - _APP_ENV - _APP_WORKER_PER_CORE @@ -710,6 +727,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER @@ -729,7 +747,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); - appwrite depends_on: - redis - - mariadb + - environment: - _APP_ENV - _APP_WORKER_PER_CORE @@ -739,6 +757,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER @@ -757,7 +776,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); - appwrite depends_on: - redis - - mariadb + - environment: - _APP_ENV - _APP_WORKER_PER_CORE @@ -767,6 +786,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER @@ -784,7 +804,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); networks: - appwrite depends_on: - - mariadb + - - redis environment: - _APP_ENV @@ -799,6 +819,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER appwrite-task-scheduler-executions: image: /: @@ -809,7 +830,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); networks: - appwrite depends_on: - - mariadb + - - redis environment: - _APP_ENV @@ -824,6 +845,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER appwrite-task-scheduler-messages: image: /: @@ -834,7 +856,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); networks: - appwrite depends_on: - - mariadb + - - redis environment: - _APP_ENV @@ -849,6 +871,7 @@ $enableAssistant = $this->getParam('enableAssistant', false); - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER appwrite-assistant: @@ -922,10 +945,12 @@ $enableAssistant = $this->getParam('enableAssistant', false); - OPR_EXECUTOR_STORAGE_WASABI_REGION=$_APP_STORAGE_WASABI_REGION - OPR_EXECUTOR_STORAGE_WASABI_BUCKET=$_APP_STORAGE_WASABI_BUCKET + + + mariadb: - image: mariadb:10.11 # fix issues when upgrading using: mysql_upgrade -u root -p + image: mariadb:10.11 container_name: appwrite-mariadb - <<: *x-logging restart: unless-stopped networks: - appwrite @@ -939,6 +964,24 @@ $enableAssistant = $this->getParam('enableAssistant', false); - MARIADB_AUTO_UPGRADE=1 command: 'mysqld --innodb-flush-method=fsync' + + + postgresql: + image: postgres:15 + container_name: appwrite-postgresql + restart: unless-stopped + networks: + - appwrite + volumes: + - appwrite-postgresql:/var/lib/postgresql/data:rw + environment: + - POSTGRES_DB=${_APP_DB_SCHEMA} + - POSTGRES_USER=${_APP_DB_USER} + - POSTGRES_PASSWORD=${_APP_DB_PASS} + command: "postgres" + + + redis: image: redis:7.2.4-alpine container_name: appwrite-redis @@ -972,7 +1015,11 @@ networks: name: runtimes volumes: + appwrite-mariadb: + + appwrite-postgresql: + appwrite-redis: appwrite-cache: appwrite-uploads: diff --git a/docker-compose.yml b/docker-compose.yml index a1f5ca77c2..0a959cd137 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -100,7 +100,7 @@ services: - ./dev:/usr/src/code/dev # - ./vendor/utopia-php/framework:/usr/src/code/vendor/utopia-php/framework depends_on: - - mariadb + - ${_APP_DB_HOST:-mariadb} - redis - coredns # - clamav @@ -149,6 +149,7 @@ services: - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_SMTP_HOST - _APP_SMTP_PORT - _APP_SMTP_SECURE @@ -283,7 +284,7 @@ services: - ./app:/usr/src/code/app - ./src:/usr/src/code/src depends_on: - - mariadb + - ${_APP_DB_HOST:-mariadb} - redis environment: - _APP_ENV @@ -300,6 +301,7 @@ services: - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_USAGE_STATS - _APP_LOGGING_CONFIG - _APP_LOGGING_CONFIG_REALTIME @@ -318,7 +320,7 @@ services: - ./src:/usr/src/code/src depends_on: - redis - - mariadb + - ${_APP_DB_HOST:-mariadb} environment: - _APP_ENV - _APP_WORKER_PER_CORE @@ -333,6 +335,7 @@ services: - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_LOGGING_CONFIG - _APP_DATABASE_SHARED_TABLES @@ -348,7 +351,7 @@ services: - ./src:/usr/src/code/src depends_on: - redis - - mariadb + - ${_APP_DB_HOST:-mariadb} - request-catcher-sms - request-catcher-webhook environment: @@ -362,6 +365,7 @@ services: - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER @@ -379,7 +383,7 @@ services: - appwrite depends_on: - redis - - mariadb + - ${_APP_DB_HOST:-mariadb} volumes: - appwrite-uploads:/storage/uploads:rw - appwrite-cache:/storage/cache:rw @@ -403,6 +407,7 @@ services: - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_STORAGE_DEVICE - _APP_STORAGE_S3_ACCESS_KEY - _APP_STORAGE_S3_SECRET @@ -446,7 +451,7 @@ services: - ./src:/usr/src/code/src depends_on: - redis - - mariadb + - ${_APP_DB_HOST:-mariadb} environment: - _APP_ENV - _APP_WORKER_PER_CORE @@ -461,6 +466,7 @@ services: - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_LOGGING_CONFIG - _APP_WORKERS_NUM - _APP_QUEUE_NAME @@ -481,7 +487,7 @@ services: - ./src:/usr/src/code/src depends_on: - redis - - mariadb + - ${_APP_DB_HOST:-mariadb} environment: - _APP_ENV - _APP_WORKER_PER_CORE @@ -498,6 +504,7 @@ services: - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_LOGGING_CONFIG - _APP_VCS_GITHUB_APP_NAME - _APP_VCS_GITHUB_PRIVATE_KEY @@ -609,7 +616,7 @@ services: - appwrite depends_on: - redis - - mariadb + - ${_APP_DB_HOST:-mariadb} volumes: - appwrite-config:/storage/config:rw - appwrite-certificates:/storage/certificates:rw @@ -638,6 +645,7 @@ services: - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_LOGGING_CONFIG - _APP_DATABASE_SHARED_TABLES @@ -683,12 +691,8 @@ services: - ./app:/usr/src/code/app - ./src:/usr/src/code/src depends_on: - redis: - condition: service_started - mariadb: - condition: service_started - openruntimes-executor: - condition: service_healthy + - ${_APP_DB_HOST:-mariadb} + - redis environment: - _APP_ENV - _APP_WORKER_PER_CORE @@ -705,6 +709,7 @@ services: - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_FUNCTIONS_TIMEOUT - _APP_SITES_TIMEOUT - _APP_COMPUTE_BUILD_TIMEOUT @@ -782,6 +787,7 @@ services: - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_LOGGING_CONFIG - _APP_SMS_FROM - _APP_SMS_PROVIDER @@ -825,7 +831,7 @@ services: - ./src:/usr/src/code/src - ./tests:/usr/src/code/tests depends_on: - - mariadb + - ${_APP_DB_HOST:-mariadb} environment: - _APP_ENV - _APP_WORKER_PER_CORE @@ -847,6 +853,7 @@ services: - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_LOGGING_CONFIG - _APP_MIGRATIONS_FIREBASE_CLIENT_ID - _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET @@ -888,6 +895,7 @@ services: - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_MAINTENANCE_INTERVAL - _APP_MAINTENANCE_RETENTION_EXECUTION - _APP_MAINTENANCE_RETENTION_CACHE @@ -950,7 +958,7 @@ services: - ./src:/usr/src/code/src depends_on: - redis - - mariadb + - ${_APP_DB_HOST:-mariadb} environment: - _APP_ENV - _APP_WORKER_PER_CORE @@ -961,6 +969,7 @@ services: - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER @@ -982,7 +991,7 @@ services: - ./src:/usr/src/code/src depends_on: - redis - - mariadb + - ${_APP_DB_HOST:-mariadb} environment: - _APP_ENV - _APP_WORKER_PER_CORE @@ -993,6 +1002,7 @@ services: - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER @@ -1014,7 +1024,7 @@ services: - ./src:/usr/src/code/src depends_on: - redis - - mariadb + - ${_APP_DB_HOST:-mariadb} environment: - _APP_ENV - _APP_WORKER_PER_CORE @@ -1025,6 +1035,7 @@ services: - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER @@ -1045,7 +1056,7 @@ services: - ./app:/usr/src/code/app - ./src:/usr/src/code/src depends_on: - - mariadb + - ${_APP_DB_HOST:-mariadb} - redis environment: - _APP_ENV @@ -1061,6 +1072,7 @@ services: - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_DATABASE_SHARED_TABLES appwrite-task-scheduler-executions: @@ -1074,7 +1086,7 @@ services: - ./app:/usr/src/code/app - ./src:/usr/src/code/src depends_on: - - mariadb + - ${_APP_DB_HOST:-mariadb} - redis environment: - _APP_ENV @@ -1090,6 +1102,7 @@ services: - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER appwrite-task-scheduler-messages: entrypoint: schedule-messages @@ -1102,7 +1115,7 @@ services: - ./app:/usr/src/code/app - ./src:/usr/src/code/src depends_on: - - mariadb + - ${_APP_DB_HOST:-mariadb} - redis environment: - _APP_ENV @@ -1118,6 +1131,7 @@ services: - _APP_DB_SCHEMA - _APP_DB_USER - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_DATABASE_SHARED_TABLES appwrite-assistant: @@ -1211,6 +1225,22 @@ services: - MARIADB_AUTO_UPGRADE=1 command: "mysqld --innodb-flush-method=fsync" + postgresql: + image: postgres:18 + container_name: appwrite-postgresql + <<: *x-logging + networks: + - appwrite + volumes: + - appwrite-postgresql:/var/lib/postgresql/data:rw + ports: + - "5432:5432" + environment: + - POSTGRES_DB=${_APP_DB_SCHEMA} + - POSTGRES_USER=${_APP_DB_USER} + - POSTGRES_PASSWORD=${_APP_DB_PASS} + command: "postgres" + redis: image: redis:7.2.4-alpine <<: *x-logging @@ -1438,6 +1468,7 @@ configs: volumes: appwrite-mariadb: + appwrite-postgresql: appwrite-redis: appwrite-cache: appwrite-uploads: diff --git a/src/Appwrite/Platform/Tasks/Install.php b/src/Appwrite/Platform/Tasks/Install.php index e51ea3188a..c3e5576fa3 100644 --- a/src/Appwrite/Platform/Tasks/Install.php +++ b/src/Appwrite/Platform/Tasks/Install.php @@ -32,10 +32,11 @@ class Install extends Action ->param('image', 'appwrite', new Text(0), 'Main appwrite docker image', true) ->param('interactive', 'Y', new Text(1), 'Run an interactive session', true) ->param('no-start', false, new Boolean(true), 'Run an interactive session', true) + ->param('database', 'mariadb', new Text(0), 'Database to use (mariadb|postgresql)', true) ->callback($this->action(...)); } - public function action(string $httpPort, string $httpsPort, string $organization, string $image, string $interactive, bool $noStart): void + public function action(string $httpPort, string $httpsPort, string $organization, string $image, string $interactive, bool $noStart, string $database): void { $config = Config::getParam('variables'); $defaultHTTPPort = '80'; @@ -138,6 +139,7 @@ class Install extends Action } } + if (empty($httpPort)) { $httpPort = Console::confirm('Choose your server HTTP port: (default: ' . $defaultHTTPPort . ')'); $httpPort = ($httpPort) ? $httpPort : $defaultHTTPPort; @@ -226,6 +228,11 @@ class Install extends Action continue; } + if ($var['name'] === '_APP_DB_ADAPTER' && $data !== false) { + $input[$var['name']] = $database; + continue; + } + $input[$var['name']] = Console::confirm($var['question'] . ' (default: \'' . $var['default'] . '\')'); if (empty($input[$var['name']])) { @@ -242,17 +249,25 @@ class Install extends Action } } } + $database = $input['_APP_DB_ADAPTER']; + if ($database === 'postgresql') { + $input['_APP_DB_HOST'] = 'postgresql'; + $input['_APP_DB_PORT'] = 5432; + } elseif ($database === 'mariadb') { + $input['_APP_DB_HOST'] = 'mariadb'; + $input['_APP_DB_PORT'] = 3306; + } $templateForCompose = new View(__DIR__ . '/../../../../app/views/install/compose.phtml'); $templateForEnv = new View(__DIR__ . '/../../../../app/views/install/env.phtml'); - $templateForCompose ->setParam('httpPort', $httpPort) ->setParam('httpsPort', $httpsPort) ->setParam('version', APP_VERSION_STABLE) ->setParam('organization', $organization) ->setParam('image', $image) - ->setParam('enableAssistant', $enableAssistant); + ->setParam('enableAssistant', $enableAssistant) + ->setParam('database', $database); $templateForEnv->setParam('vars', $input); diff --git a/src/Appwrite/Platform/Tasks/Upgrade.php b/src/Appwrite/Platform/Tasks/Upgrade.php index d6159d2718..5b9a9e1f3a 100644 --- a/src/Appwrite/Platform/Tasks/Upgrade.php +++ b/src/Appwrite/Platform/Tasks/Upgrade.php @@ -3,6 +3,7 @@ namespace Appwrite\Platform\Tasks; use Utopia\CLI\Console; +use Utopia\System\System; use Utopia\Validator\Boolean; use Utopia\Validator\Text; @@ -23,10 +24,11 @@ class Upgrade extends Install ->param('image', 'appwrite', new Text(0), 'Main appwrite docker image', true) ->param('interactive', 'Y', new Text(1), 'Run an interactive session', true) ->param('no-start', false, new Boolean(true), 'Run an interactive session', true) + ->param('database', 'mariadb', new Text(length: 0), 'Database to use (mariadb|postgresql)', true) ->callback($this->action(...)); } - public function action(string $httpPort, string $httpsPort, string $organization, string $image, string $interactive, bool $noStart): void + public function action(string $httpPort, string $httpsPort, string $organization, string $image, string $interactive, bool $noStart, string $database): void { // Check for previous installation $data = @file_get_contents($this->path . '/docker-compose.yml'); @@ -39,6 +41,7 @@ class Upgrade extends Install Console::log(' └── docker-compose.yml'); Console::exit(1); } - parent::action($httpPort, $httpsPort, $organization, $image, $interactive, $noStart); + $database = System::getEnv('_APP_DB_ADAPTER', 'mariadb'); + parent::action($httpPort, $httpsPort, $organization, $image, $interactive, $noStart, $database); } } diff --git a/tests/e2e/Services/Sites/SitesBase.php b/tests/e2e/Services/Sites/SitesBase.php index e7af09d1d9..239237c8b1 100644 --- a/tests/e2e/Services/Sites/SitesBase.php +++ b/tests/e2e/Services/Sites/SitesBase.php @@ -335,21 +335,28 @@ trait SitesBase protected function helperGetLatestCommit(string $owner, string $repository): ?string { - $ch = curl_init("https://api.github.com/repos/{$owner}/{$repository}/commits/main"); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLOPT_HTTPHEADER, [ - 'User-Agent: Appwrite', - 'Accept: application/vnd.github.v3+json' - ]); + $maxRetries = 3; + for ($attempt = 0; $attempt < $maxRetries; $attempt++) { + if ($attempt > 0) { + sleep(5); + } - $response = curl_exec($ch); - $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); - curl_close($ch); + $ch = curl_init("https://api.github.com/repos/{$owner}/{$repository}/commits/main"); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + 'User-Agent: Appwrite', + 'Accept: application/vnd.github.v3+json' + ]); - if ($httpCode === 200) { - $commitData = json_decode($response, true); - if (isset($commitData['sha'])) { - return $commitData['sha']; + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + if ($httpCode === 200) { + $commitData = json_decode($response, true); + if (isset($commitData['sha'])) { + return $commitData['sha']; + } } }