diff --git a/Dockerfile b/Dockerfile index e9e2c547df..23bd3f188f 100755 --- a/Dockerfile +++ b/Dockerfile @@ -167,6 +167,7 @@ RUN chmod +x /usr/local/bin/doctor && \ chmod +x /usr/local/bin/maintenance && \ chmod +x /usr/local/bin/usage && \ chmod +x /usr/local/bin/install && \ + chmod +x /usr/local/bin/upgrade && \ chmod +x /usr/local/bin/migrate && \ chmod +x /usr/local/bin/realtime && \ chmod +x /usr/local/bin/schedule && \ diff --git a/bin/upgrade b/bin/upgrade new file mode 100755 index 0000000000..ce32b9ca30 --- /dev/null +++ b/bin/upgrade @@ -0,0 +1,3 @@ +#!/bin/sh + +php /usr/src/code/app/cli.php upgrade $@ \ No newline at end of file diff --git a/src/Appwrite/Platform/Services/Tasks.php b/src/Appwrite/Platform/Services/Tasks.php index 10c573da42..bc8d1bbc72 100644 --- a/src/Appwrite/Platform/Services/Tasks.php +++ b/src/Appwrite/Platform/Services/Tasks.php @@ -22,6 +22,7 @@ use Appwrite\Platform\Tasks\VolumeSync; use Appwrite\Platform\Tasks\CalcUsersStats; use Appwrite\Platform\Tasks\CalcTierStats; use Appwrite\Platform\Tasks\PatchDeleteProjectCollections; +use Appwrite\Platform\Tasks\Upgrade; class Tasks extends Service { @@ -36,6 +37,7 @@ class Tasks extends Service ->addAction(Hamster::getName(), new Hamster()) ->addAction(Doctor::getName(), new Doctor()) ->addAction(Install::getName(), new Install()) + ->addAction(Upgrade::getName(), new Upgrade()) ->addAction(Maintenance::getName(), new Maintenance()) ->addAction(PatchCreateMissingSchedules::getName(), new PatchCreateMissingSchedules()) ->addAction(ClearCardCache::getName(), new ClearCardCache()) diff --git a/src/Appwrite/Platform/Tasks/Install.php b/src/Appwrite/Platform/Tasks/Install.php index 1d384715cb..22355d0269 100644 --- a/src/Appwrite/Platform/Tasks/Install.php +++ b/src/Appwrite/Platform/Tasks/Install.php @@ -16,6 +16,8 @@ use Utopia\Platform\Action; class Install extends Action { + protected string $path = '/usr/src/code/appwrite'; + public static function getName(): string { return 'install'; @@ -36,7 +38,6 @@ class Install extends Action public function action(string $httpPort, string $httpsPort, string $organization, string $image, string $interactive): void { $config = Config::getParam('variables'); - $path = '/usr/src/code/appwrite'; $defaultHTTPPort = '80'; $defaultHTTPSPort = '443'; $vars = []; @@ -56,19 +57,28 @@ class Install extends Action Console::success('Starting Appwrite installation...'); // Create directory with write permissions - if (!\file_exists(\dirname($path))) { - if (!@\mkdir(\dirname($path), 0755, true)) { - Console::error('Can\'t create directory ' . \dirname($path)); + if (!\file_exists(\dirname($this->path))) { + if (!@\mkdir(\dirname($this->path), 0755, true)) { + Console::error('Can\'t create directory ' . \dirname($this->path)); Console::exit(1); } } - $data = @file_get_contents($path . '/docker-compose.yml'); + $data = @file_get_contents($this->path . '/docker-compose.yml'); if ($data !== false) { + if ($interactive == 'Y' && Console::isInteractive()) { + $answer = Console::confirm('Previous installation found, do you want to overwrite it (a backup will be created before overwriting)? (Y/n)'); + + if ($answer !== 'Y') { + Console::info('No action taken.'); + return; + } + } + $time = \time(); Console::info('Compose file found, creating backup: docker-compose.yml.' . $time . '.backup'); - file_put_contents($path . '/docker-compose.yml.' . $time . '.backup', $data); + file_put_contents($this->path . '/docker-compose.yml.' . $time . '.backup', $data); $compose = new Compose($data); $appwrite = $compose->getService('appwrite'); $oldVersion = ($appwrite) ? $appwrite->getImageVersion() : null; @@ -102,11 +112,11 @@ class Install extends Action } } - $data = @file_get_contents($path . '/.env'); + $data = @file_get_contents($this->path . '/.env'); if ($data !== false) { // Fetch all env vars from previous .env file Console::info('Env file found, creating backup: .env.' . $time . '.backup'); - file_put_contents($path . '/.env.' . $time . '.backup', $data); + file_put_contents($this->path . '/.env.' . $time . '.backup', $data); $env = new Env($data); foreach ($env->list() as $key => $value) { @@ -196,14 +206,14 @@ class Install extends Action $templateForEnv->setParam('vars', $input); - if (!file_put_contents($path . '/docker-compose.yml', $templateForCompose->render(false))) { + if (!file_put_contents($this->path . '/docker-compose.yml', $templateForCompose->render(false))) { $message = 'Failed to save Docker Compose file'; $this->sendEvent($analytics, $message); Console::error($message); Console::exit(1); } - if (!file_put_contents($path . '/.env', $templateForEnv->render(false))) { + if (!file_put_contents($this->path . '/.env', $templateForEnv->render(false))) { $message = 'Failed to save environment variables file'; $this->sendEvent($analytics, $message); Console::error($message); @@ -222,7 +232,7 @@ class Install extends Action Console::log("Running \"docker compose up -d --remove-orphans --renew-anon-volumes\""); - $exit = Console::execute("${env} docker compose --project-directory ${path} up -d --remove-orphans --renew-anon-volumes", '', $stdout, $stderr); + $exit = Console::execute("$env docker compose --project-directory $this->path up -d --remove-orphans --renew-anon-volumes", '', $stdout, $stderr); if ($exit !== 0) { $message = 'Failed to install Appwrite dockers'; diff --git a/src/Appwrite/Platform/Tasks/Upgrade.php b/src/Appwrite/Platform/Tasks/Upgrade.php new file mode 100644 index 0000000000..e3f0458394 --- /dev/null +++ b/src/Appwrite/Platform/Tasks/Upgrade.php @@ -0,0 +1,42 @@ +desc('Upgrade Appwrite') + ->param('httpPort', '', new Text(4), 'Server HTTP port', true) + ->param('httpsPort', '', new Text(4), 'Server HTTPS port', true) + ->param('organization', 'appwrite', new Text(0), 'Docker Registry organization', true) + ->param('image', 'appwrite', new Text(0), 'Main appwrite docker image', true) + ->param('interactive', 'Y', new Text(1), 'Run an interactive session', true) + ->callback(fn ($httpPort, $httpsPort, $organization, $image, $interactive) => $this->action($httpPort, $httpsPort, $organization, $image, $interactive)); + } + + public function action(string $httpPort, string $httpsPort, string $organization, string $image, string $interactive): void + { + // Check for previous installation + $data = @file_get_contents($this->path . '/docker-compose.yml'); + if (empty($data)) { + Console::error('Appwrite installation not found.'); + Console::log('The command was not run in the parent folder of your appwrite installation.'); + Console::log('Please navigate to the parent directory of the Appwrite installation and try again.'); + Console::log(' parent_directory <= you run the command in this directory'); + Console::log(' └── appwrite'); + Console::log(' └── docker-compose.yml'); + Console::exit(1); + } + parent::action($httpPort, $httpsPort, $organization, $image, $interactive); + } +}