Merge branch 'feat-functions-refactor' of github.com:appwrite/appwrite into feat-add-builds-worker

This commit is contained in:
Christy Jacob
2022-01-26 16:59:24 +04:00
46 changed files with 694 additions and 686 deletions
+7 -7
View File
@@ -1322,8 +1322,8 @@ $collections = [
],
[
'$collection' => Database::SYSTEM_COLLECTION_RULES,
'label' => 'Tag',
'key' => 'tag',
'label' => 'Deployment',
'key' => 'deployment',
'type' => Database::SYSTEM_VAR_TYPE_KEY,
'default' => '',
'required' => false,
@@ -1386,11 +1386,11 @@ $collections = [
],
],
],
Database::SYSTEM_COLLECTION_TAGS => [
Database::SYSTEM_COLLECTION_DEPLOYMENTS => [
'$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS,
'$id' => Database::SYSTEM_COLLECTION_TAGS,
'$id' => Database::SYSTEM_COLLECTION_DEPLOYMENTS,
'$permissions' => ['read' => ['role:all']],
'name' => 'Tags',
'name' => 'Deployments',
'structure' => true,
'rules' => [
[
@@ -1467,8 +1467,8 @@ $collections = [
],
[
'$collection' => Database::SYSTEM_COLLECTION_RULES,
'label' => 'Tag ID',
'key' => 'tagId',
'label' => 'Deployment ID',
'key' => 'deploymentId',
'type' => Database::SYSTEM_VAR_TYPE_KEY,
'default' => '',
'required' => false,
+5 -5
View File
@@ -1799,7 +1799,7 @@ $collections = [
'filters' => [],
],
[
'$id' => 'tag',
'$id' => 'deployment',
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
@@ -1898,10 +1898,10 @@ $collections = [
],
],
'tags' => [
'deployments' => [
'$collection' => Database::METADATA,
'$id' => 'tags',
'name' => 'Tags',
'$id' => 'deployments',
'name' => 'Deployments',
'attributes' => [
[
'$id' => 'dateCreated',
@@ -2217,7 +2217,7 @@ $collections = [
'filters' => [],
],
[
'$id' => 'tagId',
'$id' => 'deploymentId',
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
+7 -7
View File
@@ -147,18 +147,18 @@ return [
'model' => Response::MODEL_ANY,
'note' => 'version >= 0.7',
],
'functions.tags.create' => [
'description' => 'This event triggers when a function tag is created.',
'model' => Response::MODEL_TAG,
'functions.deployments.create' => [
'description' => 'This event triggers when a function delpoyment is created.',
'model' => Response::MODEL_DEPLOYMENT,
'note' => 'version >= 0.7',
],
'functions.tags.update' => [
'description' => 'This event triggers when a function tag is updated.',
'functions.deployments.update' => [
'description' => 'This event triggers when a function delpoyment is updated.',
'model' => Response::MODEL_FUNCTION,
'note' => 'version >= 0.7',
],
'functions.tags.delete' => [
'description' => 'This event triggers when a function tag is deleted.',
'functions.deployments.delete' => [
'description' => 'This event triggers when a function delpoyment is deleted.',
'model' => Response::MODEL_ANY,
'note' => 'version >= 0.7',
],
+2 -2
View File
@@ -44,10 +44,10 @@ return [ // List of publicly visible scopes
'description' => 'Access to create, update, and delete your project\'s storage files',
],
'functions.read' => [
'description' => 'Access to read your project\'s functions and code tags',
'description' => 'Access to read your project\'s functions and code deployments',
],
'functions.write' => [
'description' => 'Access to create, update, and delete your project\'s functions and code tags',
'description' => 'Access to create, update, and delete your project\'s functions and code deployments',
],
'execution.read' => [
'description' => 'Access to read your project\'s execution logs',
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+99 -100
View File
@@ -64,7 +64,7 @@ App::post('/v1/functions')
'status' => 'disabled',
'name' => $name,
'runtime' => $runtime,
'tag' => '',
'deployment' => '',
'vars' => $vars,
'events' => $events,
'schedule' => $schedule,
@@ -314,8 +314,8 @@ App::put('/v1/functions/:functionId')
}
$original = $function->getAttribute('schedule', '');
$cron = (!empty($function->getAttribute('tag', null)) && !empty($schedule)) ? new CronExpression($schedule) : null;
$next = (!empty($function->getAttribute('tag', null)) && !empty($schedule)) ? $cron->getNextRunDate()->format('U') : 0;
$cron = (!empty($function->getAttribute('deployment', null)) && !empty($schedule)) ? new CronExpression($schedule) : null;
$next = (!empty($function->getAttribute('deployment', null)) && !empty($schedule)) ? $cron->getNextRunDate()->format('U') : 0;
$function = $dbForProject->updateDocument('functions', $function->getId(), new Document(array_merge($function->getArrayCopy(), [
'execute' => $execute,
@@ -343,38 +343,38 @@ App::put('/v1/functions/:functionId')
$response->dynamic($function, Response::MODEL_FUNCTION);
});
App::patch('/v1/functions/:functionId/tag')
App::patch('/v1/functions/:functionId/deployment')
->groups(['api', 'functions'])
->desc('Update Function Tag')
->desc('Update Function Deployment')
->label('scope', 'functions.write')
->label('event', 'functions.tags.update')
->label('event', 'functions.deployments.update')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'updateTag')
->label('sdk.description', '/docs/references/functions/update-function-tag.md')
->label('sdk.method', 'updateDeployment')
->label('sdk.description', '/docs/references/functions/update-function-deployment.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_FUNCTION)
->param('functionId', '', new UID(), 'Function ID.')
->param('tag', '', new UID(), 'Tag ID.')
->param('deployment', '', new UID(), 'Deployment ID.')
->inject('response')
->inject('dbForProject')
->inject('project')
->action(function ($functionId, $tag, $response, $dbForProject, $project) {
->action(function ($functionId, $deployment, $response, $dbForProject, $project) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
/** @var Utopia\Database\Document $project */
$function = $dbForProject->getDocument('functions', $functionId);
$tag = $dbForProject->getDocument('tags', $tag);
$build = $dbForProject->getDocument('builds', $tag->getAttribute('buildId', ''));
$deployment = $dbForProject->getDocument('deployments', $deployment);
$build = $dbForProject->getDocument('builds', $deployment->getAttribute('buildId'));
if ($function->isEmpty()) {
throw new Exception('Function not found', 404);
}
if ($tag->isEmpty()) {
throw new Exception('Tag not found', 404);
if ($deployment->isEmpty()) {
throw new Exception('Deployment not found', 404);
}
if ($build->isEmpty()) {
@@ -386,11 +386,11 @@ App::patch('/v1/functions/:functionId/tag')
}
$schedule = $function->getAttribute('schedule', '');
$cron = (empty($function->getAttribute('tag')) && !empty($schedule)) ? new CronExpression($schedule) : null;
$next = (empty($function->getAttribute('tag')) && !empty($schedule)) ? $cron->getNextRunDate()->format('U') : 0;
$cron = (empty($function->getAttribute('deployment')) && !empty($schedule)) ? new CronExpression($schedule) : null;
$next = (empty($function->getAttribute('deployment')) && !empty($schedule)) ? $cron->getNextRunDate()->format('U') : 0;
$function = $dbForProject->updateDocument('functions', $function->getId(), new Document(array_merge($function->getArrayCopy(), [
'tag' => $tag->getId(),
'deployment' => $deployment->getId(),
'scheduleNext' => (int)$next,
])));
@@ -431,7 +431,7 @@ App::delete('/v1/functions/:functionId')
$function = $dbForProject->getDocument('functions', $functionId);
// Request executor to delete tag containers
// Request executor to delete deployment containers
$ch = \curl_init();
\curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
\curl_setopt($ch, CURLOPT_URL, "http://appwrite-executor/v1/functions/$functionId");
@@ -476,20 +476,20 @@ App::delete('/v1/functions/:functionId')
$response->noContent();
});
App::post('/v1/functions/:functionId/tags')
App::post('/v1/functions/:functionId/deployments')
->groups(['api', 'functions'])
->desc('Create Tag')
->desc('Create Deployment')
->label('scope', 'functions.write')
->label('event', 'functions.tags.create')
->label('event', 'functions.deployments.create')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'createTag')
->label('sdk.description', '/docs/references/functions/create-tag.md')
->label('sdk.method', 'createDeployment')
->label('sdk.description', '/docs/references/functions/create-deployment.md')
->label('sdk.packaging', true)
->label('sdk.request.type', 'multipart/form-data')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_TAG)
->label('sdk.response.model', Response::MODEL_DEPLOYMENT)
->param('functionId', '', new UID(), 'Function ID.')
->param('entrypoint', '', new Text('1028'), 'Entrypoint File.')
->param('code', [], new File(), 'Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.', false)
@@ -550,23 +550,21 @@ App::post('/v1/functions/:functionId/tags')
}
if ((bool) $deploy) {
// Remove deploy for all other tags.
$tags = $dbForProject->find('tags', [
// Remove deploy for all other deployments.
$deployments = $dbForProject->find('deployments', [
new Query('deploy', Query::TYPE_EQUAL, [true]),
new Query('functionId', Query::TYPE_EQUAL, [$functionId])
]);
foreach ($tags as $tag) {
$tag->setAttribute('deploy', false);
$dbForProject->updateDocument('tags', $tag->getId(), $tag);
foreach ($deployments as $deployment) {
$deployment->setAttribute('deploy', false);
$dbForProject->updateDocument('deployments', $deployment->getId(), $deployment);
}
}
$tagId = $dbForProject->getId();
// TODO : What should be the read and write permissons of a tag?
$tag = $dbForProject->createDocument('tags', new Document([
'$id' => $tagId,
$deploymentId = $dbForProject->getId();
$deployment = $dbForProject->createDocument('deployments', new Document([
'$id' => $deploymentId,
'$read' => ['role:all'],
'$write' => ['role:all'],
'functionId' => $function->getId(),
@@ -574,45 +572,46 @@ App::post('/v1/functions/:functionId/tags')
'entrypoint' => $entrypoint,
'path' => $path,
'size' => $size,
'search' => implode(' ', [$tagId, $entrypoint]),
'search' => implode(' ', [$deploymentId, $entrypoint]),
'status' => 'processing',
'buildStdout' => '',
'buildStderr' => '',
'deploy' => ($deploy === 'true'),
]));
$usage
->setParam('storage', $tag->getAttribute('size', 0))
;
// Enqueue a message to start the build
Resque::enqueue('v1-builds', 'BuildsV1', [
'projectId' => $project->getId(),
'functionId' => $function->getId(),
'tagId' => $tagId,
'deploymentId' => $deploymentId,
'type' => BUILD_TYPE_TAG
]);
$usage
->setParam('storage', $deployment->getAttribute('size', 0))
;
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($tag, Response::MODEL_TAG);
$response->dynamic($deployment, Response::MODEL_DEPLOYMENT);
});
App::get('/v1/functions/:functionId/tags')
App::get('/v1/functions/:functionId/deployments')
->groups(['api', 'functions'])
->desc('List Tags')
->desc('List Deployments')
->label('scope', 'functions.read')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'listTags')
->label('sdk.description', '/docs/references/functions/list-tags.md')
->label('sdk.method', 'listDeployments')
->label('sdk.description', '/docs/references/functions/list-deployments.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_TAG_LIST)
->label('sdk.response.model', Response::MODEL_DEPLOYMENT_LIST)
->param('functionId', '', new UID(), 'Function ID.')
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->param('limit', 25, new Range(0, 100), 'Maximum number of tags to return in response. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true)
->param('limit', 25, new Range(0, 100), 'Maximum number of deployments to return in response. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true)
->param('offset', 0, new Range(0, APP_LIMIT_COUNT), 'Offset value. The default value is 0. Use this value to manage pagination. [learn more about pagination](https://appwrite.io/docs/pagination)', true)
->param('cursor', '', new UID(), 'ID of the tag used as the starting point for the query, excluding the tag itself. Should be used for efficient pagination when working with large sets of data. [learn more about pagination](https://appwrite.io/docs/pagination)', true)
->param('cursor', '', new UID(), 'ID of the deployment used as the starting point for the query, excluding the deployment itself. Should be used for efficient pagination when working with large sets of data. [learn more about pagination](https://appwrite.io/docs/pagination)', true)
->param('cursorDirection', Database::CURSOR_AFTER, new WhiteList([Database::CURSOR_AFTER, Database::CURSOR_BEFORE]), 'Direction of the cursor.', true)
->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true)
->inject('response')
@@ -628,10 +627,10 @@ App::get('/v1/functions/:functionId/tags')
}
if (!empty($cursor)) {
$cursorTag = $dbForProject->getDocument('tags', $cursor);
$cursorDeployment = $dbForProject->getDocument('deployments', $cursor);
if ($cursorTag->isEmpty()) {
throw new Exception("Tag '{$cursor}' for the 'cursor' value not found.", 400);
if ($cursorDeployment->isEmpty()) {
throw new Exception("Deployment '{$cursor}' for the 'cursor' value not found.", 400);
}
}
@@ -643,40 +642,40 @@ App::get('/v1/functions/:functionId/tags')
$queries[] = new Query('functionId', Query::TYPE_EQUAL, [$function->getId()]);
$results = $dbForProject->find('tags', $queries, $limit, $offset, [], [$orderType], $cursorTag ?? null, $cursorDirection);
$sum = $dbForProject->count('tags', $queries, APP_LIMIT_COUNT);
$results = $dbForProject->find('deployments', $queries, $limit, $offset, [], [$orderType], $cursorDeployment ?? null, $cursorDirection);
$sum = $dbForProject->count('deployments', $queries, APP_LIMIT_COUNT);
// Get Current Build Data
foreach ($results as &$tag) {
$build = $dbForProject->getDocument('builds', $tag->getAttribute('buildId', ''));
foreach ($results as &$deployment) {
$build = $dbForProject->getDocument('builds', $deployment->getAttribute('buildId', ''));
$tag['status'] = $build->getAttribute('status', 'processing');
$tag['buildStdout'] = $build->getAttribute('stdout', '');
$tag['buildStderr'] = $build->getAttribute('stderr', '');
$deployment['status'] = $build->getAttribute('status', 'processing');
$deployment['buildStdout'] = $build->getAttribute('stdout', '');
$deployment['buildStderr'] = $build->getAttribute('stderr', '');
}
$response->dynamic(new Document([
'tags' => $results,
'deployments' => $results,
'sum' => $sum,
]), Response::MODEL_TAG_LIST);
]), Response::MODEL_DEPLOYMENT_LIST);
});
App::get('/v1/functions/:functionId/tags/:tagId')
App::get('/v1/functions/:functionId/deployments/:deploymentId')
->groups(['api', 'functions'])
->desc('Get Tag')
->desc('Get Deployment')
->label('scope', 'functions.read')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'getTag')
->label('sdk.description', '/docs/references/functions/get-tag.md')
->label('sdk.method', 'getDeployment')
->label('sdk.description', '/docs/references/functions/get-deployment.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_TAG)
->label('sdk.response.model', Response::MODEL_DEPLOYMENT_LIST)
->param('functionId', '', new UID(), 'Function ID.')
->param('tagId', '', new UID(), 'Tag ID.')
->param('deploymentId', '', new UID(), 'Deployment ID.')
->inject('response')
->inject('dbForProject')
->action(function ($functionId, $tagId, $response, $dbForProject) {
->action(function ($functionId, $deploymentId, $response, $dbForProject) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
@@ -686,37 +685,37 @@ App::get('/v1/functions/:functionId/tags/:tagId')
throw new Exception('Function not found', 404);
}
$tag = $dbForProject->getDocument('tags', $tagId);
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
if ($tag->getAttribute('functionId') !== $function->getId()) {
throw new Exception('Tag not found', 404);
if ($deployment->getAttribute('functionId') !== $function->getId()) {
throw new Exception('Deployment not found', 404);
}
if ($tag->isEmpty()) {
throw new Exception('Tag not found', 404);
if ($deployment->isEmpty()) {
throw new Exception('Deployment not found', 404);
}
$response->dynamic($tag, Response::MODEL_TAG);
$response->dynamic($deployment, Response::MODEL_DEPLOYMENT);
});
App::delete('/v1/functions/:functionId/tags/:tagId')
App::delete('/v1/functions/:functionId/deployments/:deploymentId')
->groups(['api', 'functions'])
->desc('Delete Tag')
->desc('Delete Deployment')
->label('scope', 'functions.write')
->label('event', 'functions.tags.delete')
->label('event', 'functions.deployments.delete')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'deleteTag')
->label('sdk.description', '/docs/references/functions/delete-tag.md')
->label('sdk.method', 'deleteDeployment')
->label('sdk.description', '/docs/references/functions/delete-deployment.md')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.model', Response::MODEL_NONE)
->param('functionId', '', new UID(), 'Function ID.')
->param('tagId', '', new UID(), 'Tag ID.')
->param('deploymentId', '', new UID(), 'Deployment ID.')
->inject('response')
->inject('dbForProject')
->inject('usage')
->inject('project')
->action(function ($functionId, $tagId, $response, $dbForProject, $usage, $project) {
->action(function ($functionId, $deploymentId, $response, $dbForProject, $usage, $project) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForProject */
/** @var Appwrite\Event\Event $usage */
@@ -728,20 +727,20 @@ App::delete('/v1/functions/:functionId/tags/:tagId')
throw new Exception('Function not found', 404);
}
$tag = $dbForProject->getDocument('tags', $tagId);
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
if ($tag->getAttribute('functionId') !== $function->getId()) {
throw new Exception('Tag not found', 404);
if ($deployment->getAttribute('functionId') !== $function->getId()) {
throw new Exception('Deployment not found', 404);
}
if ($tag->isEmpty()) {
throw new Exception('Tag not found', 404);
if ($deployment->isEmpty()) {
throw new Exception('deployment not found', 404);
}
// Request executor to delete tag containers
// Request executor to delete deployment containers
$ch = \curl_init();
\curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
\curl_setopt($ch, CURLOPT_URL, "http://appwrite-executor/v1/tags/$tagId");
\curl_setopt($ch, CURLOPT_URL, "http://appwrite-executor/v1/deployments/$deploymentId");
\curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
\curl_setopt($ch, CURLOPT_TIMEOUT, 900);
\curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
@@ -769,20 +768,20 @@ App::delete('/v1/functions/:functionId/tags/:tagId')
$device = Storage::getDevice('functions');
if ($device->delete($tag->getAttribute('path', ''))) {
if (!$dbForProject->deleteDocument('tags', $tag->getId())) {
throw new Exception('Failed to remove tag from DB', 500);
if ($device->delete($deployment->getAttribute('path', ''))) {
if (!$dbForProject->deleteDocument('deployments', $deployment->getId())) {
throw new Exception('Failed to remove deployment from DB', 500);
}
}
if($function->getAttribute('tag') === $tag->getId()) { // Reset function tag
if($function->getAttribute('deployment') === $deployment->getId()) { // Reset function deployment
$function = $dbForProject->updateDocument('functions', $function->getId(), new Document(array_merge($function->getArrayCopy(), [
'tag' => '',
'deployment' => '',
])));
}
$usage
->setParam('storage', $tag->getAttribute('size', 0) * -1)
->setParam('storage', $deployment->getAttribute('size', 0) * -1)
;
$response->noContent();
@@ -821,14 +820,14 @@ App::post('/v1/functions/:functionId/executions')
throw new Exception('Function not found', 404);
}
$tag = Authorization::skip(fn() => $dbForProject->getDocument('tags', $function->getAttribute('tag')));
$deployment = Authorization::skip(fn() => $dbForProject->getDocument('deployments', $function->getAttribute('deployment')));
if ($tag->getAttribute('functionId') !== $function->getId()) {
throw new Exception('Tag not found. Deploy tag before trying to execute a function', 404);
if ($deployment->getAttribute('functionId') !== $function->getId()) {
throw new Exception('Deployment not found. Deploy deployment before trying to execute a function', 404);
}
if ($tag->isEmpty()) {
throw new Exception('Tag not found. Deploy tag before trying to execute a function', 404);
if ($deployment->isEmpty()) {
throw new Exception('Deployment not found. Deploy deployment before trying to execute a function', 404);
}
$validator = new Authorization('execute');
@@ -845,7 +844,7 @@ App::post('/v1/functions/:functionId/executions')
'$write' => ['role:all'],
'dateCreated' => time(),
'functionId' => $function->getId(),
'tagId' => $tag->getId(),
'deploymentId' => $deployment->getId(),
'trigger' => 'http', // http / schedule / event
'status' => 'waiting', // waiting / processing / completed / failed
'statusCode' => 0,
@@ -1095,7 +1094,7 @@ App::post('/v1/builds/:buildId')
->groups(['api', 'functions'])
->desc('Retry Build')
->label('scope', 'functions.write')
->label('event', 'functions.tags.update')
->label('event', 'functions.deployments.update')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'functions')
->label('sdk.method', 'retryBuild')
+86 -87
View File
@@ -153,7 +153,7 @@ try {
call_user_func($logError, $error, "startupError");
}
function createRuntimeServer(string $functionId, string $projectId, string $tagId, Database $database): void
function createRuntimeServer(string $functionId, string $projectId, string $deploymentId, Database $database): void
{
global $orchestrationPool;
global $runtimes;
@@ -162,17 +162,17 @@ function createRuntimeServer(string $functionId, string $projectId, string $tagI
try {
$orchestration = $orchestrationPool->get();
$function = $database->getDocument('functions', $functionId);
$tag = $database->getDocument('tags', $tagId);
$deployment = $database->getDocument('deployments', $deploymentId);
if ($tag->getAttribute('buildId') === null) {
throw new Exception('Tag has no buildId');
if ($deployment->getAttribute('buildId') === null) {
throw new Exception('Deployment has no buildId');
}
// Grab Build Document
$build = $database->getDocument('builds', $tag->getAttribute('buildId'));
$build = $database->getDocument('builds', $deployment->getAttribute('buildId'));
// Check if function isn't already created
$functions = $orchestration->list(['label' => 'appwrite-type=function', 'name' => 'appwrite-function-' . $tag->getId()]);
$functions = $orchestration->list(['label' => 'appwrite-type=function', 'name' => 'appwrite-function-' . $deployment->getId()]);
if (\count($functions) > 0) {
return;
@@ -184,8 +184,8 @@ function createRuntimeServer(string $functionId, string $projectId, string $tagI
// Check if runtime is active
$runtime = $runtimes[$function->getAttribute('runtime', '')] ?? null;
if ($tag->getAttribute('functionId') !== $function->getId()) {
throw new Exception('Tag not found', 404);
if ($deployment->getAttribute('functionId') !== $function->getId()) {
throw new Exception('deployment not found', 404);
}
if (\is_null($runtime)) {
@@ -196,7 +196,7 @@ function createRuntimeServer(string $functionId, string $projectId, string $tagI
$vars = \array_merge($function->getAttribute('vars', []), [
'APPWRITE_FUNCTION_ID' => $function->getId(),
'APPWRITE_FUNCTION_NAME' => $function->getAttribute('name', ''),
'APPWRITE_FUNCTION_TAG' => $tag->getId(),
'APPWRITE_FUNCTION_DEPLOYMENT' => $deployment->getId(),
'APPWRITE_FUNCTION_RUNTIME_NAME' => $runtime['name'],
'APPWRITE_FUNCTION_RUNTIME_VERSION' => $runtime['version'],
'APPWRITE_FUNCTION_PROJECT_ID' => $projectId,
@@ -205,7 +205,7 @@ function createRuntimeServer(string $functionId, string $projectId, string $tagI
$vars = \array_merge($vars, $build->getAttribute('vars', [])); // for gettng endpoint.
$container = 'appwrite-function-' . $tag->getId();
$container = 'appwrite-function-' . $deployment->getId();
if ($activeFunctions->exists($container) && !(\substr($activeFunctions->get($container)['status'], 0, 2) === 'Up')) { // Remove container if not online
// If container is online then stop and remove it
@@ -222,41 +222,41 @@ function createRuntimeServer(string $functionId, string $projectId, string $tagI
$activeFunctions->del($container);
}
// Check if tag hasn't failed
// Check if deployment hasn't failed
if ($build->getAttribute('status') === 'failed') {
throw new Exception('Tag build failed, please check your logs.', 500);
throw new Exception('Deployment build failed, please check your logs.', 500);
}
// Check if tag is built yet.
// Check if deployment is built yet.
if ($build->getAttribute('status') !== 'ready') {
throw new Exception('Tag is not built yet', 500);
throw new Exception('Deployment is not built yet', 500);
}
// Grab Tag Files
$tagPath = $build->getAttribute('outputPath', '');
// Grab Deployment Files
$deploymentPath = $build->getAttribute('outputPath', '');
$tagPathTarget = '/tmp/project-' . $projectId . '/' . $build->getId() . '/builtCode/code.tar.gz';
$tagPathTargetDir = \pathinfo($tagPathTarget, PATHINFO_DIRNAME);
$container = 'appwrite-function-' . $tag->getId();
$deploymentPathTarget = '/tmp/project-' . $projectId . '/' . $build->getId() . '/builtCode/code.tar.gz';
$deploymentPathTargetDir = \pathinfo($deploymentPathTarget, PATHINFO_DIRNAME);
$container = 'appwrite-function-' . $deployment->getId();
$device = Storage::getDevice('builds');
if (!\file_exists($tagPathTargetDir)) {
if (@\mkdir($tagPathTargetDir, 0777, true)) {
\chmod($tagPathTargetDir, 0777);
if (!\file_exists($deploymentPathTargetDir)) {
if (@\mkdir($deploymentPathTargetDir, 0777, true)) {
\chmod($deploymentPathTargetDir, 0777);
} else {
throw new Exception('Can\'t create directory ' . $tagPathTargetDir);
throw new Exception('Can\'t create directory ' . $deploymentPathTargetDir);
}
}
if (!\file_exists($tagPathTarget)) {
if (!\file_exists($deploymentPathTarget)) {
if (App::getEnv('_APP_STORAGE_DEVICE', Storage::DEVICE_LOCAL) === Storage::DEVICE_LOCAL) {
if (!\copy($tagPath, $tagPathTarget)) {
throw new Exception('Can\'t create temporary code file ' . $tagPathTarget);
if (!\copy($deploymentPath, $deploymentPathTarget)) {
throw new Exception('Can\'t create temporary code file ' . $deploymentPathTarget);
}
} else {
$buffer = $device->read($tagPath);
\file_put_contents($tagPathTarget, $buffer);
$buffer = $device->read($deploymentPath);
\file_put_contents($deploymentPathTarget, $buffer);
}
};
@@ -290,10 +290,10 @@ function createRuntimeServer(string $functionId, string $projectId, string $tagI
'appwrite-created' => strval($executionTime),
'appwrite-runtime' => $function->getAttribute('runtime', ''),
'appwrite-project' => $projectId,
'appwrite-tag' => $tag->getId(),
'appwrite-deployment' => $deployment->getId(),
],
hostname: $container,
mountFolder: $tagPathTargetDir,
mountFolder: $deploymentPathTargetDir,
);
if (empty($id)) {
@@ -333,11 +333,11 @@ function execute(string $trigger, string $projectId, string $executionId, string
global $register;
$function = $database->getDocument('functions', $functionId);
$tag = $database->getDocument('tags', $function->getAttribute('tag', ''));
$build = $database->getDocument('builds', $tag->getAttribute('buildId', ''));
$deployment = $database->getDocument('deployments', $function->getAttribute('deployment', ''));
$build = $database->getDocument('builds', $deployment->getAttribute('buildId', ''));
if ($tag->getAttribute('functionId') !== $function->getId()) {
throw new Exception('Tag not found', 404);
if ($deployment->getAttribute('functionId') !== $function->getId()) {
throw new Exception('Deployment not found', 404);
}
// Grab execution document if exists
@@ -350,7 +350,7 @@ function execute(string $trigger, string $projectId, string $executionId, string
'$write' => ['role:all'],
'dateCreated' => time(),
'functionId' => $function->getId(),
'tagId' => $tag->getId(),
'deploymentId' => $deployment->getId(),
'trigger' => $trigger, // http / schedule / event
'status' => 'processing', // waiting / processing / completed / failed
'statusCode' => 0,
@@ -370,12 +370,12 @@ function execute(string $trigger, string $projectId, string $executionId, string
$execution
->setAttribute('status', 'failed')
->setAttribute('statusCode', 500)
->setAttribute('stderr', 'Tag is still being built.')
->setAttribute('stderr', 'Deployment is still being built.')
->setAttribute('time', 0);
$database->updateDocument('executions', $execution->getId(), $execution);
throw new Exception('Execution Failed. Reason: Tag is still being built.');
throw new Exception('Execution Failed. Reason: Deployment is still being built.');
}
// Check if runtime is active
@@ -389,7 +389,7 @@ function execute(string $trigger, string $projectId, string $executionId, string
$vars = \array_merge($function->getAttribute('vars', []), [
'APPWRITE_FUNCTION_ID' => $function->getId(),
'APPWRITE_FUNCTION_NAME' => $function->getAttribute('name', ''),
'APPWRITE_FUNCTION_TAG' => $tag->getId(),
'APPWRITE_FUNCTION_DEPLOYMENT' => $deployment->getId(),
'APPWRITE_FUNCTION_TRIGGER' => $trigger,
'APPWRITE_FUNCTION_RUNTIME_NAME' => $runtime['name'],
'APPWRITE_FUNCTION_RUNTIME_VERSION' => $runtime['version'],
@@ -403,7 +403,7 @@ function execute(string $trigger, string $projectId, string $executionId, string
$vars = \array_merge($vars, $build->getAttribute('vars', []));
$container = 'appwrite-function-' . $tag->getId();
$container = 'appwrite-function-' . $deployment->getId();
try {
if ($build->getAttribute('status') !== 'ready') {
@@ -417,13 +417,13 @@ function execute(string $trigger, string $projectId, string $executionId, string
'status' => 'processing',
'outputPath' => '',
'runtime' => $function->getAttribute('runtime', ''),
'source' => $tag->getAttribute('path'),
'source' => $deployment->getAttribute('path'),
'sourceType' => Storage::DEVICE_LOCAL,
'stdout' => '',
'stderr' => '',
'time' => 0,
'vars' => [
'ENTRYPOINT_NAME' => $tag->getAttribute('entrypoint'),
'ENTRYPOINT_NAME' => $deployment->getAttribute('entrypoint'),
'APPWRITE_FUNCTION_ID' => $function->getId(),
'APPWRITE_FUNCTION_NAME' => $function->getAttribute('name', ''),
'APPWRITE_FUNCTION_RUNTIME_NAME' => $runtime['name'],
@@ -432,9 +432,9 @@ function execute(string $trigger, string $projectId, string $executionId, string
]
]));
$tag->setAttribute('buildId', $buildId);
$deployment->setAttribute('buildId', $buildId);
$database->updateDocument('tags', $tag->getId(), $tag);
$database->updateDocument('deployments', $deployment->getId(), $deployment);
runBuildStage($buildId, $projectId);
}
@@ -452,7 +452,7 @@ function execute(string $trigger, string $projectId, string $executionId, string
try {
if (!$activeFunctions->exists($container)) { // Create container if not ready
createRuntimeServer($functionId, $projectId, $tag->getId(), $database);
createRuntimeServer($functionId, $projectId, $deployment->getId(), $database);
} else if ($activeFunctions->get($container)['status'] === 'Down') {
sleep(1);
} else {
@@ -479,13 +479,13 @@ function execute(string $trigger, string $projectId, string $executionId, string
];
}
$key = $activeFunctions->get('appwrite-function-' . $tag->getId(), 'key');
$key = $activeFunctions->get('appwrite-function-' . $deployment->getId(), 'key');
// Process environment variables
$vars = \array_merge($function->getAttribute('vars', []), [
'APPWRITE_FUNCTION_ID' => $function->getId(),
'APPWRITE_FUNCTION_NAME' => $function->getAttribute('name', ''),
'APPWRITE_FUNCTION_TAG' => $tag->getId(),
'APPWRITE_FUNCTION_DEPLOYMENT' => $deployment->getId(),
'APPWRITE_FUNCTION_TRIGGER' => $trigger,
'APPWRITE_FUNCTION_RUNTIME_NAME' => $runtime['name'],
'APPWRITE_FUNCTION_RUNTIME_VERSION' => $runtime['version'],
@@ -603,7 +603,7 @@ function execute(string $trigger, string $projectId, string $executionId, string
Console::success('Function executed in ' . ($executionEnd - $executionStart) . ' seconds, status: ' . $functionStatus);
$execution->setAttribute('tagId', $tag->getId())
$execution->setAttribute('deploymentId', $deployment->getId())
->setAttribute('status', $functionStatus)
->setAttribute('statusCode', $statusCode)
->setAttribute('stdout', \utf8_encode(\mb_substr($stdout, -8000)))
@@ -701,37 +701,37 @@ function runBuildStage(string $buildId, string $projectID): Document
}
// Grab Tag Files
$tagPath = $build->getAttribute('source', '');
$deploymentPath = $build->getAttribute('source', '');
$sourceType = $build->getAttribute('sourceType', '');
$device = Storage::getDevice('builds');
$tagPathTarget = '/tmp/project-' . $projectID . '/' . $build->getId() . '/code.tar.gz';
$tagPathTargetDir = \pathinfo($tagPathTarget, PATHINFO_DIRNAME);
$deploymentPathTarget = '/tmp/project-' . $projectID . '/' . $build->getId() . '/code.tar.gz';
$deploymentPathTargetDir = \pathinfo($deploymentPathTarget, PATHINFO_DIRNAME);
$container = 'build-stage-' . $build->getId();
// Perform various checks
if (!\file_exists($tagPathTargetDir)) {
if (@\mkdir($tagPathTargetDir, 0777, true)) {
\chmod($tagPathTargetDir, 0777);
if (!\file_exists($deploymentPathTargetDir)) {
if (@\mkdir($deploymentPathTargetDir, 0777, true)) {
\chmod($deploymentPathTargetDir, 0777);
} else {
throw new Exception('Can\'t create directory ' . $tagPathTargetDir);
throw new Exception('Can\'t create directory ' . $deploymentPathTargetDir);
}
}
if (!\file_exists($tagPathTarget)) {
if (!\file_exists($deploymentPathTarget)) {
if (App::getEnv('_APP_STORAGE_DEVICE', Storage::DEVICE_LOCAL) === Storage::DEVICE_LOCAL) {
if (!\copy($tagPath, $tagPathTarget)) {
throw new Exception('Can\'t create temporary code file ' . $tagPathTarget);
if (!\copy($deploymentPath, $deploymentPathTarget)) {
throw new Exception('Can\'t create temporary code file ' . $deploymentPathTarget);
}
} else {
$buffer = $device->read($tagPath);
\file_put_contents($tagPathTarget, $buffer);
$buffer = $device->read($deploymentPath);
\file_put_contents($deploymentPathTarget, $buffer);
}
}
if (!$device->exists($tagPath)) {
if (!$device->exists($deploymentPath)) {
throw new Exception('Code is not readable: ' . $build->getAttribute('source', ''));
}
@@ -776,7 +776,7 @@ function runBuildStage(string $buildId, string $projectID): Document
'/dev/null'
],
hostname: $container,
mountFolder: $tagPathTargetDir,
mountFolder: $deploymentPathTargetDir,
volumes: [
'/tmp/project-' . $projectID . '/' . $build->getId() . '/builtCode' . ':/usr/builtCode:rw'
]
@@ -960,29 +960,29 @@ App::delete('/v1/functions/:functionId')
throw new Exception('Function not found', 404);
}
$results = $dbForProject->find('tags', [new Query('functionId', Query::TYPE_EQUAL, [$functionId])], 999);
$results = $dbForProject->find('deployments', [new Query('functionId', Query::TYPE_EQUAL, [$functionId])], 999);
// If amount is 0 then we simply return true
if (count($results) === 0) {
return $response->json(['success' => true]);
}
// Delete the containers of all tags
foreach ($results as $tag) {
// Delete the containers of all deployments
foreach ($results as $deployment) {
try {
// Remove any ongoing builds
if ($tag->getAttribute('buildId')) {
$build = $dbForProject->getDocument('builds', $tag->getAttribute('buildId'));
if ($deployment->getAttribute('buildId')) {
$build = $dbForProject->getDocument('builds', $deployment->getAttribute('buildId'));
if ($build->getAttribute('status') === 'building') {
// Remove the build
$orchestration->remove('build-stage-' . $tag->getAttribute('buildId'), true);
Console::info('Removed build for tag ' . $tag['$id']);
$orchestration->remove('build-stage-' . $deployment->getAttribute('buildId'), true);
Console::info('Removed build for deployment ' . $deployment['$id']);
}
}
$orchestration->remove('appwrite-function-' . $tag['$id'], true);
Console::info('Removed container for tag ' . $tag['$id']);
$orchestration->remove('appwrite-function-' . $deployment['$id'], true);
Console::info('Removed container for deployment ' . $deployment['$id']);
} catch (Exception $e) {
// Do nothing, we don't care that much if it fails
}
@@ -1031,38 +1031,38 @@ App::post('/v1/functions/:functionId/tags/:tagId/runtime')
->send();
});
App::delete('/v1/tags/:tagId')
->param('tagId', '', new UID(), 'Tag unique ID.')
App::delete('/v1/deployments/:deploymentId')
->param('deploymentId', '', new UID(), 'Deployment unique ID.')
->inject('response')
->inject('dbForProject')
->action(function (string $tagId, Response $response, Database $dbForProject) use ($orchestrationPool) {
->action(function (string $deploymentId, Response $response, Database $dbForProject) use ($orchestrationPool) {
try {
/** @var Orchestration $orchestration */
$orchestration = $orchestrationPool->get();
// Get tag document
$tag = $dbForProject->getDocument('tags', $tagId);
// Get deployment document
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
// Check if tag exists
if ($tag->isEmpty()) {
throw new Exception('Tag not found', 404);
// Check if deployment exists
if ($deployment->isEmpty()) {
throw new Exception('Deployment not found', 404);
}
try {
// Remove any ongoing builds
if ($tag->getAttribute('buildId')) {
$build = $dbForProject->getDocument('builds', $tag->getAttribute('buildId'));
if ($deployment->getAttribute('buildId')) {
$build = $dbForProject->getDocument('builds', $deployment->getAttribute('buildId'));
if ($build->getAttribute('status') == 'building') {
// Remove the build
$orchestration->remove('build-stage-' . $tag->getAttribute('buildId'), true);
Console::info('Removed build for tag ' . $tag['$id']);
$orchestration->remove('build-stage-' . $deployment->getAttribute('buildId'), true);
Console::info('Removed build for deployment ' . $deployment['$id']);
}
}
// Remove the container of the tag
$orchestration->remove('appwrite-function-' . $tag['$id'], true);
Console::info('Removed container for tag ' . $tag['$id']);
// Remove the container of the deployment
$orchestration->remove('appwrite-function-' . $deployment['$id'], true);
Console::info('Removed container for deployment ' . $deployment['$id']);
} catch (Exception $e) {
// Do nothing, we don't care that much if it fails
}
@@ -1078,7 +1078,6 @@ App::delete('/v1/tags/:tagId')
});
App::post('/v1/builds/:buildId')
->desc('Start a build')
->param('buildId', '', new UID(), 'Build unique ID.', false)
->inject('response')
->inject('dbForProject')
@@ -1148,7 +1147,7 @@ function handleShutdown()
// Get list of all processing executions
$executions = $database->find('executions', [
new Query('tagId', Query::TYPE_EQUAL, [$container->getLabels()["appwrite-tag"]]),
new Query('deploymentId', Query::TYPE_EQUAL, [$container->getLabels()["appwrite-deployment"]]),
new Query('status', Query::TYPE_EQUAL, ['waiting'])
]);
+1 -1
View File
@@ -62,7 +62,7 @@ const APP_PAGING_LIMIT = 12;
const APP_LIMIT_COUNT = 5000;
const APP_LIMIT_USERS = 10000;
const APP_CACHE_BUSTER = 201;
const APP_VERSION_STABLE = '0.13.0';
const APP_VERSION_STABLE = '0.12.1';
const APP_DATABASE_ATTRIBUTE_EMAIL = 'email';
const APP_DATABASE_ATTRIBUTE_ENUM = 'enum';
const APP_DATABASE_ATTRIBUTE_IP = 'ip';
+1 -1
View File
@@ -370,7 +370,7 @@ $cli
// Get total storage
$dbForProject->setNamespace('_project_' . $projectId);
$storageTotal = $dbForProject->sum('files', 'sizeOriginal') + $dbForProject->sum('tags', 'size');
$storageTotal = $dbForProject->sum('files', 'sizeOriginal') + $dbForProject->sum('deployments', 'size');
$time = (int) (floor(time() / 1800) * 1800); // Time rounded to nearest 30 minutes
$id = \md5($time . '_30m_storage.total'); //Construct unique id for each metric using time, period and metric
+64 -64
View File
@@ -8,7 +8,7 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
<div
data-service="functions.get"
data-name="project-function"
data-event="load,functions.update,functions.createTag,functions.updateTag,functions.deleteTag,functions.retryBuild"
data-event="load,functions.update,functions.createDeployment,functions.updateDeployment,functions.deleteDeployment,functions.retryBuild"
data-param-function-id="{{router.params.id}}"
data-success="trigger"
data-success-param-trigger-events="functions.get">
@@ -50,77 +50,77 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
<p class="text-fade margin-bottom-small" data-ls-bind="{{project-function.runtime|runtimeName}} {{project-function.runtime|runtimeVersion}}">
</p>
<div data-ls-if="{{project-function.tag}} !== ''" class="margin-top">
<div data-ls-if="{{project-function.deployment}} !== ''" class="margin-top">
<button data-ls-ui-trigger="execute-now">Execute Now</button> &nbsp; <a data-ls-attrs="href=/console/functions/function/logs?id={{router.params.id}}&project={{router.params.project}}" class="button reverse" style="vertical-align: top;">View Logs</a>
</div>
</div>
</div>
<div class="margin-bottom"
data-service="functions.listTags"
data-service="functions.listDeployments"
data-scope="sdk"
data-event="load,functions.createTag,functions.deleteTag,functions.updateTag,functions.retryBuild"
data-name="project-function-tags"
data-event="load,functions.createDeployment,functions.deleteDeployment,functions.updateDeployment,functions.retryBuild"
data-name="project-function-deployments"
data-param-function-id="{{router.params.id}}"
data-param-limit="<?php echo APP_PAGING_LIMIT; ?>"
data-param-offset=""
data-param-order-type="DESC"
data-success="trigger"
data-success-param-trigger-events="functions.listTags">
data-success-param-trigger-events="functions.listDeployments">
<h3>Tags <span class="text-fade text-size-small pull-end margin-top-small" data-ls-bind="{{project-function-tags.sum}} tags found"></span></h3>
<h3>Deployments <span class="text-fade text-size-small pull-end margin-top-small" data-ls-bind="{{project-function-deployments.sum}} deployments found"></span></h3>
<div data-ls-if="0 == {{project-function-tags.tags.length}} || undefined == {{project-function-tags.tags.length}}" class="box margin-top margin-bottom">
<h3 class="margin-bottom-small text-bold">No Tags Found</h3>
<div data-ls-if="0 == {{project-function-deployments.deployments.length}} || undefined == {{project-function-deployments.deployments.length}}" class="box margin-top margin-bottom">
<h3 class="margin-bottom-small text-bold">No Deployments Found</h3>
<p class="margin-bottom-no">You haven't deployed any tags for your function yet.</p>
<p class="margin-bottom-no">You haven't deployed any deployments for your function yet.</p>
</div>
<div data-ls-if="(0 != {{project-function-tags.tags.length}}) && (undefined !== {{project-function-tags.tags.length}})">
<div data-ls-if="(0 != {{project-function-deployments.deployments.length}}) && (undefined !== {{project-function-deployments.deployments.length}})">
<div class="box margin-bottom">
<ul data-ls-loop="project-function-tags.tags" data-ls-as="tag" class="list">
<ul data-ls-loop="project-function-deployments.deployments" data-ls-as="deployment" class="list">
<li class="clear">
<div data-ui-modal class="modal width-large box close" data-button-hide="on" data-open-event="open-stderr-{{tag.$id}}">
<div data-ui-modal class="modal width-large box close" data-button-hide="on" data-open-event="open-stderr-{{deployment.$id}}">
<button type="button" class="close pull-end" data-ui-modal-close=""><i class="icon-cancel"></i></button>
<h2>Build Error Log</h2>
<div class="margin-bottom">
<input type="hidden" data-ls-bind="{{tag.buildStderr}}" data-forms-code="bash" data-lang="bash" data-lang-label="Bash" />
<input type="hidden" data-ls-bind="{{deployment.buildStderr}}" data-forms-code="bash" data-lang="bash" data-lang-label="Bash" />
</div>
<button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
</div>
<div data-ui-modal class="modal width-large box close" data-button-hide="on" data-open-event="open-stdout-{{tag.$id}}">
<div data-ui-modal class="modal width-large box close" data-button-hide="on" data-open-event="open-stdout-{{deployment.$id}}">
<button type="button" class="close pull-end" data-ui-modal-close=""><i class="icon-cancel"></i></button>
<h2>Build Log</h2>
<div class="margin-bottom">
<input type="hidden" data-ls-bind="{{tag.buildStdout}}" data-forms-code="bash" data-lang="bash" data-lang-label="Bash" />
<input type="hidden" data-ls-bind="{{deployment.buildStdout}}" data-forms-code="bash" data-lang="bash" data-lang-label="Bash" />
</div>
<button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
</div>
<form data-ls-if="({{tag.$id}} !== {{project-function.tag}} && {{tag.status}} == 'ready')" name="functions.updateTag" class="pull-end"
<form data-ls-if="({{deployment.$id}} !== {{project-function.deployment}} && {{deployment.status}} == 'ready')" name="functions.updateDeployment" class="pull-end"
data-analytics
data-analytics-activity
data-analytics-event="submit"
data-analytics-category="console"
data-analytics-label="Create Function Execution"
data-service="functions.updateTag"
data-service="functions.updateDeployment"
data-event="submit"
data-param-function-id="{{router.params.id}}"
data-success="alert,trigger"
data-success-param-alert-text="Tag updated successfully"
data-success-param-trigger-events="functions.updateTag"
data-success-param-alert-text="Deployment updated successfully"
data-success-param-trigger-events="functions.updateDeployment"
data-failure="alert"
data-failure-param-alert-text="Failed to update tag"
data-failure-param-alert-text="Failed to update deployment"
data-failure-param-alert-classname="error">
<input type="hidden" name="tag" data-ls-bind="{{tag.$id}}">
<input type="hidden" name="deployment" data-ls-bind="{{deployment.$id}}">
<button>Activate</button>
</form>
<form data-ls-if="({{tag.$id}} !== {{project-function.tag}} && {{tag.status}} == 'failed')" name="functions.retryBuild" class="pull-end"
<form data-ls-if="({{deployment.$id}} !== {{project-function.deployment}} && {{deployment.status}} == 'failed')" name="functions.retryBuild" class="pull-end"
data-analytics
data-analytics-activity
data-analytics-event="submit"
@@ -134,38 +134,38 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
data-failure="alert"
data-failure-param-alert-text="Failed to retry build"
data-failure-param-alert-classname="error">
<input type="hidden" name="buildId" data-ls-bind="{{tag.buildId}}">
<input type="hidden" name="buildId" data-ls-bind="{{deployment.buildId}}">
<button>Retry Build</button>
</form>
<b data-ls-bind="{{tag.$id}}"></b> &nbsp;
<span class="text-fade" data-ls-bind="{{tag.entrypoint}}"></span>
<b data-ls-bind="{{deployment.$id}}"></b> &nbsp;
<span class="text-fade" data-ls-bind="{{deployment.entrypoint}}"></span>
<div class="text-size-small margin-top-small clear">
<span data-ls-if="{{tag.status}} == 'failed'" style="color: var(--config-color-danger)" class="pull-start" data-ls-bind="{{tag.status}}"></span>
<span data-ls-if="{{tag.status}} == 'ready'" style="color: var(--config-color-success)" class="pull-start" data-ls-bind="{{tag.status}}"></span>
<span data-ls-if="{{tag.status}} == 'processing' || {{tag.status}} == 'building'" style="color: var(--config-color-info)" class="pull-start" data-ls-bind="{{tag.status}}"></span>
<span class="pull-start" data-ls-bind="&nbsp; | &nbsp; Created {{tag.dateCreated|timeSince}} &nbsp; | &nbsp; {{tag.size|humanFileSize}}{{tag.size|humanFileUnit}}"></span>
<span data-ls-if="{{deployment.status}} == 'failed'" style="color: var(--config-color-danger)" class="pull-start" data-ls-bind="{{deployment.status}}"></span>
<span data-ls-if="{{deployment.status}} == 'ready'" style="color: var(--config-color-success)" class="pull-start" data-ls-bind="{{deployment.status}}"></span>
<span data-ls-if="{{deployment.status}} == 'processing' || {{deployment.status}} == 'building'" style="color: var(--config-color-info)" class="pull-start" data-ls-bind="{{deployment.status}}"></span>
<span class="pull-start" data-ls-bind="&nbsp; | &nbsp; Created {{deployment.dateCreated|timeSince}} &nbsp; | &nbsp; {{deployment.size|humanFileSize}}{{deployment.size|humanFileUnit}}"></span>
<span data-ls-if="{{tag.status}} == 'failed'">&nbsp; | &nbsp;<button type="button" class="link text-size-small" data-ls-ui-trigger="open-stderr-{{tag.$id}}">Logs</button></span>
<span data-ls-if="{{tag.status}} == 'ready'">&nbsp; | &nbsp;<button type="button" class="link text-size-small" data-ls-ui-trigger="open-stdout-{{tag.$id}}">Logs</button></span>
<span data-ls-if="{{deployment.status}} == 'failed'">&nbsp; | &nbsp;<button type="button" class="link text-size-small" data-ls-ui-trigger="open-stderr-{{deployment.$id}}">Logs</button></span>
<span data-ls-if="{{deployment.status}} == 'ready'">&nbsp; | &nbsp;<button type="button" class="link text-size-small" data-ls-ui-trigger="open-stdout-{{deployment.$id}}">Logs</button></span>
<form data-ls-if="{{tag.$id}} !== {{project-function.tag}}" name="functions.deleteTag" class="pull-start"
<form data-ls-if="{{deployment.$id}} !== {{project-function.deployment}}" name="functions.deleteDeployment" class="pull-start"
data-analytics
data-analytics-activity
data-analytics-event="submit"
data-analytics-category="console"
data-analytics-label="Delete Function Tag"
data-service="functions.deleteTag"
data-analytics-label="Delete Function Deployment"
data-service="functions.deleteDeployment"
data-event="submit"
data-param-function-id="{{router.params.id}}"
data-confirm="Are you sure you want to delete this function tag?"
data-confirm="Are you sure you want to delete this function deployment?"
data-success="alert,trigger"
data-success-param-alert-text="Function tag deleted successfully"
data-success-param-trigger-events="functions.deleteTag"
data-success-param-alert-text="Function deployment deleted successfully"
data-success-param-trigger-events="functions.deleteDeployment"
data-failure="alert"
data-failure-param-alert-text="Failed to delete function tag"
data-failure-param-alert-text="Failed to delete function deployment"
data-failure-param-alert-classname="error">
<input type="hidden" name="tagId" data-ls-bind="{{tag.$id}}" />
<input type="hidden" name="deploymentId" data-ls-bind="{{deployment.$id}}" />
&nbsp; | &nbsp;<button type="submit" class="link text-danger text-size-small">Delete</button>
</form>
@@ -177,38 +177,38 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
</div>
<div class="pull-start">
<button data-ls-ui-trigger="deploy-tag">Deploy Tag</button>
<button data-ls-ui-trigger="deploy-deployment">Create Deployment</button>
</div>
<div class="pull-end paging">
<form
data-service="functions.listTags"
data-service="functions.listDeployments"
data-event="submit"
data-param-function-id="{{router.params.id}}"
data-param-search="{{router.params.search}}"
data-param-limit="<?php echo APP_PAGING_LIMIT; ?>"
data-param-order-type="DESC"
data-scope="sdk"
data-name="project-function-tags"
data-name="project-function-deployments"
data-success="state"
data-success-param-state-keys="search,offset">
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-sum="{{project-function-tags.sum}}" class="margin-end round small" aria-label="Back"><i class="icon-left-open"></i></button>
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-sum="{{project-function-deployments.sum}}" class="margin-end round small" aria-label="Back"><i class="icon-left-open"></i></button>
</form>
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{project-function-tags.sum|pageTotal}}"></span>
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{project-function-deployments.sum|pageTotal}}"></span>
<form
data-service="functions.listTags"
data-service="functions.listDeployments"
data-event="submit"
data-param-function-id="{{router.params.id}}"
data-param-search="{{router.params.search}}"
data-param-limit="<?php echo APP_PAGING_LIMIT; ?>"
data-param-order-type="DESC"
data-scope="sdk"
data-name="project-function-tags"
data-name="project-function-deployments"
data-success="state"
data-success-param-state-keys="search,offset">
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-sum="{{project-function-tags.sum}}" class="margin-start round small" aria-label="Next"><i class="icon-right-open"></i></button>
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-sum="{{project-function-deployments.sum}}" class="margin-start round small" aria-label="Next"><i class="icon-right-open"></i></button>
</form>
</div>
</div>
@@ -607,7 +607,7 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
<div data-ui-modal class="modal close box sticky-footer" data-button-hide="on" data-open-event="execute-now">
<button type="button" class="close pull-end" data-ui-modal-close=""><i class="icon-cancel"></i></button>
<h1 class="margin-bottom">Execute Function</h1>
<form data-ls-if="{{project-function.tag}} !== ''" name="functions.createExecution" class="margin-top"
<form data-ls-if="{{project-function.deployment}} !== ''" name="functions.createExecution" class="margin-top"
data-analytics
data-analytics-activity
data-analytics-event="submit"
@@ -629,10 +629,10 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
<button type="submit" style="vertical-align: top;">Execute Now</button>
</form>
</div>
<div data-ui-modal class="modal close box sticky-footer" data-button-hide="on" data-open-event="deploy-tag">
<div data-ui-modal class="modal close box sticky-footer" data-button-hide="on" data-open-event="deploy-deployment">
<button type="button" class="close pull-end" data-ui-modal-close=""><i class="icon-cancel"></i></button>
<h1 class="margin-bottom-xl">Deploy a New Tag</h1>
<h1 class="margin-bottom-xl">Create a New Deployment</h1>
<ul class="phases padding margin-top-negative-small" data-ui-phases>
<li>
@@ -641,7 +641,7 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
<p><b>Unix</b></p>
<div class="margin-bottom">
<textarea type="hidden" data-ls-bind="appwrite functions createTag \
<textarea type="hidden" data-ls-bind="appwrite functions createDeployment \
--functionId={{project-function.$id}} \
--entrypoint='scriptFile' \
--code='/myrepo/myfunction'" data-forms-code="bash" data-lang="bash" data-lang-label="Bash"></textarea>
@@ -650,13 +650,13 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
<p><b>PowerShell</b></p>
<div class="margin-bottom">
<textarea type="hidden" data-ls-bind="appwrite functions createTag `
<textarea type="hidden" data-ls-bind="appwrite functions createDeployment `
--functionId={{project-function.$id}} `
--entrypoint='scriptFile' `
--code='/myrepo/myfunction'" data-forms-code="powershell" data-lang="powershell" data-lang-label="PowerShell"></textarea>
</div>
<p>Learn more about <a href="https://appwrite.io/docs/server/functions#functionsCreateTag" target="_blank">creating tags</a>, installing and using the <a href="https://appwrite.io/docs/command-line" target="_blank">Appwrite CLI</a>.</p>
<p>Learn more about <a href="https://appwrite.io/docs/server/functions#functionsCreateDeployment" target="_blank">creating deployments</a>, installing and using the <a href="https://appwrite.io/docs/command-line" target="_blank">Appwrite CLI</a>.</p>
</li>
<li>
<h2 style="display: none">Manual</h2>
@@ -665,27 +665,27 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
data-analytics-activity
data-analytics-event="submit"
data-analytics-category="console"
data-analytics-label="Create Function Tag"
data-service="functions.createTag"
data-analytics-label="Create Function Deployment"
data-service="functions.createDeployment"
data-scope="sdk"
data-event="submit"
data-success="alert,trigger,reset"
data-success-param-alert-text="Created function tag successfully"
data-success-param-trigger-events="functions.createTag"
data-success-param-alert-text="Created function deployment successfully"
data-success-param-trigger-events="functions.createDeployment"
data-failure="alert"
data-failure-param-alert-text="Failed to create function tag"
data-failure-param-alert-text="Failed to create function deployment"
data-failure-param-alert-classname="error">
<input type="hidden" name="functionId" data-ls-bind="{{router.params.id}}" />
<label for="tag-entrypoint">Entrypoint</label>
<input type="text" id="tag-entrypoint" name="entrypoint" required autocomplete="off" class="margin-bottom" placeholder="main.js" />
<label for="deployment-entrypoint">Entrypoint</label>
<input type="text" id="deployment-entrypoint" name="entrypoint" required autocomplete="off" class="margin-bottom" placeholder="main.js" />
<label for="tag-code">Gzipped Code (tar.gz file)</label>
<input type="file" name="code" id="tag-code" size="1" required accept="application/x-gzip,.gz">
<label for="deployment-code">Gzipped Code (tar.gz file)</label>
<input type="file" name="code" id="deployment-code" size="1" required accept="application/x-gzip,.gz">
<div class="text-fade text-size-xs margin-top-negative-small margin-bottom">(Max file size allowed: <?php echo $fileLimitHuman; ?>)</div>
<label for="tag-deploy" class="margin-bottom-large">Auto Deploy Tag after build <input type="checkbox" class="margin-start-small" id="tag-deploy" name="deploy" /></label>
<label for="deployment-deploy" class="margin-bottom-large">Auto Deploy Deployment after build <input type="checkbox" class="margin-start-small" id="deployment-deploy" name="deploy" /></label>
<footer>
<button type="submit">Create</button> &nbsp; <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
+4 -4
View File
@@ -309,15 +309,15 @@ class DeletesV1 extends Worker
$dbForProject = $this->getProjectDB($projectId);
$device = new Local(APP_STORAGE_FUNCTIONS . '/app-' . $projectId);
// Delete Tags
$this->deleteByGroup('tags', [
// Delete Deployments
$this->deleteByGroup('deployments', [
new Query('functionId', Query::TYPE_EQUAL, [$document->getId()])
], $dbForProject, function (Document $document) use ($device) {
if ($device->delete($document->getAttribute('path', ''))) {
Console::success('Delete code tag: ' . $document->getAttribute('path', ''));
Console::success('Delete code deployment: ' . $document->getAttribute('path', ''));
} else {
Console::error('Failed to delete code tag: ' . $document->getAttribute('path', ''));
Console::error('Failed to delete code deployment: ' . $document->getAttribute('path', ''));
}
});
+3 -3
View File
@@ -84,11 +84,11 @@ class FunctionsV1 extends Worker
foreach ($functions as $function) {
$events = $function->getAttribute('events', []);
$tag = $function->getAttribute('tag', []);
$deployment = $function->getAttribute('deployment', []);
Console::success('Itterating function: ' . $function->getAttribute('name'));
if (!\in_array($event, $events) || empty($tag)) {
if (!\in_array($event, $events) || empty($deployment)) {
continue;
}
@@ -205,7 +205,7 @@ class FunctionsV1 extends Worker
}
/**
* Execute function tag
* Execute function deployment
*
* @param string $trigger
* @param string $projectId