diff --git a/Dockerfile b/Dockerfile index 67e8606c2..e2ce94578 100755 --- a/Dockerfile +++ b/Dockerfile @@ -143,8 +143,10 @@ RUN mkdir -p /storage/uploads && \ # Executables RUN chmod +x /usr/local/bin/doctor && \ + chmod +x /usr/local/bin/install && \ chmod +x /usr/local/bin/migrate && \ chmod +x /usr/local/bin/schedule && \ + chmod +x /usr/local/bin/ssl && \ chmod +x /usr/local/bin/test && \ chmod +x /usr/local/bin/worker-audits && \ chmod +x /usr/local/bin/worker-certificates && \ diff --git a/README.md b/README.md index e107a3b93..a48e764fc 100644 --- a/README.md +++ b/README.md @@ -50,9 +50,8 @@ The easiest way to start running your Appwrite server is by running our docker-c ```bash docker run -it --rm \ --volume /var/run/docker.sock:/var/run/docker.sock \ - --volume "$(pwd)"/appwrite:/install/appwrite:rw \ - -e version=0.7.0 \ - appwrite/install + --volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \ + appwrite/appwrite:0.7.0 ``` ### Windows @@ -62,9 +61,8 @@ docker run -it --rm \ ```cmd docker run -it --rm ^ --volume //var/run/docker.sock:/var/run/docker.sock ^ - --volume "%cd%"/appwrite:/install/appwrite:rw ^ - -e version=0.7.0 ^ - appwrite/install + --volume "%cd%"/appwrite:/usr/src/code/appwrite:rw ^ + appwrite/appwrite:0.7.0 ``` #### PowerShell @@ -72,9 +70,8 @@ docker run -it --rm ^ ```powershell docker run -it --rm , --volume /var/run/docker.sock:/var/run/docker.sock , - --volume ${pwd}/appwrite:/install/appwrite:rw , - -e version=0.7.0 , - appwrite/install + --volume ${pwd}/appwrite:/usr/src/code/appwrite:rw , + appwrite/appwrite:0.7.0 ``` Once the Docker installation completes, go to http://localhost to access the Appwrite console from your browser. Please note that on non-linux native hosts, the server might take a few minutes to start after installation completes. diff --git a/app/cli.php b/app/cli.php new file mode 100644 index 000000000..9eede27a3 --- /dev/null +++ b/app/cli.php @@ -0,0 +1,25 @@ +#!/bin/env php +task('version') + ->desc('Get the server version') + ->action(function () { + Console::log(App::getEnv('_APP_VERSION', 'UNKNOWN')); + }); + +$cli->run(); \ No newline at end of file diff --git a/app/config/services.php b/app/config/services.php index cf5ee4392..e500f9a24 100644 --- a/app/config/services.php +++ b/app/config/services.php @@ -3,96 +3,96 @@ return [ '/' => [ 'name' => 'Homepage', - 'controller' => 'controllers/web/home.php', + 'controller' => 'web/home.php', 'sdk' => false, 'tests' => false, ], 'console/' => [ 'name' => 'Console', - 'controller' => 'controllers/web/console.php', + 'controller' => 'web/console.php', 'sdk' => false, 'tests' => false, ], 'v1/account' => [ 'name' => 'Account', 'description' => '/docs/services/account.md', - 'controller' => 'controllers/api/account.php', + 'controller' => 'api/account.php', 'sdk' => true, 'tests' => false, ], 'v1/avatars' => [ 'name' => 'Avatars', 'description' => '/docs/services/avatars.md', - 'controller' => 'controllers/api/avatars.php', + 'controller' => 'api/avatars.php', 'sdk' => true, 'tests' => false, ], 'v1/database' => [ 'name' => 'Database', 'description' => '/docs/services/database.md', - 'controller' => 'controllers/api/database.php', + 'controller' => 'api/database.php', 'sdk' => true, 'tests' => false, ], 'v1/locale' => [ 'name' => 'Locale', 'description' => '/docs/services/locale.md', - 'controller' => 'controllers/api/locale.php', + 'controller' => 'api/locale.php', 'sdk' => true, 'tests' => false, ], 'v1/health' => [ 'name' => 'Health', 'description' => '/docs/services/health.md', - 'controller' => 'controllers/api/health.php', + 'controller' => 'api/health.php', 'sdk' => true, 'tests' => false, ], 'v1/projects' => [ 'name' => 'Projects', - 'controller' => 'controllers/api/projects.php', + 'controller' => 'api/projects.php', 'sdk' => true, 'tests' => false, ], 'v1/storage' => [ 'name' => 'Storage', 'description' => '/docs/services/storage.md', - 'controller' => 'controllers/api/storage.php', + 'controller' => 'api/storage.php', 'sdk' => true, 'tests' => false, ], 'v1/teams' => [ 'name' => 'Teams', 'description' => '/docs/services/teams.md', - 'controller' => 'controllers/api/teams.php', + 'controller' => 'api/teams.php', 'sdk' => true, 'tests' => false, ], 'v1/users' => [ 'name' => 'Users', 'description' => '/docs/services/users.md', - 'controller' => 'controllers/api/users.php', + 'controller' => 'api/users.php', 'sdk' => true, 'tests' => false, ], 'v1/functions' => [ 'name' => 'Users', 'description' => '/docs/services/functions.md', - 'controller' => 'controllers/api/functions.php', + 'controller' => 'api/functions.php', 'sdk' => true, 'tests' => false, ], 'v1/mock' => [ 'name' => 'Mock', 'description' => '', - 'controller' => 'controllers/mock.php', + 'controller' => 'mock.php', 'sdk' => false, 'tests' => true, ], 'v1/graphql' => [ 'name' => 'GraphQL', 'description' => 'GraphQL Endpoint', - 'controller' => 'controllers/api/graphql.php', + 'controller' => 'api/graphql.php', 'sdk' => false, 'tests' => false, ], diff --git a/app/config/variables.php b/app/config/variables.php new file mode 100644 index 000000000..c1b998276 --- /dev/null +++ b/app/config/variables.php @@ -0,0 +1,136 @@ + '_APP_ENV', + 'default' => 'production', + 'required' => false, + 'question' => '', + ], + [ + 'name' => '_APP_OPTIONS_ABUSE', + 'default' => 'enabled', + 'required' => false, + 'question' => '', + ], + [ + 'name' => '_APP_OPTIONS_FORCE_HTTPS', + 'default' => 'enabled', + 'required' => false, + 'question' => '', + ], + [ + 'name' => '_APP_OPENSSL_KEY_V1', + 'default' => 'your-secret-key', + 'required' => true, + 'question' => 'Choose a secret API key, make sure to make a backup of your key in a secure location', + ], + [ + 'name' => '_APP_DOMAIN', + 'default' => 'localhost', + 'required' => true, + 'question' => 'Enter your Appwrite hostname', + ], + [ + 'name' => '_APP_DOMAIN_TARGET', + 'default' => 'localhost', + 'required' => true, + 'question' => "Enter a DNS A record hostname to serve as a CNAME for your custom domains.\nYou can use the same value as used for the Appwrite hostname.", + ], + [ + 'name' => '_APP_REDIS_HOST', + 'default' => 'redis', + 'required' => false, + 'question' => '', + ], + [ + 'name' => '_APP_REDIS_PORT', + 'default' => '6379', + 'required' => false, + 'question' => '', + ], + [ + 'name' => '_APP_DB_HOST', + 'default' => 'mariadb', + 'required' => false, + 'question' => '', + ], + [ + 'name' => '_APP_DB_PORT', + 'default' => '3306', + 'required' => false, + 'question' => '', + ], + [ + 'name' => '_APP_DB_SCHEMA', + 'default' => 'appwrite', + 'required' => false, + 'question' => '', + ], + [ + 'name' => '_APP_DB_USER', + 'default' => 'user', + 'required' => false, + 'question' => '', + ], + [ + 'name' => '_APP_DB_PASS', + 'default' => 'password', + 'required' => false, + 'question' => '', + ], + [ + 'name' => '_APP_INFLUXDB_HOST', + 'default' => 'influxdb', + 'required' => false, + 'question' => '', + ], + [ + 'name' => '_APP_INFLUXDB_PORT', + 'default' => '8086', + 'required' => false, + 'question' => '', + ], + [ + 'name' => '_APP_STATSD_HOST', + 'default' => 'telegraf', + 'required' => false, + 'question' => '', + ], + [ + 'name' => '_APP_STATSD_PORT', + 'default' => '8125', + 'required' => false, + 'question' => '', + ], + [ + 'name' => '_APP_SMTP_HOST', + 'default' => 'smtp', + 'required' => false, + 'question' => '', + ], + [ + 'name' => '_APP_SMTP_PORT', + 'default' => '25', + 'required' => false, + 'question' => '', + ], + [ + 'name' => '_APP_STORAGE_LIMIT', + 'default' => '100000000', + 'required' => false, + 'question' => '', + ], + [ + 'name' => '_APP_FUNCTIONS_TIMEOUT', + 'default' => '900', + 'required' => false, + 'question' => '', + ], + [ + 'name' => '_APP_FUNCTIONS_CONTAINERS', + 'default' => '10', + 'required' => false, + 'question' => '', + ], +]; \ No newline at end of file diff --git a/app/app.php b/app/controllers/general.php similarity index 99% rename from app/app.php rename to app/controllers/general.php index d14e126c7..1a5ea470e 100644 --- a/app/app.php +++ b/app/controllers/general.php @@ -1,6 +1,6 @@ text($content); }, ['request', 'response']); -include_once __DIR__ . '/controllers/shared/api.php'; -include_once __DIR__ . '/controllers/shared/web.php'; +include_once __DIR__ . '/shared/api.php'; +include_once __DIR__ . '/shared/web.php'; foreach(Config::getParam('services', []) as $service) { include_once $service['controller']; diff --git a/app/http.php b/app/http.php index 1c93d9d21..f5438cad9 100644 --- a/app/http.php +++ b/app/http.php @@ -63,7 +63,7 @@ $http->on('start', function (Server $http) use ($payloadSize) { Files::load(__DIR__ . '/../public'); -include __DIR__ . '/app.php'; +include __DIR__ . '/controllers/general.php'; $domain = App::getEnv('_APP_DOMAIN', ''); diff --git a/app/init.php b/app/init.php index a009b13fb..66c131fb3 100644 --- a/app/init.php +++ b/app/init.php @@ -67,6 +67,7 @@ Config::load('environments', __DIR__.'/config/environments.php'); Config::load('roles', __DIR__.'/config/roles.php'); // User roles and scopes Config::load('scopes', __DIR__.'/config/scopes.php'); // User roles and scopes Config::load('services', __DIR__.'/config/services.php'); // List of services +Config::load('variables', __DIR__.'/config/variables.php'); // List of env variables Config::load('avatar-browsers', __DIR__.'/config/avatars/browsers.php'); Config::load('avatar-credit-cards', __DIR__.'/config/avatars/credit-cards.php'); Config::load('avatar-flags', __DIR__.'/config/avatars/flags.php'); diff --git a/app/preload.php b/app/preload.php index 7e5fe6654..63d08c3e1 100644 --- a/app/preload.php +++ b/app/preload.php @@ -18,8 +18,7 @@ if (file_exists(__DIR__.'/../vendor/autoload.php')) { use Appwrite\Preloader\Preloader; -include 'init.php'; -include 'app.php'; +include __DIR__.'/controllers/general.php'; (new Preloader()) ->paths(realpath(__DIR__ . '/../app/config')) diff --git a/app/tasks/doctor.php b/app/tasks/doctor.php index 485e237eb..c28b4d229 100644 --- a/app/tasks/doctor.php +++ b/app/tasks/doctor.php @@ -1,18 +1,14 @@ -#!/bin/env php task('doctor') ->desc('Validate server health') @@ -237,5 +233,3 @@ $cli Console::error('Failed to check for a newer version'."\n"); } }); - -$cli->run(); diff --git a/app/tasks/init.php b/app/tasks/init.php deleted file mode 100644 index 63f754b5a..000000000 --- a/app/tasks/init.php +++ /dev/null @@ -1,259 +0,0 @@ -#!/bin/env php -task('ssl') - ->desc('Validate server certificates') - ->action(function () { - $domain = App::getEnv('_APP_DOMAIN', ''); - - Console::log('Issue a TLS certificate for master domain ('.$domain.') in 30 seconds. - Make sure your domain points to your server or restart to try again.'); - - ResqueScheduler::enqueueAt(\time() + 30, 'v1-certificates', 'CertificatesV1', [ - 'document' => [], - 'domain' => $domain, - 'validateTarget' => false, - 'validateCNAME' => false, - ]); - }); - -$cli - ->task('doctor') - ->desc('Validate server health') - ->action(function () use ($register) { - Console::log(" __ ____ ____ _ _ ____ __ ____ ____ __ __ - / _\ ( _ \( _ \/ )( \( _ \( )(_ _)( __) ( )/ \ -/ \ ) __/ ) __/\ /\ / ) / )( )( ) _) _ )(( O ) -\_/\_/(__) (__) (_/\_)(__\_)(__) (__) (____)(_)(__)\__/ "); - - Console::log("\n".'👩‍⚕️ Running '.APP_NAME.' Doctor for version '.App::getEnv('_APP_VERSION', 'UNKNOWN').' ...'."\n"); - - Console::log('Checking for production best practices...'); - - $domain = new Domain(App::getEnv('_APP_DOMAIN')); - - if(!$domain->isKnown() || $domain->isTest()) { - Console::log('🔴 Hostname has a public suffix'); - } - else { - Console::log('🟢 Hostname has a public suffix'); - } - - $domain = new Domain(App::getEnv('_APP_DOMAIN_TARGET')); - - if(!$domain->isKnown() || $domain->isTest()) { - Console::log('🔴 CNAME target has a public suffix'); - } - else { - Console::log('🟢 CNAME target has a public suffix'); - } - - if(App::getEnv('_APP_OPENSSL_KEY_V1', 'your-secret-key') === 'your-secret-key') { - Console::log('🔴 Using a unique secret key for encryption'); - } - else { - Console::log('🟢 Using a unique secret key for encryption'); - } - - if(App::getEnv('_APP_ENV', 'development') === 'development') { - Console::log('🔴 App enviornment is set for production'); - } - else { - Console::log('🟢 App enviornment is set for production'); - } - - if(App::getEnv('_APP_OPTIONS_ABUSE', 'disabled') === 'disabled') { - Console::log('🔴 Abuse protection is enabled'); - } - else { - Console::log('🟢 Abuse protection is enabled'); - } - - $authWhitelistEmails = App::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null); - $authWhitelistIPs = App::getEnv('_APP_CONSOLE_WHITELIST_IPS', null); - $authWhitelistDomains = App::getEnv('_APP_CONSOLE_WHITELIST_DOMAINS', null); - - if(empty($authWhitelistEmails) - && empty($authWhitelistDomains) - && empty($authWhitelistIPs) - ) { - Console::log('🔴 Console access limits are disabled'); - } - else { - Console::log('🟢 Console access limits are enabled'); - } - - if(empty(App::getEnv('_APP_OPTIONS_FORCE_HTTPS', null))) { - Console::log('🔴 HTTP force option is disabled'); - } - else { - Console::log('🟢 HTTP force option is enabled'); - } - - \sleep(0.2); - - try { - Console::log("\n".'Checking connectivity...'); - } catch (\Throwable $th) { - //throw $th; - } - - try { - $register->get('db'); /* @var $db PDO */ - Console::success('Database............connected 👍'); - } catch (\Throwable $th) { - Console::error('Database.........disconnected 👎'); - } - - try { - $register->get('cache'); - Console::success('Queue...............connected 👍'); - } catch (\Throwable $th) { - Console::error('Queue............disconnected 👎'); - } - - try { - $register->get('cache'); - Console::success('Cache...............connected 👍'); - } catch (\Throwable $th) { - Console::error('Cache............disconnected 👎'); - } - - if(App::getEnv('_APP_STORAGE_ANTIVIRUS') === 'enabled') { // Check if scans are enabled - try { - $antiVirus = new Network('clamav', 3310); - - if((@$antiVirus->ping())) { - Console::success('AntiVirus...........connected 👍'); - } - else { - Console::error('AntiVirus........disconnected 👎'); - } - } catch (\Throwable $th) { - Console::error('AntiVirus........disconnected 👎'); - } - } - - try { - $mail = $register->get('smtp'); /* @var $mail \PHPMailer\PHPMailer\PHPMailer */ - - $mail->addAddress('demo@example.com', 'Example.com'); - $mail->Subject = 'Test SMTP Connection'; - $mail->Body = 'Hello World'; - $mail->AltBody = 'Hello World'; - - $mail->send(); - Console::success('SMTP................connected 👍'); - } catch (\Throwable $th) { - Console::error('SMTP.............disconnected 👎'); - } - - $host = App::getEnv('_APP_STATSD_HOST', 'telegraf'); - $port = App::getEnv('_APP_STATSD_PORT', 8125); - - if($fp = @\fsockopen('udp://'.$host, $port, $errCode, $errStr, 2)){ - Console::success('StatsD..............connected 👍'); - \fclose($fp); - } else { - Console::error('StatsD...........disconnected 👎'); - } - - $host = App::getEnv('_APP_INFLUXDB_HOST', ''); - $port = App::getEnv('_APP_INFLUXDB_PORT', ''); - - if($fp = @\fsockopen($host, $port, $errCode, $errStr, 2)){ - Console::success('InfluxDB............connected 👍'); - \fclose($fp); - } else { - Console::error('InfluxDB.........disconnected 👎'); - } - - \sleep(0.2); - - Console::log(''); - Console::log('Checking volumes...'); - - foreach ([ - 'Uploads' => APP_STORAGE_UPLOADS, - 'Cache' => APP_STORAGE_CACHE, - 'Config' => APP_STORAGE_CONFIG, - 'Certs' => APP_STORAGE_CERTIFICATES - ] as $key => $volume) { - $device = new Local($volume); - - if (\is_readable($device->getRoot())) { - Console::success('🟢 '.$key.' Volume is readable'); - } - else { - Console::error('🔴 '.$key.' Volume is unreadable'); - } - - if (\is_writable($device->getRoot())) { - Console::success('🟢 '.$key.' Volume is writeable'); - } - else { - Console::error('🔴 '.$key.' Volume is unwriteable'); - } - } - - \sleep(0.2); - - Console::log(''); - Console::log('Checking disk space usage...'); - - foreach ([ - 'Uploads' => APP_STORAGE_UPLOADS, - 'Cache' => APP_STORAGE_CACHE, - 'Config' => APP_STORAGE_CONFIG, - 'Certs' => APP_STORAGE_CERTIFICATES - ] as $key => $volume) { - $device = new Local($volume); - - $percentage = (($device->getPartitionTotalSpace() - $device->getPartitionFreeSpace()) - / $device->getPartitionTotalSpace()) * 100; - - $message = $key.' Volume has '.Storage::human($device->getPartitionFreeSpace()) . ' free space ('.\round($percentage, 2).'% used)'; - - if ($percentage < 80) { - Console::success('🟢 ' . $message); - } - else { - Console::error('🔴 ' . $message); - } - } - - - try { - Console::log(''); - $version = \json_decode(@\file_get_contents(App::getEnv('_APP_HOME', 'http://localhost').'/v1/health/version'), true); - - if($version && isset($version['version'])) { - if(\version_compare($version['version'], App::getEnv('_APP_VERSION', 'UNKNOWN')) === 0) { - Console::info('You are running the latest version of '.APP_NAME.'! 🥳'); - } - else { - Console::info('A new version ('.$version['version'].') is available! 🥳'."\n"); - } - } - else { - Console::error('Failed to check for a newer version'."\n"); - } - } catch (\Throwable $th) { - Console::error('Failed to check for a newer version'."\n"); - } - }); - -$cli->run(); diff --git a/app/tasks/install.php b/app/tasks/install.php new file mode 100644 index 000000000..3b3aa4ea6 --- /dev/null +++ b/app/tasks/install.php @@ -0,0 +1,152 @@ +task('install') + ->desc('Install Appwrite') + ->action(function () { + /** + * 1. Start - DONE + * 2. Check for older setup and get older version - DONE + * 2.1 If older version is equal or bigger(?) than current version, **stop setup** + * 2.2. Get ENV vars - DONE + * 2.2.1 Fetch from older docker-compose.yml file + * 2.2.2 Fetch from older .env file (manually parse) + * 2.3 Use old ENV vars as default values + * 2.4 Ask for all required vars not given as CLI args and if in interactive mode + * Otherwise, just use default vars. - DONE + * 3. Ask user to backup important volumes, env vars, and SQL tables + * In th future we can try and automate this for smaller/medium size setups + * 4. Drop new docker-compose.yml setup (located inside the container, no network dependencies with appwrite.io) - DONE + * 5. Run docker-compose up -d - DONE + * 6. Run data migration + */ + $vars = Config::getParam('variables'); + $path = '/usr/src/code/appwrite'; + $version = null; + $defaultHTTPPort = '80'; + $defaultHTTPSPort = '443'; + + Console::success('Starting Appwrite installation...'); + + // Create directory with write permissions + if (null !== $path && !\file_exists(\dirname($path))) { + if (!@\mkdir(\dirname($path), 0755, true)) { + Console::error('Can\'t create directory '.\dirname($path)); + exit(1); + } + } + + $data = @file_get_contents($path.'/docker-compose.yml'); + + if($data !== false) { + $compose = new Compose($data); + $appwrite = $compose->getService('appwrite'); + $version = ($appwrite) ? $appwrite->getImageVersion() : $version; + $ports = $compose->getService('traefik')->getPorts(); + + if($version) { + foreach($compose->getServices() as $service) { // Fetch all env vars from previous compose file + if(!$service) { + continue; + } + + $env = $service->getEnvironment()->list(); + + foreach ($env as $key => $value) { + foreach($vars as &$var) { + if($var['name'] === $key) { + $var['default'] = $value; + } + } + } + } + + $data = @file_get_contents($path.'/.env'); + + if($data !== false) { // Fetch all env vars from previous .env file + $env = new Env($data); + + foreach ($env->list() as $key => $value) { + foreach($vars as &$var) { + if($var['name'] === $key) { + $var['default'] = $value; + } + } + } + } + + foreach ($ports as $key => $value) { + if($value === $defaultHTTPPort) { + $defaultHTTPPort = $key; + } + + if($value === $defaultHTTPSPort) { + $defaultHTTPSPort = $key; + } + } + } + } + + $httpPort = Console::confirm('Choose your server HTTP port: (default: '.$defaultHTTPPort.')'); + $httpPort = ($httpPort) ? $httpPort : $defaultHTTPPort; + + $httpsPort = Console::confirm('Choose your server HTTPS port: (default: '.$defaultHTTPSPort.')'); + $httpsPort = ($httpsPort) ? $httpsPort : $defaultHTTPPort; + + $input = []; + + foreach($vars as $key => $var) { + if(!$var['required']) { + $input[$var['name']] = $var['default']; + continue; + } + + $input[$var['name']] = Console::confirm($var['question'].' (default: \''.$var['default'].'\')'); + + if(empty($input[$key])) { + $input[$var['name']] = $var['default']; + } + } + + $templateForCompose = new View(__DIR__.'/../views/install/compose.phtml'); + $templateForEnv = new View(__DIR__.'/../views/install/env.phtml'); + + $templateForCompose + ->setParam('httpPort', $httpPort) + ->setParam('httpsPort', $httpsPort) + ->setParam('version', APP_VERSION_STABLE) + ; + + $templateForEnv + ->setParam('vars', $input) + ; + + if(!file_put_contents($path.'/docker-compose.yml', $templateForCompose->render(false))) { + Console::error('Failed to save Docker Compose file'); + exit(1); + } + + if(!file_put_contents($path.'/.env', $templateForEnv->render(false))) { + Console::error('Failed to save environment variables file'); + exit(1); + } + + $stdout = ''; + $stderr = ''; + + //Console::execute("docker-compose -f {$path}.'/docker-compose.yml up -d --remove-orphans", null, $stdout, $stderr); + + if ($stderr !== '') { + Console::error("Failed to install Appwrite dockers"); + } else { + Console::success("Appwrite installed successfully"); + } + }); \ No newline at end of file diff --git a/app/tasks/migrate.php b/app/tasks/migrate.php index 3e3eec30c..efa06e1fe 100644 --- a/app/tasks/migrate.php +++ b/app/tasks/migrate.php @@ -1,18 +1,13 @@ -#!/bin/env php get('db'); $callbacks = [ @@ -152,9 +147,7 @@ function fixDocument(Document $document) { ->removeAttribute('$uid') ; - //Console::log('Switched from $uid to $id: '.$document->getCollection().'/'.$document->getId()); - - foreach($document as &$attr) { + foreach($document as &$attr) { // Handle child documents if($attr instanceof Document) { $attr = fixDocument($attr); } @@ -172,7 +165,7 @@ function fixDocument(Document $document) { } $cli - ->task('run') + ->task('migrate') ->action(function () use ($console, $projectDB, $consoleDB, $callbacks) { Console::success('Starting Data Migration'); @@ -214,6 +207,4 @@ $cli } Console::success('Data Migration Completed'); - }); - -$cli->run(); + }); \ No newline at end of file diff --git a/app/tasks/sdks.php b/app/tasks/sdks.php index bab19d108..b70dbc7be 100644 --- a/app/tasks/sdks.php +++ b/app/tasks/sdks.php @@ -1,10 +1,8 @@ -#!/bin/env php run(); + }); \ No newline at end of file diff --git a/app/tasks/ssl.php b/app/tasks/ssl.php new file mode 100644 index 000000000..2c32324fa --- /dev/null +++ b/app/tasks/ssl.php @@ -0,0 +1,23 @@ +task('ssl') + ->desc('Validate server certificates') + ->action(function () { + $domain = App::getEnv('_APP_DOMAIN', ''); + + Console::log('Issue a TLS certificate for master domain ('.$domain.') in 30 seconds. + Make sure your domain points to your server or restart to try again.'); + + ResqueScheduler::enqueueAt(\time() + 30, 'v1-certificates', 'CertificatesV1', [ + 'document' => [], + 'domain' => $domain, + 'validateTarget' => false, + 'validateCNAME' => false, + ]); + }); \ No newline at end of file diff --git a/app/views/install/compose.phtml b/app/views/install/compose.phtml new file mode 100644 index 000000000..7df932c9e --- /dev/null +++ b/app/views/install/compose.phtml @@ -0,0 +1,327 @@ +getParam('httpPort', ''); +$httpsPort = $this->getParam('httpsPort', ''); +$version = $this->getParam('version', ''); +?>version: '3' + +services: + traefik: + image: traefik:2.2 + container_name: appwrite-traefik + command: + - --providers.file.directory=/storage/config + - --providers.file.watch=true + - --providers.docker=true + - --entrypoints.web.address=:80 + - --entrypoints.websecure.address=:443 + restart: unless-stopped + ports: + - :80 + - :443 + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - appwrite-config:/storage/config:ro + - appwrite-certificates:/storage/certificates:ro + depends_on: + - appwrite + networks: + - gateway + - appwrite + + appwrite: + image: appwrite/appwrite: + container_name: appwrite + restart: unless-stopped + networks: + - appwrite + labels: + - traefik.http.routers.appwrite.rule=PathPrefix(`/`) + - traefik.http.routers.appwrite-secure.rule=PathPrefix(`/`) + - traefik.http.routers.appwrite-secure.tls=true + volumes: + - appwrite-uploads:/storage/uploads:rw + - appwrite-cache:/storage/cache:rw + - appwrite-config:/storage/config:rw + - appwrite-certificates:/storage/certificates:rw + - appwrite-functions:/storage/functions:rw + depends_on: + - mariadb + - redis + - clamav + - influxdb + environment: + - _APP_ENV + - _APP_OPTIONS_ABUSE + - _APP_OPTIONS_FORCE_HTTPS + - _APP_OPENSSL_KEY_V1 + - _APP_DOMAIN + - _APP_DOMAIN_TARGET + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS + - _APP_INFLUXDB_HOST + - _APP_INFLUXDB_PORT + - _APP_STORAGE_LIMIT + - _APP_FUNCTIONS_TIMEOUT + - _APP_FUNCTIONS_CONTAINERS + + appwrite-worker-usage: + image: appwrite/appwrite: + entrypoint: worker-usage + container_name: appwrite-worker-usage + restart: unless-stopped + networks: + - appwrite + depends_on: + - redis + - telegraf + environment: + - _APP_ENV + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_STATSD_HOST + - _APP_STATSD_PORT + + appwrite-worker-audits: + image: appwrite/appwrite: + entrypoint: worker-audits + container_name: appwrite-worker-audits + restart: unless-stopped + networks: + - appwrite + depends_on: + - redis + - mariadb + environment: + - _APP_ENV + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS + + appwrite-worker-webhooks: + image: appwrite/appwrite: + entrypoint: worker-webhooks + container_name: appwrite-worker-webhooks + restart: unless-stopped + networks: + - appwrite + depends_on: + - redis + - mariadb + environment: + - _APP_ENV + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS + + appwrite-worker-tasks: + image: appwrite/appwrite: + entrypoint: worker-tasks + container_name: appwrite-worker-tasks + restart: unless-stopped + networks: + - appwrite + depends_on: + - redis + - mariadb + environment: + - _APP_ENV + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS + + appwrite-worker-deletes: + image: appwrite/appwrite: + entrypoint: worker-deletes + container_name: appwrite-worker-deletes + restart: unless-stopped + networks: + - appwrite + depends_on: + - redis + - mariadb + volumes: + - appwrite-uploads:/storage/uploads:rw + - appwrite-cache:/storage/cache:rw + environment: + - _APP_ENV + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS + + appwrite-worker-certificates: + image: appwrite/appwrite: + entrypoint: worker-certificates + container_name: appwrite-worker-certificates + restart: unless-stopped + networks: + - appwrite + depends_on: + - redis + - mariadb + volumes: + - appwrite-config:/storage/config:rw + - appwrite-certificates:/storage/certificates:rw + environment: + - _APP_ENV + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS + + appwrite-worker-functions: + image: appwrite/appwrite: + entrypoint: worker-functions + container_name: appwrite-worker-functions + restart: unless-stopped + networks: + - appwrite + depends_on: + - redis + - mariadb + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - /tmp:/tmp:rw + - appwrite-functions:/storage/functions:rw + environment: + - _APP_ENV + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS + - _APP_FUNCTIONS_TIMEOUT + - _APP_FUNCTIONS_CONTAINERS + + appwrite-worker-mails: + image: appwrite/appwrite: + entrypoint: worker-mails + container_name: appwrite-worker-mails + restart: unless-stopped + networks: + - appwrite + depends_on: + - redis + - smtp + environment: + - _APP_ENV + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_SMTP_HOST + - _APP_SMTP_PORT + + appwrite-schedule: + image: appwrite/appwrite: + entrypoint: schedule + container_name: appwrite-schedule + restart: unless-stopped + networks: + - appwrite + depends_on: + - redis + environment: + - _APP_ENV + - _APP_REDIS_HOST + - _APP_REDIS_PORT + + mariadb: + image: appwrite/mariadb:1.0.3 # fix issues when upgrading using: mysql_upgrade -u root -p + container_name: appwrite-mariadb + restart: unless-stopped + networks: + - appwrite + volumes: + - appwrite-mariadb:/var/lib/mysql:rw + ports: + - "3306:3306" + environment: + - MYSQL_ROOT_PASSWORD=rootsecretpassword + - MYSQL_DATABASE=appwrite + - MYSQL_USER=user + - MYSQL_PASSWORD=password + command: 'mysqld --innodb-flush-method=fsync' + + smtp: + image: appwrite/smtp:1.0.1 + container_name: appwrite-smtp + restart: unless-stopped + networks: + - appwrite + environment: + - MAILNAME=appwrite + - RELAY_NETWORKS=:192.168.0.0/24:10.0.0.0/16 + + redis: + image: redis:5.0 + container_name: appwrite-redis + restart: unless-stopped + networks: + - appwrite + volumes: + - appwrite-redis:/data:rw + + clamav: + image: appwrite/clamav:1.0.12 + container_name: appwrite-clamav + restart: unless-stopped + networks: + - appwrite + volumes: + - appwrite-uploads:/storage/uploads + + influxdb: + image: influxdb:1.6 + container_name: appwrite-influxdb + restart: unless-stopped + networks: + - appwrite + volumes: + - appwrite-influxdb:/var/lib/influxdb:rw + + telegraf: + image: appwrite/telegraf:1.0.0 + container_name: appwrite-telegraf + restart: unless-stopped + networks: + - appwrite + +networks: + gateway: + appwrite: + +volumes: + appwrite-mariadb: + appwrite-redis: + appwrite-cache: + appwrite-uploads: + appwrite-certificates: + appwrite-functions: + appwrite-influxdb: + appwrite-chronograf: + appwrite-config: diff --git a/app/views/install/env.phtml b/app/views/install/env.phtml new file mode 100644 index 000000000..c3ebb6f91 --- /dev/null +++ b/app/views/install/env.phtml @@ -0,0 +1,8 @@ +getParam('vars'); + +foreach ($vars as $key => $value) { + echo $key.'='.$value."\n"; +} +?> \ No newline at end of file diff --git a/bin/doctor b/bin/doctor index c6fecb724..d015bcdca 100755 --- a/bin/doctor +++ b/bin/doctor @@ -1,3 +1,3 @@ #!/bin/sh -php /usr/src/code/app/tasks/doctor.php doctor $@ \ No newline at end of file +php /usr/src/code/app/cli.php doctor $@ diff --git a/bin/install b/bin/install new file mode 100755 index 000000000..e669e91e6 --- /dev/null +++ b/bin/install @@ -0,0 +1,3 @@ +#!/bin/sh + +php /usr/src/code/app/cli.php install $@ \ No newline at end of file diff --git a/bin/migrate b/bin/migrate index 6c889a421..85dbf67d8 100755 --- a/bin/migrate +++ b/bin/migrate @@ -1,3 +1,3 @@ #!/bin/sh -php /usr/src/code/app/tasks/migrate.php run $@ \ No newline at end of file +php /usr/src/code/app/cli.php migrate $@ diff --git a/bin/ssl b/bin/ssl new file mode 100755 index 000000000..83dcf6a02 --- /dev/null +++ b/bin/ssl @@ -0,0 +1,3 @@ +#!/bin/sh + +php /usr/src/code/app/cli.php ssl $@ \ No newline at end of file diff --git a/public/index.php b/public/index.php index 3aa0984c7..01f9dbb11 100644 --- a/public/index.php +++ b/public/index.php @@ -20,7 +20,7 @@ ini_set('display_startup_errors', 1); error_reporting(E_ALL); //trigger_error('hide errors in prod', E_USER_NOTICE); -include __DIR__ . '/../app/app.php'; +include __DIR__ . '/../app/controllers/general.php'; $app = new App('Asia/Tel_Aviv'); diff --git a/src/Appwrite/Docker/Compose.php b/src/Appwrite/Docker/Compose.php new file mode 100644 index 000000000..d186f9479 --- /dev/null +++ b/src/Appwrite/Docker/Compose.php @@ -0,0 +1,73 @@ +compose = yaml_parse($data); + + $this->compose['services'] = (isset($this->compose['services']) && is_array($this->compose['services'])) + ? $this->compose['services'] : []; + + foreach ($this->compose['services'] as $key => &$service) { + $service = new Service($service); + } + } + + /** + * @return array + */ + public function getVersion(): string + { + return (isset($this->compose['version'])) ? $this->compose['version'] : ''; + } + + /** + * @return Service[] + */ + public function getServices(): array + { + return $this->compose['services']; + } + + /** + * @return Service + */ + public function getService(string $name): Service + { + if(!isset($this->compose['services'][$name])) { + throw new Exception('Service not found'); + } + + return $this->compose['services'][$name]; + } + + /** + * @return array + */ + public function getNetworks(): array + { + return (isset($this->compose['networks'])) ? array_keys($this->compose['networks']) : []; + } + + /** + * @return array + */ + public function getVolumes(): array + { + return (isset($this->compose['volumes'])) ? array_keys($this->compose['volumes']) : []; + } +} diff --git a/src/Appwrite/Docker/Compose/Service.php b/src/Appwrite/Docker/Compose/Service.php new file mode 100644 index 000000000..dcb4ce737 --- /dev/null +++ b/src/Appwrite/Docker/Compose/Service.php @@ -0,0 +1,75 @@ +service = $service; + + $ports = (isset($this->service['ports']) && is_array($this->service['ports'])) ? $this->service['ports'] : []; + $this->service['ports'] = []; + + array_walk($ports, function(&$value, &$key) { + $split = explode(':', $value); + $this->service['ports'][ + (isset($split[0])) ? $split[0] : '' + ] = (isset($split[1])) ? $split[1] : ''; + }); + + $this->service['environment'] = (isset($this->service['environment']) && is_array($this->service['environment'])) ? $this->service['environment'] : []; + $this->service['environment'] = new Env(implode("\n", $this->service['environment'])); + } + + /** + * @return string + */ + public function getContainerName(): string + { + return (isset($this->service['container_name'])) ? $this->service['container_name'] : ''; + } + + /** + * @return string + */ + public function getImage(): string + { + return (isset($this->service['image'])) ? $this->service['image'] : ''; + } + + /** + * @return string + */ + public function getImageVersion(): string + { + $image = $this->getImage(); + return substr($image, strpos($image, ':')+1); + } + + /** + * @return Env + */ + public function getEnvironment(): Env + { + return $this->service['environment']; + } + + /** + * @return array + */ + public function getPorts(): array + { + return $this->service['ports']; + } +} diff --git a/src/Appwrite/Docker/Env.php b/src/Appwrite/Docker/Env.php new file mode 100644 index 000000000..c1f25d5e4 --- /dev/null +++ b/src/Appwrite/Docker/Env.php @@ -0,0 +1,79 @@ +vars[$key] = $value; + } + } + } + + /** + * @param string $key + * @param mixed $value + * + * @return $this + */ + public function setVar(string $key, $value): self + { + $this->vars[$key] = $value; + + return $this; + } + + /** + * @param string $key + * + * @return mixed|null + */ + public function getVar(string $key): string + { + return (isset($this->vars[$key])) ? $this->vars[$key] : ''; + } + + /** + * Get All Vars + * + * @return array + */ + public function list(): array + { + return $this->vars; + } + + /** + * @return string + */ + public function export(): string + { + $output = ''; + + foreach ($this->vars as $key => $value) { + $output .= $key.'='.$value."\n"; + } + + return $output; + } +} diff --git a/tests/resources/docker/.env b/tests/resources/docker/.env new file mode 100644 index 000000000..1c1359f0f --- /dev/null +++ b/tests/resources/docker/.env @@ -0,0 +1,3 @@ +_APP_X=value1 +_APP_Y=value2 +_APP_Z = value3 \ No newline at end of file diff --git a/tests/resources/docker/docker-compose.yml b/tests/resources/docker/docker-compose.yml new file mode 100644 index 000000000..4a3192947 --- /dev/null +++ b/tests/resources/docker/docker-compose.yml @@ -0,0 +1,409 @@ +version: '3' + +services: + traefik: + image: traefik:2.2 + container_name: appwrite-traefik + command: + - --log.level=DEBUG + - --api.insecure=true + - --providers.file.directory=/storage/config + - --providers.file.watch=true + - --providers.docker=true + - --entrypoints.web.address=:80 + - --entrypoints.websecure.address=:443 + - --accesslog=true + restart: unless-stopped + ports: + - 2080:80 + - 2443:443 + - 8080:8080 + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - appwrite-config:/storage/config:ro + - appwrite-certificates:/storage/certificates:ro + depends_on: + - appwrite + networks: + - gateway + - appwrite + + appwrite: + container_name: appwrite + build: + context: . + args: + - TESTING=true + - VERSION=dev + restart: unless-stopped + ports: + - 9501:80 + networks: + - appwrite + labels: + - traefik.http.routers.appwrite.rule=PathPrefix(`/`) + - traefik.http.routers.appwrite-secure.rule=PathPrefix(`/`) + - traefik.http.routers.appwrite-secure.tls=true + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - appwrite-uploads:/storage/uploads:rw + - appwrite-cache:/storage/cache:rw + - appwrite-config:/storage/config:rw + - appwrite-certificates:/storage/certificates:rw + - appwrite-functions:/storage/functions:rw + - ./phpunit.xml:/usr/src/code/phpunit.xml + - ./tests:/usr/src/code/tests + - ./app:/usr/src/code/app + # - ./vendor:/usr/src/code/vendor + - ./docs:/usr/src/code/docs + - ./public:/usr/src/code/public + - ./src:/usr/src/code/src + - ./debug:/tmp + depends_on: + - mariadb + - redis + - clamav + - influxdb + environment: + - _APP_ENV + - _APP_OPTIONS_ABUSE + - _APP_OPTIONS_FORCE_HTTPS + - _APP_OPENSSL_KEY_V1 + - _APP_DOMAIN + - _APP_DOMAIN_TARGET + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS + - _APP_INFLUXDB_HOST + - _APP_INFLUXDB_PORT + - _APP_STORAGE_LIMIT + - _APP_FUNCTIONS_TIMEOUT + - _APP_FUNCTIONS_CONTAINERS + + appwrite-worker-usage: + entrypoint: worker-usage + container_name: appwrite-worker-usage + build: + context: . + restart: unless-stopped + networks: + - appwrite + depends_on: + - redis + - telegraf + environment: + - _APP_ENV + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_STATSD_HOST + - _APP_STATSD_PORT + + appwrite-worker-audits: + entrypoint: worker-audits + container_name: appwrite-worker-audits + build: + context: . + restart: unless-stopped + networks: + - appwrite + depends_on: + - redis + - mariadb + environment: + - _APP_ENV + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS + + appwrite-worker-webhooks: + entrypoint: worker-webhooks + container_name: appwrite-worker-webhooks + build: + context: . + restart: unless-stopped + networks: + - appwrite + depends_on: + - redis + - mariadb + environment: + - _APP_ENV + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS + + appwrite-worker-tasks: + entrypoint: worker-tasks + container_name: appwrite-worker-tasks + build: + context: . + restart: unless-stopped + networks: + - appwrite + depends_on: + - redis + - mariadb + environment: + - _APP_ENV + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS + + appwrite-worker-deletes: + entrypoint: worker-deletes + container_name: appwrite-worker-deletes + build: + context: . + restart: unless-stopped + networks: + - appwrite + depends_on: + - redis + - mariadb + volumes: + - appwrite-uploads:/storage/uploads:rw + - appwrite-cache:/storage/cache:rw + environment: + - _APP_ENV + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS + + appwrite-worker-certificates: + entrypoint: worker-certificates + container_name: appwrite-worker-certificates + build: + context: . + restart: unless-stopped + networks: + - appwrite + depends_on: + - redis + - mariadb + volumes: + - appwrite-config:/storage/config:rw + - appwrite-certificates:/storage/certificates:rw + environment: + - _APP_ENV + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS + + appwrite-worker-functions: + entrypoint: worker-functions + container_name: appwrite-worker-functions + build: + context: . + restart: unless-stopped + networks: + - appwrite + depends_on: + - redis + - mariadb + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - /tmp:/tmp:rw + - appwrite-functions:/storage/functions:rw + environment: + - _APP_ENV + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS + - _APP_FUNCTIONS_TIMEOUT + - _APP_FUNCTIONS_CONTAINERS + + appwrite-worker-mails: + entrypoint: worker-mails + container_name: appwrite-worker-mails + build: + context: . + restart: unless-stopped + networks: + - appwrite + depends_on: + - redis + - maildev + # - smtp + environment: + - _APP_ENV + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_SMTP_HOST + - _APP_SMTP_PORT + + appwrite-schedule: + entrypoint: schedule + container_name: appwrite-schedule + build: + context: . + restart: unless-stopped + networks: + - appwrite + depends_on: + - redis + environment: + - _APP_ENV + - _APP_REDIS_HOST + - _APP_REDIS_PORT + + mariadb: + image: appwrite/mariadb:1.0.3 # fix issues when upgrading using: mysql_upgrade -u root -p + container_name: appwrite-mariadb + restart: unless-stopped + networks: + - appwrite + volumes: + - appwrite-mariadb:/var/lib/mysql:rw + ports: + - "3306:3306" + environment: + - MYSQL_ROOT_PASSWORD=rootsecretpassword + - MYSQL_DATABASE=appwrite + - MYSQL_USER=user + - MYSQL_PASSWORD=password + command: 'mysqld --innodb-flush-method=fsync' + + maildev: + image: djfarrelly/maildev + container_name: appwrite-maildev + restart: unless-stopped + ports: + - '1080:80' + networks: + - appwrite + + # smtp: + # image: appwrite/smtp:1.0.1 + # container_name: appwrite-smtp + # restart: unless-stopped + # networks: + # - appwrite + # environment: + # - MAILNAME=appwrite + # - RELAY_NETWORKS=:192.168.0.0/24:10.0.0.0/16 + + redis: + image: redis:5.0 + container_name: appwrite-redis + restart: unless-stopped + networks: + - appwrite + volumes: + - appwrite-redis:/data:rw + + clamav: + image: appwrite/clamav:1.0.12 + container_name: appwrite-clamav + restart: unless-stopped + networks: + - appwrite + volumes: + - appwrite-uploads:/storage/uploads + + influxdb: + image: influxdb:1.6 + container_name: appwrite-influxdb + restart: unless-stopped + networks: + - appwrite + volumes: + - appwrite-influxdb:/var/lib/influxdb:rw + + telegraf: + image: appwrite/telegraf:1.0.0 + container_name: appwrite-telegraf + restart: unless-stopped + networks: + - appwrite + + # redis-commander: + # image: rediscommander/redis-commander:latest + # restart: unless-stopped + # networks: + # - appwrite + # environment: + # - REDIS_HOSTS=redis + # ports: + # - "8081:8081" + + # resque: + # image: registry.gitlab.com/appwrite/appwrite/resque-web:v1.0.2 + # restart: unless-stopped + # networks: + # - appwrite + # ports: + # - "5678:5678" + # environment: + # - RESQUE_WEB_HOST=redis + # - RESQUE_WEB_PORT=6379 + # - RESQUE_WEB_HTTP_BASIC_AUTH_USER=user + # - RESQUE_WEB_HTTP_BASIC_AUTH_PASSWORD=password + + # chronograf: + # image: chronograf:1.5 + # container_name: appwrite-chronograf + # restart: unless-stopped + # networks: + # - appwrite + # volumes: + # - appwrite-chronograf:/var/lib/chronograf + # ports: + # - "8888:8888" + # environment: + # - INFLUXDB_URL=http://influxdb:8086 + # - KAPACITOR_URL=http://kapacitor:9092 + # - AUTH_DURATION=48h + # - TOKEN_SECRET=duperduper5674829!jwt + # - GH_CLIENT_ID=d86f7145a41eacfc52cc + # - GH_CLIENT_SECRET=9e0081062367a2134e7f2ea95ba1a32d08b6c8ab + # - GH_ORGS=appwrite + + # webgrind: + # image: 'jokkedk/webgrind:latest' + # volumes: + # - './debug:/tmp' + # ports: + # - '3001:80' + +networks: + gateway: + appwrite: + +volumes: + appwrite-mariadb: + appwrite-redis: + appwrite-cache: + appwrite-uploads: + appwrite-certificates: + appwrite-functions: + appwrite-influxdb: + appwrite-chronograf: + appwrite-config: diff --git a/tests/unit/Docker/ComposeTest.php b/tests/unit/Docker/ComposeTest.php new file mode 100644 index 000000000..b7d7c40fa --- /dev/null +++ b/tests/unit/Docker/ComposeTest.php @@ -0,0 +1,59 @@ +object = new Compose($data); + } + + public function tearDown() + { + } + + public function testVersion() + { + $this->assertEquals('3', $this->object->getVersion()); + } + + public function testServices() + { + $this->assertCount(17, $this->object->getServices()); + $this->assertEquals('appwrite-telegraf', $this->object->getService('telegraf')->getContainerName()); + $this->assertEquals('appwrite', $this->object->getService('appwrite')->getContainerName()); + $this->assertEquals('', $this->object->getService('appwrite')->getImageVersion()); + $this->assertEquals('2.2', $this->object->getService('traefik')->getImageVersion()); + $this->assertEquals(['2080' => '80', '2443' => '443', '8080' => '8080'], $this->object->getService('traefik')->getPorts()); + } + + public function testNetworks() + { + $this->assertCount(2, $this->object->getNetworks()); + } + + public function testVolumes() + { + $this->assertCount(9, $this->object->getVolumes()); + $this->assertEquals('appwrite-mariadb', $this->object->getVolumes()[0]); + $this->assertEquals('appwrite-redis', $this->object->getVolumes()[1]); + $this->assertEquals('appwrite-cache', $this->object->getVolumes()[2]); + } +} \ No newline at end of file diff --git a/tests/unit/Docker/EnvTest.php b/tests/unit/Docker/EnvTest.php new file mode 100644 index 000000000..ce4d4b391 --- /dev/null +++ b/tests/unit/Docker/EnvTest.php @@ -0,0 +1,49 @@ +object = new Env($data); + } + + public function tearDown() + { + } + + public function testVars() + { + $this->object->setVar('_APP_TEST', 'value4'); + + $this->assertEquals('value1', $this->object->getVar('_APP_X')); + $this->assertEquals('value2', $this->object->getVar('_APP_Y')); + $this->assertEquals('value3', $this->object->getVar('_APP_Z')); + $this->assertEquals('value4', $this->object->getVar('_APP_TEST')); + } + + public function testExport() + { + $this->assertEquals("_APP_X=value1 +_APP_Y=value2 +_APP_Z=value3 +", $this->object->export()); + } +} \ No newline at end of file