1
0
Fork 0
arangodb/js/actions/_admin/foxx/app.js

406 lines
12 KiB
JavaScript

/* jshint strict: false */
// //////////////////////////////////////////////////////////////////////////////
// / @brief Foxx administration actions
// /
// / @file
// /
// / DISCLAIMER
// /
// / Copyright 2016 ArangoDB GmbH, Cologne, Germany
// /
// / Licensed under the Apache License, Version 2.0 (the "License")
// / you may not use this file except in compliance with the License.
// / You may obtain a copy of the License at
// /
// / http://www.apache.org/licenses/LICENSE-2.0
// /
// / Unless required by applicable law or agreed to in writing, software
// / distributed under the License is distributed on an "AS IS" BASIS,
// / WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// / See the License for the specific language governing permissions and
// / limitations under the License.
// /
// / Copyright holder is ArangoDB GmbH, Cologne, Germany
// /
// / @author Dr. Frank Celler
// / @author Copyright 2014-2016, ArangoDB GmbH, Cologne, Germany
// / @author Copyright 2012, triAGENS GmbH, Cologne, Germany
// //////////////////////////////////////////////////////////////////////////////
const actions = require('@arangodb/actions');
const FoxxManager = require('@arangodb/foxx/manager');
const store = require('@arangodb/foxx/store');
const request = require('@arangodb/request');
const db = require('@arangodb').db;
const ArangoError = require('@arangodb').ArangoError;
const joinPath = require('path').join;
const fs = require('fs');
const fmu = require('@arangodb/foxx/manager-utils');
const easyPostCallback = actions.easyPostCallback;
function proxyLocal (method, url, qs, body, headers = {}) {
url = `/_db/${db._name()}${url}`;
if (body instanceof Buffer) {
if (body.utf8Slice(0, 4) === 'PK\u0003\u0004') {
headers['content-type'] = 'application/zip';
} else {
headers['content-type'] = 'application/javascript';
}
} else if (body && typeof body === 'object') {
headers['content-type'] = 'application/json';
body = JSON.stringify(body);
}
if (body) {
headers['content-length'] = body.length;
}
const req = {
method,
url,
qs,
headers,
body
};
if (require('internal').db._version(true)['maintainer-mode'] === 'true') {
req.timeout = 300;
}
const res = request(req);
if (res.json && res.json.errorNum) {
throw new ArangoError(res.json);
}
res.throw();
return res.body ? JSON.parse(res.body) : null;
}
function resolveAppInfo (appInfo, refresh) {
if (!appInfo || typeof appInfo !== 'string') {
return appInfo;
}
if (/^git:/i.test(appInfo)) {
const splitted = appInfo.split(':');
const baseUrl = process.env.FOXX_BASE_URL || 'https://github.com/';
return {source: `${baseUrl}${splitted[1]}/archive/${splitted[2] || 'master'}.zip`};
}
if (/^https?:/i.test(appInfo)) {
return {source: appInfo};
}
if (/^uploads[/\\]tmp-/.test(appInfo)) {
const tempFile = joinPath(fs.getTempPath(), appInfo);
const buffer = fs.readFileSync(tempFile);
try {
fs.remove(tempFile);
} catch (e) {
console.warnStack(e, `Failed to remove uploaded file: ${tempFile}`);
}
return buffer;
}
if (fs.isDirectory(appInfo)) {
const tempFile = fmu.zipDirectory(appInfo);
const buffer = fs.readFileSync(tempFile);
try {
fs.removeDirectoryRecursive(tempFile);
} catch (e) {
console.warnStack(e, `Failed to remove temporary file: ${tempFile}`);
}
return buffer;
}
if (fs.exists(appInfo)) {
return fs.readFileSync(appInfo);
}
if (refresh !== false) {
try {
store.update();
} catch (e) {
console.warnStack(e);
}
}
return {source: appInfo};
}
// disable foxx manager routes / foxx-cli when foxx api is disabled
if (!require("internal").isFoxxApiDisabled()) {
// //////////////////////////////////////////////////////////////////////////////
// / @brief sets up a Foxx service
// //////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url: '_admin/foxx/setup',
prefix: false,
isSystem: true,
callback: easyPostCallback({
body: true,
callback: function (body, req) {
const mount = body.mount;
return FoxxManager.setup(mount);
}
})
});
// //////////////////////////////////////////////////////////////////////////////
// / @brief tears down a Foxx service
// //////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url: '_admin/foxx/teardown',
prefix: false,
isSystem: true,
callback: easyPostCallback({
body: true,
callback: function (body, req) {
const mount = body.mount;
return FoxxManager.teardown(mount);
}
})
});
// //////////////////////////////////////////////////////////////////////////////
// / @brief installs a Foxx service
// //////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url: '_admin/foxx/install',
prefix: false,
isSystem: true,
callback: easyPostCallback({
body: true,
callback: function (body, req) {
const mount = body.mount;
const options = body.options || {};
const appInfo = resolveAppInfo(body.appInfo, options.refresh);
options.mount = mount;
proxyLocal('POST', '/_api/foxx', options, appInfo, req.headers);
return FoxxManager.lookupService(mount).simpleJSON();
}
})
});
// //////////////////////////////////////////////////////////////////////////////
// / @brief uninstalls a Foxx service
// //////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url: '_admin/foxx/uninstall',
prefix: false,
isSystem: true,
callback: easyPostCallback({
body: true,
callback: function (body, req) {
const mount = body.mount;
const options = body.options || {};
options.mount = mount;
proxyLocal('DELETE', '/_api/foxx/service', options, undefined, req.headers);
return {mount};
}
})
});
// //////////////////////////////////////////////////////////////////////////////
// / @brief replaces a Foxx service
// //////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url: '_admin/foxx/replace',
prefix: false,
isSystem: true,
callback: easyPostCallback({
body: true,
callback: function (body, req) {
const mount = body.mount;
const options = body.options || {};
const appInfo = resolveAppInfo(body.appInfo, options.refresh);
options.mount = mount;
proxyLocal('PUT', '/_api/foxx/service', options, appInfo, req.headers);
return FoxxManager.lookupService(mount).simpleJSON();
}
})
});
// //////////////////////////////////////////////////////////////////////////////
// / @brief upgrades a Foxx service
// //////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url: '_admin/foxx/upgrade',
prefix: false,
isSystem: true,
callback: easyPostCallback({
body: true,
callback: function (body, req) {
const mount = body.mount;
const options = body.options || {};
const appInfo = resolveAppInfo(body.appInfo, options.refresh);
options.mount = mount;
proxyLocal('PATCH', '/_api/foxx/service', options, appInfo, req.headers);
return FoxxManager.lookupService(mount).simpleJSON();
}
})
});
// //////////////////////////////////////////////////////////////////////////////
// / @brief configures a Foxx service
// //////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url: '_admin/foxx/configure',
prefix: false,
isSystem: true,
callback: easyPostCallback({
body: true,
callback: function (body, req) {
const mount = body.mount;
let options = body.options;
if (options && options.configuration) {
options = options.configuration;
}
proxyLocal('PUT', '/_api/foxx/configuration', {mount}, options, req.headers);
return FoxxManager.lookupService(mount).simpleJSON();
}
})
});
// //////////////////////////////////////////////////////////////////////////////
// / @brief Gets the configuration of a Foxx service
// //////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url: '_admin/foxx/configuration',
prefix: false,
isSystem: true,
callback: easyPostCallback({
body: true,
callback: function (body, req) {
const mount = body.mount;
return FoxxManager.configuration(mount);
}
})
});
// //////////////////////////////////////////////////////////////////////////////
// / @brief configures a Foxx service's dependencies
// //////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url: '_admin/foxx/set-dependencies',
prefix: false,
isSystem: true,
callback: easyPostCallback({
body: true,
callback: function (body, req) {
const mount = body.mount;
let options = body.options;
if (options && options.dependencies) {
options = options.dependencies;
}
proxyLocal('PUT', '/_api/foxx/dependencies', {mount}, options, req.headers);
return FoxxManager.lookupService(mount).simpleJSON();
}
})
});
// //////////////////////////////////////////////////////////////////////////////
// / @brief Gets the dependencies of a Foxx service
// //////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url: '_admin/foxx/dependencies',
prefix: false,
isSystem: true,
callback: easyPostCallback({
body: true,
callback: function (body, req) {
const mount = body.mount;
const deps = FoxxManager.dependencies(mount);
for (const key of Object.keys(deps)) {
const dep = deps[key];
deps[key] = {
definition: dep,
title: dep.title,
current: dep.current
};
delete dep.title;
delete dep.current;
}
return deps;
}
})
});
// //////////////////////////////////////////////////////////////////////////////
// / @brief Toggles the development mode of a Foxx service
// //////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url: '_admin/foxx/development',
prefix: false,
isSystem: true,
callback: easyPostCallback({
body: true,
callback: function (body, req) {
const mount = body.mount;
const activate = body.activate;
if (activate) {
return FoxxManager.development(mount).simpleJSON();
} else {
return FoxxManager.production(mount).simpleJSON();
}
}
})
});
// //////////////////////////////////////////////////////////////////////////////
// / @brief Run tests for an app
// //////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url: '_admin/foxx/tests',
prefix: false,
isSystem: true,
callback: easyPostCallback({
body: true,
callback: function (body, req) {
const mount = body.mount;
const options = body.options;
return FoxxManager.runTests(mount, options);
}
})
});
// //////////////////////////////////////////////////////////////////////////////
// / @brief Run script for an app
// //////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url: '_admin/foxx/script',
prefix: false,
isSystem: true,
callback: easyPostCallback({
body: true,
callback: function (body, req) {
const name = body.name;
const mount = body.mount;
const options = body.options;
return FoxxManager.runScript(name, mount, options);
}
})
});
} // end - if not foxx api disabled