1
0
Fork 0

Fix Foxx API (#4614)

This commit is contained in:
Mark 2018-02-20 10:22:27 +01:00 committed by Jan
parent 1c80774091
commit cd97787adf
5 changed files with 75 additions and 9 deletions

View File

@ -1,7 +1,12 @@
devel devel
----- -----
* renamed startup option `--replication.automatic-failover` to * fixed Foxx API:
* PUT /_api/foxx/service: Respect force flag
* PATCH /_api/foxx/service: Check whether a service under given mount exists
* renamed startup option `--replication.automatic-failover` to
`--replication.active-failover` `--replication.active-failover`
using the old option name will still work in ArangoDB 3.4, but the old option using the old option name will still work in ArangoDB 3.4, but the old option
will be removed afterwards will be removed afterwards
@ -12,7 +17,7 @@ devel
inaccurate estimates. The issue is solved now, but there can be up to a second inaccurate estimates. The issue is solved now, but there can be up to a second
or so delay before updates are reflected in the estimates. or so delay before updates are reflected in the estimates.
* support `returnOld` and `returnNew` attributes for in the following HTTP REST * support `returnOld` and `returnNew` attributes for in the following HTTP REST
APIs: APIs:
* /_api/gharial/<graph>/vertex/<collection> * /_api/gharial/<graph>/vertex/<collection>
@ -21,7 +26,7 @@ devel
The exception from this is that the HTTP DELETE verb for these APIs does not The exception from this is that the HTTP DELETE verb for these APIs does not
support `returnOld` because that would make the existing API incompatible support `returnOld` because that would make the existing API incompatible
* fixed issue #4160: Run arangod with "--database.auto-upgrade" option always crash * fixed issue #4160: Run arangod with "--database.auto-upgrade" option always crash
silently without error log silently without error log
* fix issue #4457: create /var/tmp/arangod with correct user in supervisor mode * fix issue #4457: create /var/tmp/arangod with correct user in supervisor mode

View File

@ -53,6 +53,9 @@ Set to `false` to not run the new service's setup script.
@RESTQUERYPARAM{legacy,boolean,optional} @RESTQUERYPARAM{legacy,boolean,optional}
Set to `true` to install the new service in 2.8 legacy compatibility mode. Set to `true` to install the new service in 2.8 legacy compatibility mode.
@RESTQUERYPARAM{force,boolean,optional}
Set to `true` to force service install even if no service is installed under given mount.
@RESTRETURNCODES @RESTRETURNCODES
@RESTRETURNCODE{200} @RESTRETURNCODE{200}

View File

@ -199,6 +199,7 @@ serviceRouter.put(prepareServiceRequestBody, (req, res) => {
.queryParam('teardown', schemas.flag.default(true)) .queryParam('teardown', schemas.flag.default(true))
.queryParam('setup', schemas.flag.default(true)) .queryParam('setup', schemas.flag.default(true))
.queryParam('legacy', schemas.flag.default(false)) .queryParam('legacy', schemas.flag.default(false))
.queryParam('force', schemas.flag.default(false))
.response(200, schemas.fullInfo); .response(200, schemas.fullInfo);
serviceRouter.delete((req, res) => { serviceRouter.delete((req, res) => {

View File

@ -1288,8 +1288,8 @@ describe('Foxx service', () => {
const routes = [ const routes = [
['GET', '/_api/foxx/service'], ['GET', '/_api/foxx/service'],
['PATCH', '/_api/foxx/service'], ['PATCH', '/_api/foxx/service', { source: servicePath }],
['PUT', '/_api/foxx/service'], ['PUT', '/_api/foxx/service', { source: servicePath }],
['DELETE', '/_api/foxx/service'], ['DELETE', '/_api/foxx/service'],
['GET', '/_api/foxx/configuration'], ['GET', '/_api/foxx/configuration'],
['PATCH', '/_api/foxx/configuration'], ['PATCH', '/_api/foxx/configuration'],
@ -1306,20 +1306,22 @@ describe('Foxx service', () => {
['GET', '/_api/foxx/readme'], ['GET', '/_api/foxx/readme'],
['GET', '/_api/foxx/swagger'] ['GET', '/_api/foxx/swagger']
]; ];
for (const [method, url] of routes) { for (const [method, url, body] of routes) {
it(`should return 400 when mount is omitted for ${method} ${url}`, () => { it(`should return 400 when mount is omitted for ${method} ${url}`, () => {
const resp = request({ const resp = request({
method, method,
url, url,
body,
json: true json: true
}); });
expect(resp.status).to.equal(400); expect(resp.status).to.equal(400);
}); });
it(`should return 400 when mount is invalid for ${method} ${url}`, () => { it(`should return 400 when mount is unknown for ${method} ${url}`, () => {
const resp = request({ const resp = request({
method, method,
url, url,
qs: {mount: '/dev/null'}, qs: {mount: '/dev/null'},
body,
json: true json: true
}); });
expect(resp.status).to.equal(400); expect(resp.status).to.equal(400);
@ -1337,4 +1339,36 @@ describe('Foxx service', () => {
expect(resp.json).to.have.property('failures'); expect(resp.json).to.have.property('failures');
expect(resp.json).to.have.property('passes'); expect(resp.json).to.have.property('passes');
}); });
it('replace on invalid mount should not be installed', () => {
const replaceResp = request.put('/_api/foxx/service', {
qs: {
mount
},
body: {
source: servicePath
},
json: true
});
expect(replaceResp.status).to.equal(400);
const resp = request.get(mount);
expect(resp.status).to.equal(404);
});
it('replace on invalid mount should be installed when forced', () => {
const replaceResp = request.put('/_api/foxx/service', {
qs: {
mount,
force: true
},
body: {
source: servicePath
},
json: true
});
expect(replaceResp.status).to.equal(200);
const resp = request.get(mount);
expect(resp.status).to.equal(200);
expect(resp.json).to.eql({hello: 'world'});
});
}); });

View File

@ -860,8 +860,21 @@ function uninstall (mount, options = {}) {
} }
function replace (serviceInfo, mount, options = {}) { function replace (serviceInfo, mount, options = {}) {
utils.validateMount(mount);
ensureFoxxInitialized(); ensureFoxxInitialized();
if (!options.force) {
const serviceDefinition = utils.getServiceDefinition(mount);
if (!serviceDefinition) {
throw new ArangoError({
errorNum: errors.ERROR_SERVICE_NOT_FOUND.code,
errorMessage: dd`
${errors.ERROR_SERVICE_NOT_FOUND.message}
Mount path: "${mount}".
`
});
}
} else {
utils.validateMount(mount);
}
const tempPaths = _prepareService(serviceInfo, options); const tempPaths = _prepareService(serviceInfo, options);
FoxxService.validatedManifest({ FoxxService.validatedManifest({
mount, mount,
@ -877,7 +890,17 @@ function replace (serviceInfo, mount, options = {}) {
function upgrade (serviceInfo, mount, options = {}) { function upgrade (serviceInfo, mount, options = {}) {
ensureFoxxInitialized(); ensureFoxxInitialized();
const serviceOptions = utils.getServiceDefinition(mount).options; const serviceDefinition = utils.getServiceDefinition(mount);
if (!serviceDefinition) {
throw new ArangoError({
errorNum: errors.ERROR_SERVICE_NOT_FOUND.code,
errorMessage: dd`
${errors.ERROR_SERVICE_NOT_FOUND.message}
Mount path: "${mount}".
`
});
}
const serviceOptions = serviceDefinition.options;
Object.assign(serviceOptions.configuration, options.configuration); Object.assign(serviceOptions.configuration, options.configuration);
Object.assign(serviceOptions.dependencies, options.dependencies); Object.assign(serviceOptions.dependencies, options.dependencies);
serviceOptions.development = options.development; serviceOptions.development = options.development;