From eee8e6d9d703ca9159baed03caa529645b040910 Mon Sep 17 00:00:00 2001 From: Andrey Borysenko Date: Fri, 17 Jan 2025 14:15:41 +0200 Subject: [PATCH] WIP: Deploy options DB for update process (1) Signed-off-by: Andrey Borysenko --- lib/Command/ExApp/Register.php | 17 --- lib/Command/ExApp/Update.php | 24 ++-- lib/Controller/ExAppsPageController.php | 52 ++++--- lib/Db/ExAppDeployOption.php | 64 +++++++++ lib/Db/ExAppDeployOptionsMapper.php | 47 +++++++ lib/DeployActions/DockerActions.php | 120 +++-------------- .../Version032001Date20250115164140.php | 59 ++++++++ lib/Service/AppAPIService.php | 3 - lib/Service/ExAppDeployOptionsService.php | 127 ++++++++++++++++++ lib/Service/ExAppService.php | 19 ++- 10 files changed, 368 insertions(+), 164 deletions(-) create mode 100644 lib/Db/ExAppDeployOption.php create mode 100644 lib/Db/ExAppDeployOptionsMapper.php create mode 100644 lib/Migration/Version032001Date20250115164140.php create mode 100644 lib/Service/ExAppDeployOptionsService.php diff --git a/lib/Command/ExApp/Register.php b/lib/Command/ExApp/Register.php index ed807a8a..f80db841 100644 --- a/lib/Command/ExApp/Register.php +++ b/lib/Command/ExApp/Register.php @@ -59,7 +59,6 @@ protected function configure(): void { // Advanced deploy options $this->addOption('env', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Optional deploy options (ENV_NAME=ENV_VALUE), passed to ExApp container as environment variables'); $this->addOption('mount', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Optional mount options (SRC_PATH=DST_PATH), passed to ExApp container as volume mounts'); - $this->addOption('port', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Optional port mapping OPTIONAL_HOST_IP;HOST_PORT;CONTAINER_PORT (e.g. 443;9443/tcp, 0.0.0.0;80;8080/udp)'); } protected function execute(InputInterface $input, OutputInterface $output): int { @@ -102,22 +101,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int }, $mounts); $deployOptions['mounts'] = $mounts; - $ports = $input->getOption('port') ?? []; - // Parse array of port options strings (OPTIONAL_HOST_IP;HOST_PORT;CONTAINER_PORT) - // to array of arrays ['HostPort' => HOST_PORT, 'HostIp' => OPTIONAL_HOST_IP, 'ContainerPort' => CONTAINER_PORT] - // It could be two (without optional) or three parts separated by semicolon - $ports = array_map(function ($item) { - $parts = explode(';', $item, 3); - if (count($parts) === 2) { - return ['HostPort' => $parts[0], 'ContainerPort' => $parts[1]]; - } - if (count($parts) === 3) { - return ['HostIp' => $parts[0], 'HostPort' => $parts[1], 'ContainerPort' => $parts[2]]; - } - return []; // invalid port binding option - }, $ports); - $deployOptions['ports'] = $ports; - $appInfo = $this->exAppService->getAppInfo( $appId, $input->getOption('info-xml'), $input->getOption('json-info'), $deployOptions diff --git a/lib/Command/ExApp/Update.php b/lib/Command/ExApp/Update.php index 50b52ec3..0e862537 100644 --- a/lib/Command/ExApp/Update.php +++ b/lib/Command/ExApp/Update.php @@ -16,6 +16,7 @@ use OCA\AppAPI\Service\AppAPIService; use OCA\AppAPI\Service\DaemonConfigService; +use OCA\AppAPI\Service\ExAppDeployOptionsService; use OCA\AppAPI\Service\ExAppService; use Psr\Log\LoggerInterface; use Symfony\Component\Console\Command\Command; @@ -27,14 +28,15 @@ class Update extends Command { public function __construct( - private readonly AppAPIService $service, - private readonly ExAppService $exAppService, - private readonly DaemonConfigService $daemonConfigService, - private readonly DockerActions $dockerActions, - private readonly ManualActions $manualActions, - private readonly LoggerInterface $logger, - private readonly ExAppArchiveFetcher $exAppArchiveFetcher, - private readonly ExAppFetcher $exAppFetcher, + private readonly AppAPIService $service, + private readonly ExAppService $exAppService, + private readonly DaemonConfigService $daemonConfigService, + private readonly DockerActions $dockerActions, + private readonly ManualActions $manualActions, + private readonly LoggerInterface $logger, + private readonly ExAppArchiveFetcher $exAppArchiveFetcher, + private readonly ExAppFetcher $exAppFetcher, + private readonly ExAppDeployOptionsService $exAppDeployOptionsService, ) { parent::__construct(); } @@ -90,8 +92,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int private function updateExApp(InputInterface $input, OutputInterface $output, string $appId): int { $outputConsole = !$input->getOption('silent'); + $deployOptions = $this->exAppDeployOptionsService->formatDeployOptions( + $this->exAppDeployOptionsService->getDeployOptions() + ); $appInfo = $this->exAppService->getAppInfo( - $appId, $input->getOption('info-xml'), $input->getOption('json-info') + $appId, $input->getOption('info-xml'), $input->getOption('json-info'), + $deployOptions ); if (isset($appInfo['error'])) { $this->logger->error($appInfo['error']); diff --git a/lib/Controller/ExAppsPageController.php b/lib/Controller/ExAppsPageController.php index ecba1e4b..7a74ddeb 100644 --- a/lib/Controller/ExAppsPageController.php +++ b/lib/Controller/ExAppsPageController.php @@ -21,6 +21,7 @@ use OCA\AppAPI\Fetcher\ExAppFetcher; use OCA\AppAPI\Service\AppAPIService; use OCA\AppAPI\Service\DaemonConfigService; +use OCA\AppAPI\Service\ExAppDeployOptionsService; use OCA\AppAPI\Service\ExAppService; use OCP\App\IAppManager; use OCP\AppFramework\Controller; @@ -53,6 +54,7 @@ public function __construct( private readonly LoggerInterface $logger, private readonly IAppManager $appManager, private readonly ExAppService $exAppService, + private readonly ExAppDeployOptionsService $exAppDeployOptionsService, ) { parent::__construct(Application::APP_ID, $request); } @@ -319,7 +321,6 @@ public function enableApp(string $appId, array $deployOptions = []): JSONRespons $envOptions = isset($deployOptions['environment_variables']) ? array_keys($deployOptions['environment_variables']) : []; $envOptionsString = ''; - // build --deploy-option ENV_NAME=ENV_VALUE string foreach ($envOptions as $envOption) { $envOptionsString .= sprintf(' --env %s=%s', $envOption, $deployOptions['environment_variables'][$envOption]); } @@ -327,30 +328,14 @@ public function enableApp(string $appId, array $deployOptions = []): JSONRespons $mountOptions = $deployOptions['mounts'] ?? []; $mountOptionsString = ''; - // build --mount SRC_PATH=DST_PATH string foreach ($mountOptions as $mountOption) { $readonlyModifier = $mountOption['readonly'] ? 'ro' : 'rw'; $mountOptionsString .= sprintf(' --mount %s:%s:%s', $mountOption['hostPath'], $mountOption['containerPath'], $readonlyModifier); } $mountOptionsString = trim($mountOptionsString); - // port options in $deployOptions['ports'], array of ['hostPort' => '', 'hostIp' => '', 'containerPort' => ''] - // convert to array of strings with --port HOST_PORT;CONTAINER_PORT or --port HOST_IP;HOST_PORT;CONTAINER_PORT - $portOptions = $deployOptions['ports'] ?? []; - $portOptionsString = ''; - // build --port HOST_PORT;CONTAINER_PORT string - foreach ($portOptions as $portOption) { - if (isset($portOption['hostIp']) && $portOption['hostIp'] !== '') { - $portOptionsString .= sprintf(' --port %s;%s;%s', $portOption['hostIp'], $portOption['hostPort'], $portOption['containerPort']); - } else { - $portOptionsString .= sprintf(' --port %s;%s', $portOption['hostPort'], $portOption['containerPort']); - } - } - $portOptionsString = trim($portOptionsString); - // If ExApp is not registered - then it's a "Deploy and Enable" action. if (!$exApp) { -// $command = sprintf("app_api:app:register --silent %s %s %s %s", $appId, $envOptionsString, $mountOptionsString, $portOptionsString); if (!$this->service->runOccCommand(sprintf("app_api:app:register --silent %s %s %s %s", $appId, $envOptionsString, $mountOptionsString, $portOptionsString))) { return new JSONResponse(['data' => ['message' => $this->l10n->t('Error starting install of ExApp')]], Http::STATUS_INTERNAL_SERVER_ERROR); } @@ -515,27 +500,36 @@ public function getAppLogs(string $appId, string $tail = 'all'): DataDownloadRes } } - /** - * Returns ExApp Advanced deploy options (only for docker-install), container environment variables, mounts and ports - */ public function getAppDeployOptions(string $appId) { $exApp = $this->exAppService->getExApp($appId); if (is_null($exApp)) { return new JSONResponse(['error' => $this->l10n->t('ExApp not found, failed to get deploy options')], Http::STATUS_NOT_FOUND); } - $daemonConfig = $this->daemonConfigService->getDaemonConfigByName($exApp->getDaemonConfigName()); - if ($daemonConfig->getAcceptsDeployId() !== $this->dockerActions->getAcceptsDeployId()) { - return new JSONResponse(['error' => $this->l10n->t('ExApp deploy options are not supported by the daemon')], Http::STATUS_NOT_IMPLEMENTED); - } - $this->dockerActions->initGuzzleClient($daemonConfig); - $deployOptions = $this->dockerActions->getDeployOptions($appId, $daemonConfig); + $deployOptions = $this->exAppDeployOptionsService->formatDeployOptions( + $this->exAppDeployOptionsService->getDeployOptions($appId) + ); + + $envs = []; + if (isset($deployOptions['environment_variables'])) { + $envs = $deployOptions['environment_variables']; + } - if (isset($deployOptions['error'])) { - return new JSONResponse(['error' => $deployOptions['error']], Http::STATUS_INTERNAL_SERVER_ERROR); + $mounts = []; + if (isset($deployOptions['mounts'])) { + foreach ($deployOptions['mounts'] as $mount) { + $mounts[] = [ + 'hostPath' => $mount['source'], + 'containerPath' => $mount['target'], + 'readonly' => $mount['mode'] === 'ro' + ]; + } } - return new JSONResponse($deployOptions); + return new JSONResponse([ + 'environment_variables' => $envs, + 'mounts' => $mounts, + ]); } /** diff --git a/lib/Db/ExAppDeployOption.php b/lib/Db/ExAppDeployOption.php new file mode 100644 index 00000000..54bbc627 --- /dev/null +++ b/lib/Db/ExAppDeployOption.php @@ -0,0 +1,64 @@ +addType('appid', 'string'); + $this->addType('name', 'string'); + $this->addType('type', 'string'); + $this->addType('value', 'json'); + + if (isset($params['id'])) { + $this->setId($params['id']); + } + if (isset($params['appid'])) { + $this->setAppid($params['appid']); + } + if (isset($params['type'])) { + $this->setType($params['type']); + } + if (isset($params['value'])) { + $this->setValue($params['value']); + } + } + + public function jsonSerialize(): array { + return [ + 'id' => $this->getId(), + 'appid' => $this->getAppid(), + 'type' => $this->getType(), + 'value' => $this->getValue(), + ]; + } +} diff --git a/lib/Db/ExAppDeployOptionsMapper.php b/lib/Db/ExAppDeployOptionsMapper.php new file mode 100644 index 00000000..44d6759f --- /dev/null +++ b/lib/Db/ExAppDeployOptionsMapper.php @@ -0,0 +1,47 @@ + + */ +class ExAppDeployOptionsMapper extends QBMapper { + public function __construct(IDBConnection $db) { + parent::__construct($db, 'ex_deploy_options'); + } + + /** + * @throws Exception + */ + public function findAll(): array { + $qb = $this->db->getQueryBuilder(); + $result = $qb->select('exs.*') + ->from($this->tableName, 'exs') + ->executeQuery(); + return $result->fetchAll(); + } + + /** + * @throws Exception + */ + public function removeAllByAppId(string $appId): int { + $qb = $this->db->getQueryBuilder(); + $qb->delete($this->tableName) + ->where( + $qb->expr()->eq('appid', $qb->createNamedParameter($appId, IQueryBuilder::PARAM_STR)) + ); + return $qb->executeStatement(); + } +} diff --git a/lib/DeployActions/DockerActions.php b/lib/DeployActions/DockerActions.php index 5bdb366b..27754b93 100644 --- a/lib/DeployActions/DockerActions.php +++ b/lib/DeployActions/DockerActions.php @@ -17,6 +17,7 @@ use OCA\AppAPI\Db\ExApp; use OCA\AppAPI\Service\AppAPICommonService; +use OCA\AppAPI\Service\ExAppDeployOptionsService; use OCA\AppAPI\Service\ExAppService; use OCP\App\IAppManager; @@ -34,34 +35,20 @@ class DockerActions implements IDeployActions { public const EX_APP_CONTAINER_PREFIX = 'nc_app_'; public const APP_API_HAPROXY_USER = 'app_api_haproxy_user'; - public const RESERVED_ENV_KEYS = [ - 'AA_VERSION', - 'APP_SECRET', - 'APP_ID', - 'APP_DISPLAY_NAME', - 'APP_VERSION', - 'APP_HOST', - 'APP_PORT', - 'APP_PERSISTENT_STORAGE', - 'NEXTCLOUD_URL', - 'COMPUTE_DEVICE', - 'NVIDIA_VISIBLE_DEVICES', - 'NVIDIA_DRIVER_CAPABILITIES', - ]; - private Client $guzzleClient; private bool $useSocket = false; # for `pullImage` function, to detect can be stream used or not. public function __construct( - private readonly LoggerInterface $logger, - private readonly IConfig $config, - private readonly ICertificateManager $certificateManager, - private readonly IAppManager $appManager, - private readonly IURLGenerator $urlGenerator, - private readonly AppAPICommonService $service, - private readonly ExAppService $exAppService, - private readonly ITempManager $tempManager, - private readonly ICrypto $crypto, + private readonly LoggerInterface $logger, + private readonly IConfig $config, + private readonly ICertificateManager $certificateManager, + private readonly IAppManager $appManager, + private readonly IURLGenerator $urlGenerator, + private readonly AppAPICommonService $service, + private readonly ExAppService $exAppService, + private readonly ITempManager $tempManager, + private readonly ICrypto $crypto, + private readonly ExAppDeployOptionsService $exAppDeployOptionsService, ) { } @@ -110,6 +97,10 @@ public function deployExApp(ExApp $exApp, DaemonConfig $daemonConfig, array $par if (isset($result['error'])) { return $result['error']; } + + $this->exAppDeployOptionsService->removeExAppDeployOptions($exApp->getAppid()); + $this->exAppDeployOptionsService->addExAppDeployOptions($exApp->getAppid(), $params['deploy_options']); + $this->exAppService->setAppDeployProgress($exApp, 99); if (!$this->waitTillContainerStart($containerName, $daemonConfig)) { return 'container startup failed'; @@ -379,34 +370,6 @@ public function createContainer(string $dockerUrl, string $imageId, DaemonConfig ); } - if (isset($params['ports'])) { - $customPortBindings = []; - foreach ($params['ports'] as $port) { - if (!isset($customPortBindings[$port['ContainerPort']])) { - $customPortBindings[$port['ContainerPort']] = [ - ['HostPort' => $port['HostPort']] - ]; - if (isset($port['HostIp'])) { - $customPortBindings[$port['ContainerPort']][0]['HostIp'] = $port['HostIp']; - } - } else { // append additional port bindings - $customPortBindings[$port['ContainerPort']][] = [ - 'HostPort' => $port['HostPort'] - ]; - if (isset($port['HostIp'])) { - $customPortBindings[$port['ContainerPort']][count($customPortBindings[$port['ContainerPort']]) - 1]['HostIp'] = $port['HostIp']; - } - } - } - if (count($customPortBindings) > 0) { - $containerParams['HostConfig']['PortBindings'] = $customPortBindings; - $containerParams['ExposedPorts'] = array_reduce($params['ports'], function ($carry, $port) { - $carry[$port['ContainerPort']] = new \stdClass(); - return $carry; - }, []); - } - } - $url = $this->buildApiUrl($dockerUrl, sprintf('containers/create?name=%s', urlencode($this->buildExAppContainerName($params['name'])))); try { $options['json'] = $containerParams; @@ -747,12 +710,15 @@ public function buildDeployParams(DaemonConfig $daemonConfig, array $appInfo): a 'devices' => $devices, 'deviceRequests' => $deviceRequests, 'mounts' => $appInfo['external-app']['mounts'] ?? [], - 'ports' => $appInfo['external-app']['ports'] ?? [], ]; return [ 'image_params' => $imageParams, 'container_params' => $containerParams, + 'deploy_options' => [ + 'environment_variables' => $appInfo['external-app']['environment-variables'] ?? [], + 'mounts' => $appInfo['external-app']['mounts'] ?? [], + ] ]; } @@ -780,8 +746,8 @@ public function buildDeployEnvs(array $params, array $deployConfig): array { } // Appending additional deploy options to container envs - foreach ($params['environment_variables'] as $key => $value) { - $autoEnvs[] = sprintf('%s=%s', $key, $value); + foreach (array_keys($params['environment_variables']) as $envKey) { + $autoEnvs[] = sprintf('%s=%s', $envKey, $params['environment_variables'][$envKey]['value'] ?? ''); } return $autoEnvs; @@ -934,48 +900,4 @@ private function buildDefaultGPUDeviceRequests(): array { ], ]; } - - public function getDeployOptions(string $appId, DaemonConfig $daemonConfig) { - $containerInfo = $this->inspectContainer( - $this->buildDockerUrl($daemonConfig), - $this->buildExAppContainerName($appId) - ); - - $envs = array_reduce($containerInfo['Config']['Env'], function ($carry, $env) { - $envParts = explode('=', $env); - if (in_array($envParts[0], self::RESERVED_ENV_KEYS)) { - return $carry; - } - $carry[] = $env; - return $carry; - }, []); - - $mounts = []; - foreach ($containerInfo['Mounts'] as $mount) { - $mounts[] = [ - 'hostPath' => $mount['Source'], - 'containerPath' => $mount['Destination'], - 'readonly' => $mount['RW'] === false - ]; - } - - $ports = []; - foreach ($containerInfo['HostConfig']['PortBindings'] as $containerPort => $hostPorts) { - foreach ($hostPorts as $hostPort) { - $ports[] = [ - 'hostPort' => $hostPort['HostPort'], - 'containerPort' => $containerPort - ]; - if (isset($hostPort['HostIp'])) { - $ports[count($ports) - 1]['hostIp'] = $hostPort['HostIp']; - } - } - } - - return [ - 'environment_variables' => $envs, - 'mounts' => $mounts, - 'ports' => $ports, - ]; - } } diff --git a/lib/Migration/Version032001Date20250115164140.php b/lib/Migration/Version032001Date20250115164140.php new file mode 100644 index 00000000..04cb1cbe --- /dev/null +++ b/lib/Migration/Version032001Date20250115164140.php @@ -0,0 +1,59 @@ +hasTable('ex_deploy_options')) { + $table = $schema->createTable('ex_deploy_options'); + + $table->addColumn('id', Types::BIGINT, [ + 'notnull' => true, + 'autoincrement' => true, + ]); + $table->addColumn('appid', Types::STRING, [ + 'notnull' => true, + 'length' => 32, + ]); + $table->addColumn('type', Types::STRING, [ // environment_variables/mounts/ports + 'notnull' => true, + 'length' => 32, + ]); + $table->addColumn('value', Types::JSON, [ + 'notnull' => true, + ]); + + $table->setPrimaryKey(['id']); + $table->addUniqueIndex(['appid', 'type'], 'deploy_options__idx'); + } + + + return $schema; + } +} diff --git a/lib/Service/AppAPIService.php b/lib/Service/AppAPIService.php index c6307100..c92d5a32 100644 --- a/lib/Service/AppAPIService.php +++ b/lib/Service/AppAPIService.php @@ -446,9 +446,6 @@ public function runOccCommandInternal(array $args): bool { $occDirectory = dirname(__FILE__, 5); } $this->logger->info(sprintf('Calling occ(directory=%s): %s', $occDirectory ?? 'null', $args)); - $env = 'PHP_IDE_CONFIG=serverName=master '; - $xDebug = '-dxdebug.mode=debug -dxdebug.client_host=host.docker.internal -dxdebug.start_with_request=yes -dxdebug.idekey=PHPSTORM'; - $cmd = $env . 'php ' . $xDebug . ' console.php ' . $args; $process = proc_open('php console.php ' . $args, $descriptors, $pipes, $occDirectory); if (!is_resource($process)) { $this->logger->error(sprintf('Error calling occ(directory=%s): %s', $occDirectory ?? 'null', $args)); diff --git a/lib/Service/ExAppDeployOptionsService.php b/lib/Service/ExAppDeployOptionsService.php new file mode 100644 index 00000000..bb043e93 --- /dev/null +++ b/lib/Service/ExAppDeployOptionsService.php @@ -0,0 +1,127 @@ +isAvailable()) { + $this->cache = $cacheFactory->createDistributed(Application::APP_ID . '/ex_deploy_options'); + } + } + + public function addExAppDeployOptions(string $appId, array $deployOptions): array { + $added = []; + foreach (array_keys($deployOptions) as $type) { + if ($this->addExAppDeployOption($appId, $type, $deployOptions[$type])) { + $added[$type] = $deployOptions[$type]; + } + } + return $added; + } + + public function addExAppDeployOption( + string $appId, + string $type, + mixed $value, + ): ?ExAppDeployOption + { + $deployOptionEntry = $this->getDeployOption($appId, $type); + try { + $newExAppDeployOption = new ExAppDeployOption([ + 'appid' => $appId, + 'type' => $type, + 'value' => $value, + ]); + if ($deployOptionEntry !== null) { + $newExAppDeployOption->setId($deployOptionEntry->getId()); + } + $exAppDeployOption = $this->mapper->insertOrUpdate($newExAppDeployOption); + $this->resetCache(); + } catch (Exception $e) { + $this->logger->error( + sprintf('Failed to register ExApp Deploy option for %s. Error: %s', $appId, $e->getMessage()), ['exception' => $e] + ); + return null; + } + return $exAppDeployOption; + } + + public function getDeployOption(string $appId, string $type): ?ExAppDeployOption { + foreach ($this->getDeployOptions() as $deployOption) { + if (($deployOption->getAppid() === $appId) && ($deployOption->getType() === $type)) { + return $deployOption; + } + } + return null; + } + + /** + * Get list of all registered ExApp Deploy Options + * + * @return ExAppDeployOption[] + */ + public function getDeployOptions(?string $appId = null): array { + try { + $cacheKey = '/ex_deploy_options'; + $records = $this->cache?->get($cacheKey); + if ($records === null) { + $records = $this->mapper->findAll(); + $this->cache?->set($cacheKey, $records); + } + if ($appId !== null) { + $records = array_values(array_filter($records, function ($record) use ($appId) { + return $record['appid'] === $appId; + })); + } + return array_map(function ($record) { + return new ExAppDeployOption($record); + }, $records); + } catch (Exception) { + return []; + } + } + + public function formatDeployOptions(array $deployOptions): array { + $formattedDeployOptions = []; + foreach ($deployOptions as $deployOption) { + $formattedDeployOptions[$deployOption->getType()] = $deployOption->getValue(); + } + return $formattedDeployOptions; + } + + public function removeExAppDeployOptions(string $appId): int { + try { + $result = $this->mapper->removeAllByAppId($appId); + } catch (Exception) { + $result = -1; + } + $this->resetCache(); + return $result; + } + + public function resetCache(): void { + $this->cache?->remove('/ex_deploy_options'); + } +} diff --git a/lib/Service/ExAppService.php b/lib/Service/ExAppService.php index 0ccd2118..2ddba90d 100644 --- a/lib/Service/ExAppService.php +++ b/lib/Service/ExAppService.php @@ -60,6 +60,7 @@ public function __construct( private readonly SettingsService $settingsService, private readonly ExAppEventsListenerService $eventsListenerService, private readonly ExAppOccService $occService, + private readonly ExAppDeployOptionsService $deployOptionsService, private readonly IConfig $config, ) { if ($cacheFactory->isAvailable()) { @@ -128,6 +129,7 @@ public function unregisterExApp(string $appId): bool { $this->exAppArchiveFetcher->removeExAppFolder($appId); $this->eventsListenerService->unregisterExAppEventListeners($appId); $this->occService->unregisterExAppOccCommands($appId); + $this->deployOptionsService->removeExAppDeployOptions($appId); $this->unregisterExAppWebhooks($appId); $r = $this->exAppMapper->deleteExApp($appId); if ($r !== 1) { @@ -256,16 +258,16 @@ private function resetCaches(): void { $this->settingsService->resetCacheEnabled(); $this->eventsListenerService->resetCacheEnabled(); $this->occService->resetCacheEnabled(); + $this->deployOptionsService->resetCache(); } - public function getAppInfo(string $appId, ?string $infoXml, ?string $jsonInfo, ?array $deployOptions): array { + public function getAppInfo(string $appId, ?string $infoXml, ?string $jsonInfo, ?array $deployOptions = null): array { $extractedDir = ''; if ($jsonInfo !== null) { $appInfo = json_decode($jsonInfo, true); # fill 'id' if it is missing(this field was called `appid` in previous versions in json) $appInfo['id'] = $appInfo['id'] ?? $appId; # during manual install JSON can have all values at root level - // TODO: Do we need to add here new Advanced deploy options (environment_variables, mounts, ports)? foreach (['docker-install', 'translations_folder', 'routes'] as $key) { if (isset($appInfo[$key])) { $appInfo['external-app'][$key] = $appInfo[$key]; @@ -306,13 +308,19 @@ public function getAppInfo(string $appId, ?string $infoXml, ?string $jsonInfo, ? // compose the key-values pairs $envVars = []; foreach ($appInfo['external-app']['environment-variables']['variable'] as $envVar) { - $envVars[$envVar['name']] = $envVar['default'] ?? ''; + $envVars[$envVar['name']] = [ + 'name' => $envVar['name'], + 'displayName' => $envVar['display-name'] ?? '', + 'description' => $envVar['description'] ?? '', + 'default' => $envVar['default'] ?? '', + 'value' => $envVar['default'] ?? '', + ]; } if (isset($deployOptions['environment_variables']) && count(array_keys($deployOptions['environment_variables'])) > 0) { // override with given deploy options values foreach ($deployOptions['environment_variables'] as $key => $value) { if (array_key_exists($key, $envVars)) { - $envVars[$key] = $value; + $envVars[$key]['value'] = $value['value'] ?? ''; } } } @@ -321,9 +329,6 @@ public function getAppInfo(string $appId, ?string $infoXml, ?string $jsonInfo, ? if (isset($deployOptions['mounts'])) { $appInfo['external-app']['mounts'] = $deployOptions['mounts']; } - if (isset($deployOptions['ports'])) { - $appInfo['external-app']['ports'] = $deployOptions['ports']; - } if ($extractedDir) { if (file_exists($extractedDir . '/l10n')) { $appInfo['translations_folder'] = $extractedDir . '/l10n';