From c57cb3d2d95dc9777429812cb5d37cf5d15742dd Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Tue, 22 Oct 2024 17:33:33 +0200 Subject: [PATCH 1/3] fix: workers --- .zed/settings.json | 7 + app/controllers/api/proxy.php | 56 +++++-- app/controllers/general.php | 47 +++--- src/Appwrite/Platform/Workers/Builds.php | 193 +++++++++++++---------- 4 files changed, 188 insertions(+), 115 deletions(-) create mode 100644 .zed/settings.json diff --git a/.zed/settings.json b/.zed/settings.json new file mode 100644 index 0000000000..bb47c87d42 --- /dev/null +++ b/.zed/settings.json @@ -0,0 +1,7 @@ +// Folder-specific settings +// +// For a full list of overridable settings, and general information on folder-specific settings, +// see the documentation: https://zed.dev/docs/configuring-zed#settings-files +{ + "hard_tabs": false +} diff --git a/app/controllers/api/proxy.php b/app/controllers/api/proxy.php index 984a9fb974..ce4eacaedf 100644 --- a/app/controllers/api/proxy.php +++ b/app/controllers/api/proxy.php @@ -37,7 +37,7 @@ App::post('/v1/proxy/rules') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROXY_RULE) ->param('domain', null, new ValidatorDomain(), 'Domain name.') - ->param('resourceType', null, new WhiteList(['api', 'function']), 'Action definition for the rule. Possible values are "api", "function"') + ->param('resourceType', null, new WhiteList(['api', 'function', 'site']), 'Action definition for the rule. Possible values are "api", "function" and "site"') ->param('resourceId', '', new UID(), 'ID of resource for the action type. If resourceType is "api", leave empty. If resourceType is "function", provide ID of the function.', true) ->inject('response') ->inject('project') @@ -51,11 +51,23 @@ App::post('/v1/proxy/rules') throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'You cannot assign your main domain to specific resource. Please use subdomain or a different domain.'); } + $sitesDomain = System::getEnv('_APP_DOMAIN_SITES', ''); $functionsDomain = System::getEnv('_APP_DOMAIN_FUNCTIONS', ''); - if ($functionsDomain != '' && str_ends_with($domain, $functionsDomain)) { - throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'You cannot assign your functions domain or it\'s subdomain to specific resource. Please use different domain.'); + + switch($resourceType) { + case 'function': + if (str_ends_with($domain, $functionsDomain)) { + throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'You cannot assign your functions domain or it\'s subdomain to specific resource. Please use different domain.'); + } + break; + case 'site': + if (str_ends_with($domain, $sitesDomain)) { + throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'You cannot assign your functions domain or it\'s subdomain to specific resource. Please use different domain.'); + } + break; } + if ($domain === 'localhost' || $domain === APP_HOSTNAME_INTERNAL) { throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'This domain name is not allowed. Please pick another one.'); } @@ -83,18 +95,34 @@ App::post('/v1/proxy/rules') $resourceInternalId = ''; - if ($resourceType == 'function') { - if (empty($resourceId)) { - throw new Exception(Exception::FUNCTION_NOT_FOUND); - } + switch($resourceType) { + case 'function': + if (empty($resourceId)) { + throw new Exception(Exception::FUNCTION_NOT_FOUND); + } - $function = $dbForProject->getDocument('functions', $resourceId); + $function = $dbForProject->getDocument('functions', $resourceId); - if ($function->isEmpty()) { - throw new Exception(Exception::RULE_RESOURCE_NOT_FOUND); - } + if ($function->isEmpty()) { + throw new Exception(Exception::RULE_RESOURCE_NOT_FOUND); + } - $resourceInternalId = $function->getInternalId(); + $resourceInternalId = $function->getInternalId(); + break; + case 'site': + if (empty($resourceId)) { + // todo: use site relecant exception + throw new Exception(Exception::FUNCTION_NOT_FOUND); + } + + $site = $dbForProject->getDocument('sites', $resourceId); + + if ($site->isEmpty()) { + throw new Exception(Exception::RULE_RESOURCE_NOT_FOUND); + } + + $resourceInternalId = $site->getInternalId(); + break; } try { @@ -116,8 +144,8 @@ App::post('/v1/proxy/rules') ]); $status = 'created'; - $functionsDomain = System::getEnv('_APP_DOMAIN_FUNCTIONS'); - if (!empty($functionsDomain) && \str_ends_with($domain->get(), $functionsDomain)) { + + if (\str_ends_with($domain->get(), $functionsDomain) || \str_ends_with($domain->get(), $sitesDomain)) { $status = 'verified'; } diff --git a/app/controllers/general.php b/app/controllers/general.php index b2a07f06f6..cb8c0523df 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -98,7 +98,10 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo $type = $route->getAttribute('resourceType'); - if ($type === 'function') { + if ($type === 'function' || $type === 'sites') { + $isFunction = $type === 'function' ; + $isSite = $type === 'sites'; + $utopia->getRoute()?->label('sdk.namespace', 'functions'); $utopia->getRoute()?->label('sdk.method', 'createExecution'); @@ -107,12 +110,11 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo if ($request->getMethod() !== Request::METHOD_GET) { throw new AppwriteException(AppwriteException::GENERAL_PROTOCOL_UNSUPPORTED, 'Method unsupported over HTTP. Please use HTTPS instead.'); } - return $response->redirect('https://' . $request->getHostname() . $request->getURI()); } } - $functionId = $route->getAttribute('resourceId'); + $resourceId = $route->getAttribute('resourceId'); $projectId = $route->getAttribute('projectId'); $path = ($swooleRequest->server['request_uri'] ?? '/'); @@ -121,7 +123,6 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo $path .= '?' . $query; } - $body = $swooleRequest->getContent() ?? ''; $method = $swooleRequest->server['request_method']; @@ -131,7 +132,7 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo $dbForProject = $getProjectDB($project); - $function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId)); + $function = Authorization::skip(fn () => $dbForProject->getDocument($isSite ? 'sites' : 'functions', $resourceId)); if ($function->isEmpty() || !$function->getAttribute('enabled')) { throw new AppwriteException(AppwriteException::FUNCTION_NOT_FOUND); @@ -228,7 +229,7 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo 'errors' => '', 'logs' => '', 'duration' => 0.0, - 'search' => implode(' ', [$functionId, $executionId]), + 'search' => implode(' ', [$resourceId, $executionId]), ]); $queueForEvents @@ -267,7 +268,7 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo // Appwrite vars $vars = \array_merge($vars, [ 'APPWRITE_FUNCTION_API_ENDPOINT' => $endpoint, - 'APPWRITE_FUNCTION_ID' => $functionId, + 'APPWRITE_FUNCTION_ID' => $resourceId, 'APPWRITE_FUNCTION_NAME' => $function->getAttribute('name'), 'APPWRITE_FUNCTION_DEPLOYMENT' => $deployment->getId(), 'APPWRITE_FUNCTION_PROJECT_ID' => $project->getId(), @@ -357,22 +358,28 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo $queueForUsage ->addMetric(METRIC_NETWORK_REQUESTS, 1) ->addMetric(METRIC_NETWORK_INBOUND, $request->getSize() + $fileSize) - ->addMetric(METRIC_NETWORK_OUTBOUND, $response->getSize()) - ->addMetric(METRIC_EXECUTIONS, 1) - ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS), 1) - ->addMetric(METRIC_EXECUTIONS_COMPUTE, (int)($execution->getAttribute('duration') * 1000)) // per project - ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE), (int)($execution->getAttribute('duration') * 1000)) // per function - ->addMetric(METRIC_EXECUTIONS_MB_SECONDS, (int)(($spec['memory'] ?? APP_FUNCTION_MEMORY_DEFAULT) * $execution->getAttribute('duration', 0) * ($spec['cpus'] ?? APP_FUNCTION_CPUS_DEFAULT))) - ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_MB_SECONDS), (int)(($spec['memory'] ?? APP_FUNCTION_MEMORY_DEFAULT) * $execution->getAttribute('duration', 0) * ($spec['cpus'] ?? APP_FUNCTION_CPUS_DEFAULT))) - ->setProject($project) - ->trigger() - ; + ->addMetric(METRIC_NETWORK_OUTBOUND, $response->getSize()); + if ($isFunction) { + $queueForUsage + ->addMetric(METRIC_EXECUTIONS, 1) + ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS), 1) + ->addMetric(METRIC_EXECUTIONS_COMPUTE, (int)($execution->getAttribute('duration') * 1000)) // per project + ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE), (int)($execution->getAttribute('duration') * 1000)) // per function + ->addMetric(METRIC_EXECUTIONS_MB_SECONDS, (int)(($spec['memory'] ?? APP_FUNCTION_MEMORY_DEFAULT) * $execution->getAttribute('duration', 0) * ($spec['cpus'] ?? APP_FUNCTION_CPUS_DEFAULT))) + ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_MB_SECONDS), (int)(($spec['memory'] ?? APP_FUNCTION_MEMORY_DEFAULT) * $execution->getAttribute('duration', 0) * ($spec['cpus'] ?? APP_FUNCTION_CPUS_DEFAULT))); + } - $queueForFunctions - ->setType(Func::TYPE_ASYNC_WRITE) - ->setExecution($execution) + $queueForUsage ->setProject($project) ->trigger(); + + if ($isFunction) { + $queueForFunctions + ->setType(Func::TYPE_ASYNC_WRITE) + ->setExecution($execution) + ->setProject($project) + ->trigger(); + } } $execution->setAttribute('logs', ''); diff --git a/src/Appwrite/Platform/Workers/Builds.php b/src/Appwrite/Platform/Workers/Builds.php index 5dd2f7f886..538423a95d 100644 --- a/src/Appwrite/Platform/Workers/Builds.php +++ b/src/Appwrite/Platform/Workers/Builds.php @@ -109,7 +109,7 @@ class Builds extends Action * @param Database $dbForProject * @param GitHub $github * @param Document $project - * @param Document $function + * @param Document $resource * @param Document $deployment * @param Document $template * @param Log $log @@ -117,22 +117,25 @@ class Builds extends Action * @throws \Utopia\Database\Exception * @throws Exception */ - protected function buildDeployment(Device $deviceForFunctions, Func $queueForFunctions, Event $queueForEvents, Usage $queueForUsage, Database $dbForConsole, Database $dbForProject, GitHub $github, Document $project, Document $function, Document $deployment, Document $template, Log $log): void + protected function buildDeployment(Device $deviceForFunctions, Func $queueForFunctions, Event $queueForEvents, Usage $queueForUsage, Database $dbForConsole, Database $dbForProject, GitHub $github, Document $project, Document $resource, Document $deployment, Document $template, Log $log): void { + // todo: refactor + $isFunction = $resource->getCollection() === 'functions'; + $isSite = $resource->getCollection() === 'sites'; + $foreignKey = $isFunction ? 'functionId' : 'siteId'; + $executor = new Executor(System::getEnv('_APP_EXECUTOR_HOST')); - $functionId = $function->getId(); - $log->addTag('functionId', $function->getId()); + $log->addTag($foreignKey, $resource->getId()); - $function = $dbForProject->getDocument('functions', $functionId); - if ($function->isEmpty()) { + $resource = $dbForProject->getDocument($resource->getCollection(), $resource->getId()); + if ($resource->isEmpty()) { throw new \Exception('Function not found', 404); } - $deploymentId = $deployment->getId(); - $log->addTag('deploymentId', $deploymentId); + $log->addTag('deploymentId', $deployment->getId()); - $deployment = $dbForProject->getDocument('deployments', $deploymentId); + $deployment = $dbForProject->getDocument('deployments', $deployment->getId()); if ($deployment->isEmpty()) { throw new \Exception('Deployment not found', 404); } @@ -141,18 +144,19 @@ class Builds extends Action throw new \Exception('Entrypoint for your Appwrite Function is missing. Please specify it when making deployment or update the entrypoint under your function\'s "Settings" > "Configuration" > "Entrypoint".', 500); } - $version = $function->getAttribute('version', 'v2'); - $spec = Config::getParam('runtime-specifications')[$function->getAttribute('specifications', APP_FUNCTION_SPECIFICATION_DEFAULT)]; + $version = $resource->getAttribute('version', 'v2'); + $spec = Config::getParam('runtime-specifications')[$resource->getAttribute('specifications', APP_FUNCTION_SPECIFICATION_DEFAULT)]; $runtimes = Config::getParam($version === 'v2' ? 'runtimes-v2' : 'runtimes', []); - $key = $function->getAttribute('runtime'); + // todo: fix for sites using frameworks + $key = $resource->getAttribute('runtime'); $runtime = $runtimes[$key] ?? null; if (\is_null($runtime)) { - throw new \Exception('Runtime "' . $function->getAttribute('runtime', '') . '" is not supported'); + throw new \Exception('Runtime "' . $resource->getAttribute('runtime', '') . '" is not supported'); } // Realtime preparation - $allEvents = Event::generateEvents('functions.[functionId].deployments.[deploymentId].update', [ - 'functionId' => $function->getId(), + $allEvents = Event::generateEvents("{$resource->getCollection()}.[{$foreignKey}].deployments.[deploymentId].update", [ + $foreignKey => $resource->getId(), 'deploymentId' => $deployment->getId() ]); @@ -171,7 +175,7 @@ class Builds extends Action 'deploymentId' => $deployment->getId(), 'status' => 'processing', 'path' => '', - 'runtime' => $function->getAttribute('runtime'), + 'runtime' => $resource->getAttribute('runtime'), 'source' => $deployment->getAttribute('path', ''), 'sourceType' => strtolower($deviceForFunctions->getType()), 'logs' => '', @@ -263,7 +267,7 @@ class Builds extends Action } elseif ($isNewBuild && $isVcsEnabled) { // VCS and VCS+Temaplte $tmpDirectory = '/tmp/builds/' . $buildId . '/code'; - $rootDirectory = $function->getAttribute('providerRootDirectory', ''); + $rootDirectory = $resource->getAttribute('providerRootDirectory', ''); $rootDirectory = \rtrim($rootDirectory, '/'); $rootDirectory = \ltrim($rootDirectory, '.'); $rootDirectory = \ltrim($rootDirectory, '/'); @@ -344,7 +348,7 @@ class Builds extends Action Console::execute('rsync -av --exclude \'.git\' ' . \escapeshellarg($tmpTemplateDirectory . '/' . $templateRootDirectory . '/') . ' ' . \escapeshellarg($tmpDirectory . '/' . $rootDirectory), '', $stdout, $stderr); // Commit and push - $exit = Console::execute('git config --global user.email "team@appwrite.io" && git config --global user.name "Appwrite" && cd ' . \escapeshellarg($tmpDirectory) . ' && git add . && git commit -m "Create ' . \escapeshellarg($function->getAttribute('name', '')) . ' function" && git push origin ' . \escapeshellarg($branchName), '', $stdout, $stderr); + $exit = Console::execute('git config --global user.email "team@appwrite.io" && git config --global user.name "Appwrite" && cd ' . \escapeshellarg($tmpDirectory) . ' && git add . && git commit -m "Create ' . \escapeshellarg($resource->getAttribute('name', '')) . ' function" && git push origin ' . \escapeshellarg($branchName), '', $stdout, $stderr); if ($exit !== 0) { throw new \Exception('Unable to push code repository: ' . $stderr); @@ -362,7 +366,7 @@ class Builds extends Action $deployment->setAttribute('providerCommitHash', $providerCommitHash ?? ''); $deployment->setAttribute('providerCommitAuthorUrl', $authorUrl); $deployment->setAttribute('providerCommitAuthor', 'Appwrite'); - $deployment->setAttribute('providerCommitMessage', "Create '" . $function->getAttribute('name', '') . "' function"); + $deployment->setAttribute('providerCommitMessage', "Create '" . $resource->getAttribute('name', '') . "' function"); $deployment->setAttribute('providerCommitUrl', "https://github.com/$cloneOwner/$cloneRepository/commit/$providerCommitHash"); $deployment = $dbForProject->updateDocument('deployments', $deployment->getId(), $deployment); @@ -415,7 +419,7 @@ class Builds extends Action $directorySize = $deviceForFunctions->getFileSize($source); $deployment = $dbForProject->updateDocument('deployments', $deployment->getId(), $deployment->setAttribute('path', $source)->setAttribute('size', $directorySize)); - $this->runGitAction('processing', $github, $providerCommitHash, $owner, $repositoryName, $project, $function, $deployment->getId(), $dbForProject, $dbForConsole); + $this->runGitAction('processing', $github, $providerCommitHash, $owner, $repositoryName, $project, $resource, $deployment->getId(), $dbForProject, $dbForConsole); } /** Request the executor to build the code... */ @@ -423,7 +427,7 @@ class Builds extends Action $build = $dbForProject->updateDocument('builds', $buildId, $build); if ($isVcsEnabled) { - $this->runGitAction('building', $github, $providerCommitHash, $owner, $repositoryName, $project, $function, $deployment->getId(), $dbForProject, $dbForConsole); + $this->runGitAction('building', $github, $providerCommitHash, $owner, $repositoryName, $project, $resource, $deployment->getId(), $dbForProject, $dbForConsole); } /** Trigger Webhook */ @@ -433,8 +437,8 @@ class Builds extends Action ->setQueue(Event::WEBHOOK_QUEUE_NAME) ->setClass(Event::WEBHOOK_CLASS_NAME) ->setProject($project) - ->setEvent('functions.[functionId].deployments.[deploymentId].update') - ->setParam('functionId', $function->getId()) + ->setEvent("{$resource->getCollection()}.[{$foreignKey}].deployments.[deploymentId].update") + ->setParam($foreignKey, $resource->getId()) ->setParam('deploymentId', $deployment->getId()) ->setPayload($deployment->getArrayCopy(array_keys($deploymentModel->getRules()))); @@ -464,12 +468,12 @@ class Builds extends Action $vars = []; // Shared vars - foreach ($function->getAttribute('varsProject', []) as $var) { + foreach ($resource->getAttribute('varsProject', []) as $var) { $vars[$var->getAttribute('key')] = $var->getAttribute('value', ''); } // Function vars - foreach ($function->getAttribute('vars', []) as $var) { + foreach ($resource->getAttribute('vars', []) as $var) { $vars[$var->getAttribute('key')] = $var->getAttribute('value', ''); } @@ -478,27 +482,48 @@ class Builds extends Action $jwtExpiry = (int)System::getEnv('_APP_FUNCTIONS_BUILD_TIMEOUT', 900); $jwtObj = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', $jwtExpiry, 0); + //todo: not needed for sites yet, might be useful as a build variable but too shortlived $apiKey = $jwtObj->encode([ 'projectId' => $project->getId(), - 'scopes' => $function->getAttribute('scopes', []) + 'scopes' => $resource->getAttribute('scopes', []) ]); $protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') == 'disabled' ? 'http' : 'https'; $hostname = System::getEnv('_APP_DOMAIN'); $endpoint = $protocol . '://' . $hostname . "/v1"; + //todo: ugly, but works + if ($isFunction) { + $vars = [ + ...$vars, + 'APPWRITE_FUNCTION_API_ENDPOINT' => $endpoint, + 'APPWRITE_FUNCTION_API_KEY' => API_KEY_DYNAMIC . '_' . $apiKey, + 'APPWRITE_FUNCTION_ID' => $resource->getId(), + 'APPWRITE_FUNCTION_NAME' => $resource->getAttribute('name'), + 'APPWRITE_FUNCTION_DEPLOYMENT' => $deployment->getId(), + 'APPWRITE_FUNCTION_PROJECT_ID' => $project->getId(), + 'APPWRITE_FUNCTION_RUNTIME_NAME' => $runtime['name'] ?? '', + 'APPWRITE_FUNCTION_RUNTIME_VERSION' => $runtime['version'] ?? '', + 'APPWRITE_FUNCTION_CPUS' => $cpus, + 'APPWRITE_FUNCTION_MEMORY' => $memory + ]; + } + if ($isSite) { + $vars = [ + ...$vars, + 'APPWRITE_SITE_ID' => $resource->getId(), + 'APPWRITE_SITE_NAME' => $resource->getAttribute('name'), + 'APPWRITE_SITE_DEPLOYMENT' => $deployment->getId(), + 'APPWRITE_SITE_PROJECT_ID' => $project->getId(), + 'APPWRITE_SITE_RUNTIME_NAME' => $runtime['name'] ?? '', + 'APPWRITE_SITE_RUNTIME_VERSION' => $runtime['version'] ?? '', + 'APPWRITE_SITE_CPUS' => $cpus, + 'APPWRITE_SITE_MEMORY' => $memory + ]; + } + // Appwrite vars $vars = \array_merge($vars, [ - 'APPWRITE_FUNCTION_API_ENDPOINT' => $endpoint, - 'APPWRITE_FUNCTION_API_KEY' => API_KEY_DYNAMIC . '_' . $apiKey, - 'APPWRITE_FUNCTION_ID' => $function->getId(), - 'APPWRITE_FUNCTION_NAME' => $function->getAttribute('name'), - 'APPWRITE_FUNCTION_DEPLOYMENT' => $deployment->getId(), - 'APPWRITE_FUNCTION_PROJECT_ID' => $project->getId(), - 'APPWRITE_FUNCTION_RUNTIME_NAME' => $runtime['name'] ?? '', - 'APPWRITE_FUNCTION_RUNTIME_VERSION' => $runtime['version'] ?? '', - 'APPWRITE_FUNCTION_CPUS' => $cpus, - 'APPWRITE_FUNCTION_MEMORY' => $memory, 'APPWRITE_VERSION' => APP_VERSION_STABLE, 'APPWRITE_REGION' => $project->getAttribute('region'), 'APPWRITE_DEPLOYMENT_TYPE' => $deployment->getAttribute('type', ''), @@ -516,6 +541,7 @@ class Builds extends Action 'APPWRITE_VCS_ROOT_DIRECTORY' => $deployment->getAttribute('providerRootDirectory', ''), ]); + //todo: for sites use isntall and build command $command = $deployment->getAttribute('commands', ''); $response = null; @@ -529,9 +555,9 @@ class Builds extends Action $isCanceled = false; Co::join([ - Co\go(function () use ($executor, &$response, $project, $deployment, $source, $function, $runtime, $vars, $command, $cpus, $memory, &$err) { + Co\go(function () use ($executor, &$response, $project, $deployment, $source, $resource, $runtime, $vars, $command, $cpus, $memory, &$err) { try { - $version = $function->getAttribute('version', 'v2'); + $version = $resource->getAttribute('version', 'v2'); $command = $version === 'v2' ? 'tar -zxf /tmp/code.tar.gz -C /usr/code && cd /usr/local/src/ && ./build.sh' : 'tar -zxf /tmp/code.tar.gz -C /mnt/code && helpers/build.sh "' . \trim(\escapeshellarg($command), "\'") . '"'; $response = $executor->createRuntime( @@ -637,17 +663,17 @@ class Builds extends Action $build = $dbForProject->updateDocument('builds', $buildId, $build); if ($isVcsEnabled) { - $this->runGitAction('ready', $github, $providerCommitHash, $owner, $repositoryName, $project, $function, $deployment->getId(), $dbForProject, $dbForConsole); + $this->runGitAction('ready', $github, $providerCommitHash, $owner, $repositoryName, $project, $resource, $deployment->getId(), $dbForProject, $dbForConsole); } Console::success("Build id: $buildId created"); /** Set auto deploy */ if ($deployment->getAttribute('activate') === true) { - $function->setAttribute('deploymentInternalId', $deployment->getInternalId()); - $function->setAttribute('deployment', $deployment->getId()); - $function->setAttribute('live', true); - $function = $dbForProject->updateDocument('functions', $function->getId(), $function); + $resource->setAttribute('deploymentInternalId', $deployment->getInternalId()); + $resource->setAttribute('deployment', $deployment->getId()); + $resource->setAttribute('live', true); + $resource = $dbForProject->updateDocument('functions', $resource->getId(), $resource); } if ($dbForProject->getDocument('builds', $buildId)->getAttribute('status') === 'canceled') { @@ -658,12 +684,14 @@ class Builds extends Action /** Update function schedule */ // Inform scheduler if function is still active - $schedule = $dbForConsole->getDocument('schedules', $function->getAttribute('scheduleId')); - $schedule - ->setAttribute('resourceUpdatedAt', DateTime::now()) - ->setAttribute('schedule', $function->getAttribute('schedule')) - ->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment'))); - Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule)); + if ($isFunction) { + $schedule = $dbForConsole->getDocument('schedules', $resource->getAttribute('scheduleId')); + $schedule + ->setAttribute('resourceUpdatedAt', DateTime::now()) + ->setAttribute('schedule', $resource->getAttribute('schedule')) + ->setAttribute('active', !empty($resource->getAttribute('schedule')) && !empty($resource->getAttribute('deployment'))); + Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule)); + } } catch (\Throwable $th) { if ($dbForProject->getDocument('builds', $buildId)->getAttribute('status') === 'canceled') { Console::info('Build has been canceled'); @@ -680,7 +708,7 @@ class Builds extends Action $build = $dbForProject->updateDocument('builds', $buildId, $build); if ($isVcsEnabled) { - $this->runGitAction('failed', $github, $providerCommitHash, $owner, $repositoryName, $project, $function, $deployment->getId(), $dbForProject, $dbForConsole); + $this->runGitAction('failed', $github, $providerCommitHash, $owner, $repositoryName, $project, $resource, $deployment->getId(), $dbForProject, $dbForConsole); } } finally { /** @@ -702,30 +730,35 @@ class Builds extends Action /** Trigger usage queue */ if ($build->getAttribute('status') === 'ready') { - $queueForUsage - ->addMetric(METRIC_BUILDS_SUCCESS, 1) // per project - ->addMetric(METRIC_BUILDS_COMPUTE_SUCCESS, (int)$build->getAttribute('duration', 0) * 1000) - ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_BUILDS_SUCCESS), 1) // per function - ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_BUILDS_COMPUTE_SUCCESS), (int)$build->getAttribute('duration', 0) * 1000); + if ($isFunction) { + $queueForUsage + ->addMetric(METRIC_BUILDS_SUCCESS, 1) // per project + ->addMetric(METRIC_BUILDS_COMPUTE_SUCCESS, (int)$build->getAttribute('duration', 0) * 1000) + ->addMetric(str_replace('{functionInternalId}', $resource->getInternalId(), METRIC_FUNCTION_ID_BUILDS_SUCCESS), 1) // per function + ->addMetric(str_replace('{functionInternalId}', $resource->getInternalId(), METRIC_FUNCTION_ID_BUILDS_COMPUTE_SUCCESS), (int)$build->getAttribute('duration', 0) * 1000); + } } elseif ($build->getAttribute('status') === 'failed') { - $queueForUsage - ->addMetric(METRIC_BUILDS_FAILED, 1) // per project - ->addMetric(METRIC_BUILDS_COMPUTE_FAILED, (int)$build->getAttribute('duration', 0) * 1000) - ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_BUILDS_FAILED), 1) // per function - ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_BUILDS_COMPUTE_FAILED), (int)$build->getAttribute('duration', 0) * 1000); + if ($isFunction) { + $queueForUsage + ->addMetric(METRIC_BUILDS_FAILED, 1) // per project + ->addMetric(METRIC_BUILDS_COMPUTE_FAILED, (int)$build->getAttribute('duration', 0) * 1000) + ->addMetric(str_replace('{functionInternalId}', $resource->getInternalId(), METRIC_FUNCTION_ID_BUILDS_FAILED), 1) // per function + ->addMetric(str_replace('{functionInternalId}', $resource->getInternalId(), METRIC_FUNCTION_ID_BUILDS_COMPUTE_FAILED), (int)$build->getAttribute('duration', 0) * 1000); + } + } + if ($isFunction) { + $queueForUsage + ->addMetric(METRIC_BUILDS, 1) // per project + ->addMetric(METRIC_BUILDS_STORAGE, $build->getAttribute('size', 0)) + ->addMetric(METRIC_BUILDS_COMPUTE, (int)$build->getAttribute('duration', 0) * 1000) + ->addMetric(METRIC_BUILDS_MB_SECONDS, (int)(($spec['memory'] ?? APP_FUNCTION_MEMORY_DEFAULT) * $build->getAttribute('duration', 0) * ($spec['cpus'] ?? APP_FUNCTION_CPUS_DEFAULT))) + ->addMetric(str_replace('{functionInternalId}', $resource->getInternalId(), METRIC_FUNCTION_ID_BUILDS), 1) // per function + ->addMetric(str_replace('{functionInternalId}', $resource->getInternalId(), METRIC_FUNCTION_ID_BUILDS_STORAGE), $build->getAttribute('size', 0)) + ->addMetric(str_replace('{functionInternalId}', $resource->getInternalId(), METRIC_FUNCTION_ID_BUILDS_COMPUTE), (int)$build->getAttribute('duration', 0) * 1000) + ->addMetric(str_replace('{functionInternalId}', $resource->getInternalId(), METRIC_FUNCTION_ID_BUILDS_MB_SECONDS), (int)(($spec['memory'] ?? APP_FUNCTION_MEMORY_DEFAULT) * $build->getAttribute('duration', 0) * ($spec['cpus'] ?? APP_FUNCTION_CPUS_DEFAULT))) + ->setProject($project) + ->trigger(); } - - $queueForUsage - ->addMetric(METRIC_BUILDS, 1) // per project - ->addMetric(METRIC_BUILDS_STORAGE, $build->getAttribute('size', 0)) - ->addMetric(METRIC_BUILDS_COMPUTE, (int)$build->getAttribute('duration', 0) * 1000) - ->addMetric(METRIC_BUILDS_MB_SECONDS, (int)(($spec['memory'] ?? APP_FUNCTION_MEMORY_DEFAULT) * $build->getAttribute('duration', 0) * ($spec['cpus'] ?? APP_FUNCTION_CPUS_DEFAULT))) - ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_BUILDS), 1) // per function - ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_BUILDS_STORAGE), $build->getAttribute('size', 0)) - ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_BUILDS_COMPUTE), (int)$build->getAttribute('duration', 0) * 1000) - ->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_BUILDS_MB_SECONDS), (int)(($spec['memory'] ?? APP_FUNCTION_MEMORY_DEFAULT) * $build->getAttribute('duration', 0) * ($spec['cpus'] ?? APP_FUNCTION_CPUS_DEFAULT))) - ->setProject($project) - ->trigger(); } } @@ -736,7 +769,7 @@ class Builds extends Action * @param string $owner * @param string $repositoryName * @param Document $project - * @param Document $function + * @param Document $resource * @param string $deploymentId * @param Database $dbForProject * @param Database $dbForConsole @@ -747,9 +780,9 @@ class Builds extends Action * @throws Conflict * @throws Restricted */ - protected function runGitAction(string $status, GitHub $github, string $providerCommitHash, string $owner, string $repositoryName, Document $project, Document $function, string $deploymentId, Database $dbForProject, Database $dbForConsole): void + protected function runGitAction(string $status, GitHub $github, string $providerCommitHash, string $owner, string $repositoryName, Document $project, Document $resource, string $deploymentId, Database $dbForProject, Database $dbForConsole): void { - if ($function->getAttribute('providerSilentMode', false) === true) { + if ($resource->getAttribute('providerSilentMode', false) === true) { return; } @@ -771,16 +804,14 @@ class Builds extends Action default => $status }; - $functionName = $function->getAttribute('name'); + $resourceName = $resource->getAttribute('name'); $projectName = $project->getAttribute('name'); - $name = "{$functionName} ({$projectName})"; + $name = "{$resourceName} ({$projectName})"; $protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') == 'disabled' ? 'http' : 'https'; $hostname = System::getEnv('_APP_DOMAIN'); - $functionId = $function->getId(); - $projectId = $project->getId(); - $providerTargetUrl = $protocol . '://' . $hostname . "/console/project-$projectId/functions/function-$functionId"; + $providerTargetUrl = "{$protocol}://{$hostname}/console/project-{$project->getId()}/functions/function-{$resource->getId()}"; $github->updateCommitStatus($repositoryName, $providerCommitHash, $owner, $state, $message, $providerTargetUrl, $name); } @@ -809,7 +840,7 @@ class Builds extends Action try { $comment = new Comment(); $comment->parseComment($github->getComment($owner, $repositoryName, $commentId)); - $comment->addBuild($project, $function, $status, $deployment->getId(), ['type' => 'logs']); + $comment->addBuild($project, $resource, $status, $deployment->getId(), ['type' => 'logs']); $github->updateComment($owner, $repositoryName, $commentId, $comment->generateComment()); } finally { $dbForConsole->deleteDocument('vcsCommentLocks', $commentId); From 8f0c1a4224423d4c352de8387141336ed4a23478 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Tue, 22 Oct 2024 17:34:22 +0200 Subject: [PATCH 2/3] fix: gitignore --- .gitignore | 1 + .zed/settings.json | 7 ------- 2 files changed, 1 insertion(+), 7 deletions(-) delete mode 100644 .zed/settings.json diff --git a/.gitignore b/.gitignore index 5ae03e2a56..95b7e3bcee 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ dev/yasd_init.php .phpunit.result.cache Makefile appwrite.json +/.zed \ No newline at end of file diff --git a/.zed/settings.json b/.zed/settings.json deleted file mode 100644 index bb47c87d42..0000000000 --- a/.zed/settings.json +++ /dev/null @@ -1,7 +0,0 @@ -// Folder-specific settings -// -// For a full list of overridable settings, and general information on folder-specific settings, -// see the documentation: https://zed.dev/docs/configuring-zed#settings-files -{ - "hard_tabs": false -} From 7da8b44c636d16cc67ee8e76a3c7c6ca78705053 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Tue, 22 Oct 2024 17:35:24 +0200 Subject: [PATCH 3/3] chore: run formatter --- app/controllers/api/proxy.php | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/app/controllers/api/proxy.php b/app/controllers/api/proxy.php index ce4eacaedf..d749946826 100644 --- a/app/controllers/api/proxy.php +++ b/app/controllers/api/proxy.php @@ -54,7 +54,7 @@ App::post('/v1/proxy/rules') $sitesDomain = System::getEnv('_APP_DOMAIN_SITES', ''); $functionsDomain = System::getEnv('_APP_DOMAIN_FUNCTIONS', ''); - switch($resourceType) { + switch ($resourceType) { case 'function': if (str_ends_with($domain, $functionsDomain)) { throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'You cannot assign your functions domain or it\'s subdomain to specific resource. Please use different domain.'); @@ -95,33 +95,33 @@ App::post('/v1/proxy/rules') $resourceInternalId = ''; - switch($resourceType) { + switch ($resourceType) { case 'function': - if (empty($resourceId)) { - throw new Exception(Exception::FUNCTION_NOT_FOUND); - } + if (empty($resourceId)) { + throw new Exception(Exception::FUNCTION_NOT_FOUND); + } - $function = $dbForProject->getDocument('functions', $resourceId); + $function = $dbForProject->getDocument('functions', $resourceId); - if ($function->isEmpty()) { - throw new Exception(Exception::RULE_RESOURCE_NOT_FOUND); - } + if ($function->isEmpty()) { + throw new Exception(Exception::RULE_RESOURCE_NOT_FOUND); + } - $resourceInternalId = $function->getInternalId(); + $resourceInternalId = $function->getInternalId(); break; case 'site': if (empty($resourceId)) { // todo: use site relecant exception - throw new Exception(Exception::FUNCTION_NOT_FOUND); - } + throw new Exception(Exception::FUNCTION_NOT_FOUND); + } - $site = $dbForProject->getDocument('sites', $resourceId); + $site = $dbForProject->getDocument('sites', $resourceId); - if ($site->isEmpty()) { - throw new Exception(Exception::RULE_RESOURCE_NOT_FOUND); - } + if ($site->isEmpty()) { + throw new Exception(Exception::RULE_RESOURCE_NOT_FOUND); + } - $resourceInternalId = $site->getInternalId(); + $resourceInternalId = $site->getInternalId(); break; }