mirror of
https://github.com/yldio/copilot.git
synced 2024-11-28 14:10:04 +02:00
add portal-api
This commit is contained in:
parent
4e73cc4ea6
commit
d5ecdd1cbc
3
portal-api/.gitignore
vendored
Normal file
3
portal-api/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
.DS_Store
|
||||
npm-debug.log
|
8
portal-api/.travis.yml
Normal file
8
portal-api/.travis.yml
Normal file
@ -0,0 +1,8 @@
|
||||
language: node_js
|
||||
|
||||
node_js:
|
||||
- "6"
|
||||
- "7"
|
||||
- "node"
|
||||
|
||||
sudo: false
|
362
portal-api/LICENSE
Normal file
362
portal-api/LICENSE
Normal file
@ -0,0 +1,362 @@
|
||||
Mozilla Public License, version 2.0
|
||||
|
||||
1. Definitions
|
||||
|
||||
1.1. "Contributor"
|
||||
|
||||
means each individual or legal entity that creates, contributes to the
|
||||
creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
|
||||
means the combination of the Contributions of others (if any) used by a
|
||||
Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
|
||||
means Source Code Form to which the initial Contributor has attached the
|
||||
notice in Exhibit A, the Executable Form of such Source Code Form, and
|
||||
Modifications of such Source Code Form, in each case including portions
|
||||
thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
a. that the initial Contributor has attached the notice described in
|
||||
Exhibit B to the Covered Software; or
|
||||
|
||||
b. that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the terms of
|
||||
a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
|
||||
means a work that combines Covered Software with other material, in a
|
||||
separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
|
||||
means having the right to grant, to the maximum extent possible, whether
|
||||
at the time of the initial grant or subsequently, any and all of the
|
||||
rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
|
||||
means any of the following:
|
||||
|
||||
a. any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered Software; or
|
||||
|
||||
b. any new file in Source Code Form that contains any Covered Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the License,
|
||||
by the making, using, selling, offering for sale, having made, import,
|
||||
or transfer of either its Contributions or its Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
|
||||
means either the GNU General Public License, Version 2.0, the GNU Lesser
|
||||
General Public License, Version 2.1, the GNU Affero General Public
|
||||
License, Version 3.0, or any later versions of those licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that controls, is
|
||||
controlled by, or is under common control with You. For purposes of this
|
||||
definition, "control" means (a) the power, direct or indirect, to cause
|
||||
the direction or management of such entity, whether by contract or
|
||||
otherwise, or (b) ownership of more than fifty percent (50%) of the
|
||||
outstanding shares or beneficial ownership of such entity.
|
||||
|
||||
|
||||
2. License Grants and Conditions
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
a. under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
b. under Patent Claims of such Contributor to make, use, sell, offer for
|
||||
sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
a. for any code that a Contributor has removed from Covered Software; or
|
||||
|
||||
b. for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
c. under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights to
|
||||
grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
|
||||
Section 2.1.
|
||||
|
||||
|
||||
3. Responsibilities
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
a. such Covered Software must also be made available in Source Code Form,
|
||||
as described in Section 3.1, and You must inform recipients of the
|
||||
Executable Form how they can obtain a copy of such Source Code Form by
|
||||
reasonable means in a timely manner, at a charge no more than the cost
|
||||
of distribution to the recipient; and
|
||||
|
||||
b. You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter the
|
||||
recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty, or
|
||||
limitations of liability) contained within the Source Code Form of the
|
||||
Covered Software, except that You may alter any license notices to the
|
||||
extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this License
|
||||
with respect to some or all of the Covered Software due to statute,
|
||||
judicial order, or regulation then You must: (a) comply with the terms of
|
||||
this License to the maximum extent possible; and (b) describe the
|
||||
limitations and the code they affect. Such description must be placed in a
|
||||
text file included with all distributions of the Covered Software under
|
||||
this License. Except to the extent prohibited by statute or regulation,
|
||||
such description must be sufficiently detailed for a recipient of ordinary
|
||||
skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically if You
|
||||
fail to comply with any of its terms. However, if You become compliant,
|
||||
then the rights granted under this License from a particular Contributor
|
||||
are reinstated (a) provisionally, unless and until such Contributor
|
||||
explicitly and finally terminates Your grants, and (b) on an ongoing
|
||||
basis, if such Contributor fails to notify You of the non-compliance by
|
||||
some reasonable means prior to 60 days after You have come back into
|
||||
compliance. Moreover, Your grants from a particular Contributor are
|
||||
reinstated on an ongoing basis if such Contributor notifies You of the
|
||||
non-compliance by some reasonable means, this is the first time You have
|
||||
received notice of non-compliance with this License from such
|
||||
Contributor, and You become compliant prior to 30 days after Your receipt
|
||||
of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
|
||||
license agreements (excluding distributors and resellers) which have been
|
||||
validly granted by You or Your distributors under this License prior to
|
||||
termination shall survive termination.
|
||||
|
||||
6. Disclaimer of Warranty
|
||||
|
||||
Covered Software is provided under this License on an "as is" basis,
|
||||
without warranty of any kind, either expressed, implied, or statutory,
|
||||
including, without limitation, warranties that the Covered Software is free
|
||||
of defects, merchantable, fit for a particular purpose or non-infringing.
|
||||
The entire risk as to the quality and performance of the Covered Software
|
||||
is with You. Should any Covered Software prove defective in any respect,
|
||||
You (not any Contributor) assume the cost of any necessary servicing,
|
||||
repair, or correction. This disclaimer of warranty constitutes an essential
|
||||
part of this License. No use of any Covered Software is authorized under
|
||||
this License except under this disclaimer.
|
||||
|
||||
7. Limitation of Liability
|
||||
|
||||
Under no circumstances and under no legal theory, whether tort (including
|
||||
negligence), contract, or otherwise, shall any Contributor, or anyone who
|
||||
distributes Covered Software as permitted above, be liable to You for any
|
||||
direct, indirect, special, incidental, or consequential damages of any
|
||||
character including, without limitation, damages for lost profits, loss of
|
||||
goodwill, work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses, even if such party shall have been
|
||||
informed of the possibility of such damages. This limitation of liability
|
||||
shall not apply to liability for death or personal injury resulting from
|
||||
such party's negligence to the extent applicable law prohibits such
|
||||
limitation. Some jurisdictions do not allow the exclusion or limitation of
|
||||
incidental or consequential damages, so this exclusion and limitation may
|
||||
not apply to You.
|
||||
|
||||
8. Litigation
|
||||
|
||||
Any litigation relating to this License may be brought only in the courts
|
||||
of a jurisdiction where the defendant maintains its principal place of
|
||||
business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions. Nothing
|
||||
in this Section shall prevent a party's ability to bring cross-claims or
|
||||
counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides that
|
||||
the language of a contract shall be construed against the drafter shall not
|
||||
be used to construe this License against a Contributor.
|
||||
|
||||
|
||||
10. Versions of the License
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses If You choose to distribute Source Code Form that is
|
||||
Incompatible With Secondary Licenses under the terms of this version of
|
||||
the License, the notice described in Exhibit B of this License must be
|
||||
attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular file,
|
||||
then You may include the notice in a location (such as a LICENSE file in a
|
||||
relevant directory) where a recipient would be likely to look for such a
|
||||
notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
|
||||
This Source Code Form is "Incompatible
|
||||
With Secondary Licenses", as defined by
|
||||
the Mozilla Public License, v. 2.0.
|
14
portal-api/README.md
Normal file
14
portal-api/README.md
Normal file
@ -0,0 +1,14 @@
|
||||
ContainerPilot Monitor API
|
||||
|
||||
[![Build Status](https://secure.travis-ci.org/geek/portal-api.svg)](http://travis-ci.org/geek/portal-api)
|
||||
|
||||
Lead Maintainer: [Wyatt Preul](https://github.com/geek)
|
||||
|
||||
|
||||
## Example usage
|
||||
|
||||
```
|
||||
NODE_ENV=dev node example
|
||||
```
|
||||
|
||||
Navigate to http://localhost:8000/graphiql to run graphQL queries. Navigate to http://localhost:8000/documentation for documentation on each route.
|
42
portal-api/example.js
Normal file
42
portal-api/example.js
Normal file
@ -0,0 +1,42 @@
|
||||
'use strict';
|
||||
|
||||
const Hapi = require('hapi');
|
||||
const Inert = require('inert');
|
||||
const Vision = require('vision');
|
||||
const HapiSwagger = require('hapi-swagger');
|
||||
const Pack = require('./package');
|
||||
const Portal = require('./lib');
|
||||
|
||||
const server = new Hapi.Server();
|
||||
server.connection({ port: 8000 });
|
||||
|
||||
const options = {
|
||||
info: {
|
||||
'title': 'Portal API Documentation',
|
||||
'version': Pack.version
|
||||
}
|
||||
};
|
||||
|
||||
server.register([
|
||||
Inert,
|
||||
Vision,
|
||||
Portal,
|
||||
{
|
||||
register: HapiSwagger,
|
||||
options
|
||||
}],
|
||||
(err) => {
|
||||
handlerError(err);
|
||||
server.start((err) => {
|
||||
handlerError(err);
|
||||
console.log(`server started at http://localhost:${server.info.port}`);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
function handlerError (error) {
|
||||
if (error) {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
86
portal-api/lib/data.js
Normal file
86
portal-api/lib/data.js
Normal file
@ -0,0 +1,86 @@
|
||||
'use strict';
|
||||
|
||||
const Examples = require('./models/examples');
|
||||
|
||||
|
||||
module.exports = class Data {
|
||||
constructor (options) {
|
||||
this._options = options;
|
||||
}
|
||||
|
||||
createDeployment (deployment) {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve(Examples.deployment);
|
||||
});
|
||||
}
|
||||
getDeployment (id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve(Examples.deployment);
|
||||
});
|
||||
}
|
||||
updateDeployment (deployment) {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve(Examples.deployment);
|
||||
});
|
||||
}
|
||||
deleteDeployment (id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
getDeployments () {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve(Examples.deployments);
|
||||
});
|
||||
}
|
||||
|
||||
getDatacenters () {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve(Examples.datacenters);
|
||||
});
|
||||
}
|
||||
|
||||
createManifest (deploymentId, manifest) {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve(Examples.manifest);
|
||||
});
|
||||
}
|
||||
getManifest (deploymentId, revision) {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve(Examples.manifest);
|
||||
});
|
||||
}
|
||||
|
||||
getActivities (deploymentId) {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve(Examples.activities);
|
||||
});
|
||||
}
|
||||
getMetrics (deploymentId) {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve(Examples.metrics);
|
||||
});
|
||||
}
|
||||
|
||||
getState (deploymentId) {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve(Examples.state);
|
||||
});
|
||||
}
|
||||
updateState (deploymentId, action) {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve(Examples.state);
|
||||
});
|
||||
}
|
||||
|
||||
getServices (deploymentId) {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve(Examples.services);
|
||||
});
|
||||
}
|
||||
updateService (deploymentId, service) {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve(Examples.service);
|
||||
});
|
||||
}
|
||||
};
|
93
portal-api/lib/handlers.js
Normal file
93
portal-api/lib/handlers.js
Normal file
@ -0,0 +1,93 @@
|
||||
'use strict';
|
||||
|
||||
// Deployments
|
||||
|
||||
exports.deploymentCreate = function (request, reply) {
|
||||
const deploymentRoute = request.server.lookup('deploymentGet');
|
||||
|
||||
this.createDeployment(request.payload).then((deployment) => {
|
||||
reply(deployment).created(deploymentRoute.path.replace('{deployment}', deployment.id));
|
||||
}).catch((error) => {
|
||||
reply(error);
|
||||
});
|
||||
};
|
||||
|
||||
exports.deploymentGet = function (request, reply) {
|
||||
reply(this.getDeployment(request.deploymentId));
|
||||
};
|
||||
|
||||
exports.deploymentUpdate = function (request, reply) {
|
||||
const payload = request.payload;
|
||||
payload.id = request.deploymentId;
|
||||
|
||||
reply(this.updateDeployment(payload));
|
||||
};
|
||||
|
||||
exports.deploymentDelete = function (request, reply) {
|
||||
reply(this.deleteDeployment(request.deploymentId));
|
||||
};
|
||||
|
||||
exports.deploymentsGet = function (request, reply) {
|
||||
reply(this.getDeployments());
|
||||
};
|
||||
|
||||
|
||||
// Datacenters
|
||||
|
||||
exports.datacentersGet = function (request, reply) {
|
||||
reply(this.getDatacenters());
|
||||
};
|
||||
|
||||
|
||||
// Manifests
|
||||
|
||||
exports.manifestCreate = function (request, reply) {
|
||||
const manifestRoute = request.server.lookup('manifestGet');
|
||||
const deploymentId = request.params.deploymentId;
|
||||
|
||||
this.createManifest(deploymentId, request.payload).then((manifest) => {
|
||||
reply(manifest).created(manifestRoute.path.replace('{deployment}', deploymentId).replace('{revision}', manifest.revision));
|
||||
}).catch((error) => {
|
||||
reply(error);
|
||||
});
|
||||
};
|
||||
|
||||
exports.manifestGet = function (request, reply) {
|
||||
reply(this.getManifest(request.params.deploymentId, request.params.revision));
|
||||
};
|
||||
|
||||
|
||||
// Activities and Metrics
|
||||
|
||||
exports.activitiesGet = function (request, reply) {
|
||||
reply(this.getActivities(request.params.deploymentId));
|
||||
};
|
||||
|
||||
exports.metricsGet = function (request, reply) {
|
||||
reply(this.getMetrics(request.params.deploymentId));
|
||||
};
|
||||
|
||||
|
||||
// Deployment Group State
|
||||
|
||||
exports.stateGet = function (request, reply) {
|
||||
reply(this.getState(request.params.deploymentId));
|
||||
};
|
||||
|
||||
exports.stateUpdate = function (request, reply) {
|
||||
reply(this.updateState(request.params.deploymentId, request.payload.action));
|
||||
};
|
||||
|
||||
|
||||
// Services
|
||||
|
||||
exports.servicesGet = function (request, reply) {
|
||||
reply(this.getServices(request.params.deploymentId));
|
||||
};
|
||||
|
||||
exports.serviceUpdate = function (request, reply) {
|
||||
const service = request.payload;
|
||||
service.name = request.params.name;
|
||||
|
||||
reply(this.updateService(request.params.deploymentId, service));
|
||||
};
|
51
portal-api/lib/index.js
Normal file
51
portal-api/lib/index.js
Normal file
@ -0,0 +1,51 @@
|
||||
'use strict';
|
||||
|
||||
const GraphqlHapi = require('graphql-server-hapi');
|
||||
const Data = require('./data');
|
||||
const Graphql = require('./models/graphql');
|
||||
const Pack = require('../package.json');
|
||||
const Routes = require('./routes');
|
||||
|
||||
|
||||
module.exports = function (server, options, next) {
|
||||
const data = new Data(options.data);
|
||||
server.bind(data);
|
||||
|
||||
|
||||
server.register([
|
||||
{
|
||||
register: GraphqlHapi.graphqlHapi,
|
||||
options: {
|
||||
path: '/graphql',
|
||||
graphqlOptions: Graphql.options(data),
|
||||
route: {
|
||||
cors: true
|
||||
}
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
if (process.env.NODE_ENV === 'dev') {
|
||||
server.register({
|
||||
register: GraphqlHapi.graphiqlHapi,
|
||||
options: {
|
||||
path: '/graphiql',
|
||||
graphiqlOptions: Graphql.options(data),
|
||||
route: {
|
||||
cors: true
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
server.route(Routes);
|
||||
|
||||
next();
|
||||
};
|
||||
|
||||
module.exports.attributes = {
|
||||
name: Pack.name,
|
||||
version: Pack.version,
|
||||
once: true,
|
||||
multiple: false
|
||||
};
|
96
portal-api/lib/models/examples.js
Normal file
96
portal-api/lib/models/examples.js
Normal file
@ -0,0 +1,96 @@
|
||||
'use strict';
|
||||
|
||||
|
||||
exports.activities = [
|
||||
{
|
||||
date: Date.now(),
|
||||
type: 'start',
|
||||
meta: {
|
||||
user: 'Tom'
|
||||
}
|
||||
},
|
||||
{
|
||||
date: Date.now(),
|
||||
type: 'stop',
|
||||
meta: {
|
||||
user: 'Dave'
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
exports.datacenters = [
|
||||
{ name: 'us-sw-1', url: 'https://us-sw-1.api.joyentcloud.com' },
|
||||
{ name: 'us-west-1', url: 'https://us-west-1.api.joyentcloud.com' }
|
||||
];
|
||||
|
||||
|
||||
exports.deployments = [{
|
||||
id: 42,
|
||||
name: 'User Services',
|
||||
datacenter: 'us-sw-1'
|
||||
}];
|
||||
|
||||
exports.deployment = exports.deployments[0];
|
||||
|
||||
|
||||
exports.manifest = {
|
||||
revision: 5,
|
||||
file: {
|
||||
consul: {
|
||||
image: 'autopilotpattern/consul:0.7.2-r0.8',
|
||||
restart: 'always',
|
||||
dns: ['127.0.0.1'],
|
||||
labels: ['triton.cns.services=consul'],
|
||||
ports: ['8500:8500'],
|
||||
command: `>
|
||||
/usr/local/bin/containerpilot
|
||||
/bin/consul agent -server
|
||||
-config-dir=/etc/consul
|
||||
-log-level=err
|
||||
-bootstrap-expect 1
|
||||
-ui-dir /ui`
|
||||
},
|
||||
prometheus: {
|
||||
image: 'autopilotpattern/prometheus:1.3.0r1.0',
|
||||
mem_limit: '128m',
|
||||
restart: 'always',
|
||||
ports: ['9090:9090']
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
exports.metrics = [
|
||||
{
|
||||
service: 'consul',
|
||||
cpu: 1.2,
|
||||
memory: 23344523,
|
||||
network: 5024
|
||||
},
|
||||
{
|
||||
service: 'prometheus',
|
||||
cpu: 24.2,
|
||||
memory: 514234453,
|
||||
network: 10024
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
exports.services = [
|
||||
{
|
||||
name: 'consul',
|
||||
count: 3
|
||||
},
|
||||
{
|
||||
name: 'prometheus',
|
||||
count: 1
|
||||
}
|
||||
];
|
||||
|
||||
exports.service = exports.services[0];
|
||||
|
||||
|
||||
exports.state = {
|
||||
current: 'started'
|
||||
};
|
155
portal-api/lib/models/graphql.js
Normal file
155
portal-api/lib/models/graphql.js
Normal file
@ -0,0 +1,155 @@
|
||||
'use strict';
|
||||
|
||||
const Graphql = require('graphql');
|
||||
|
||||
|
||||
const internals = {
|
||||
schema: `
|
||||
scalar Object
|
||||
scalar Date
|
||||
|
||||
type Activity {
|
||||
date: Date!
|
||||
type: String!
|
||||
meta: Object
|
||||
}
|
||||
|
||||
type Datacenter {
|
||||
name: String!
|
||||
url: String!
|
||||
}
|
||||
|
||||
input DeploymentCreate {
|
||||
name: String!
|
||||
datacenter: String!
|
||||
}
|
||||
|
||||
input DeploymentUpdate {
|
||||
id: ID!
|
||||
name: String!
|
||||
datacenter: String!
|
||||
}
|
||||
|
||||
type Deployment {
|
||||
id: ID!
|
||||
name: String!
|
||||
datacenter: String!
|
||||
}
|
||||
|
||||
type Manifest {
|
||||
revision: Int!
|
||||
file: Object!
|
||||
}
|
||||
|
||||
input ManifestCreate {
|
||||
file: Object!
|
||||
}
|
||||
|
||||
type Metric {
|
||||
service: String!
|
||||
cpu: Float!
|
||||
memory: Float!
|
||||
network: Float!
|
||||
}
|
||||
|
||||
type Service {
|
||||
name: String!
|
||||
count: Int!
|
||||
}
|
||||
|
||||
input ServiceUpdate {
|
||||
name: String!
|
||||
count: Int!
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
createDeployment(deployment: DeploymentCreate!): Deployment!
|
||||
deleteDeployment(deploymentId: ID!): String
|
||||
updateDeployment(deployment: DeploymentUpdate!): Deployment!
|
||||
createManifest(deploymentId: ID!, manifest: ManifestCreate!): Manifest!
|
||||
updateService(deploymentId: ID!, service: ServiceUpdate!): Service!
|
||||
}
|
||||
|
||||
type Query {
|
||||
getActivities: [Activity]
|
||||
getDatacenters: [Datacenter]
|
||||
getDeployment(id: ID!): Deployment
|
||||
getDeployments: [Deployment]
|
||||
getManifest(deploymentId: ID!, revision: Int!): Manifest
|
||||
getMetrics(deploymentId: ID!): [Metric]
|
||||
getServices(deploymentId: ID!): [Service]
|
||||
}
|
||||
`
|
||||
};
|
||||
|
||||
|
||||
exports.options = (data) => {
|
||||
const schema = Graphql.buildSchema(internals.schema);
|
||||
|
||||
const createDeployment = function (args) {
|
||||
return data.createDeployment(args.deployment);
|
||||
};
|
||||
|
||||
const deleteDeployment = function (args) {
|
||||
return data.deleteDeployment(args.deploymentId);
|
||||
};
|
||||
|
||||
const updateDeployment = function (args) {
|
||||
return data.updateDeployment(args.deployment);
|
||||
};
|
||||
|
||||
const createManifest = function (args) {
|
||||
return data.createManifest(args.deploymentId, args.manifest);
|
||||
};
|
||||
|
||||
const updateService = function (args) {
|
||||
return data.updateService(args.deploymentId, args.service);
|
||||
};
|
||||
|
||||
const getActivities = function () {
|
||||
return data.getActivities();
|
||||
};
|
||||
|
||||
const getDatacenters = function () {
|
||||
return data.getDatacenters();
|
||||
};
|
||||
|
||||
const getDeployment = function (args) {
|
||||
return data.getDeployment(args.id);
|
||||
};
|
||||
|
||||
const getDeployments = function () {
|
||||
return data.getDeployments();
|
||||
};
|
||||
|
||||
const getManifest = function (args) {
|
||||
return data.getManifest(args.deploymentId, args.revision);
|
||||
};
|
||||
|
||||
const getMetrics = function (args) {
|
||||
return data.getMetrics(args.deploymentId);
|
||||
};
|
||||
|
||||
const getServices = function (args) {
|
||||
return data.v(args.deploymentId);
|
||||
};
|
||||
|
||||
return {
|
||||
schema,
|
||||
endpointURL: '/graphql',
|
||||
rootValue: {
|
||||
createDeployment,
|
||||
deleteDeployment,
|
||||
updateDeployment,
|
||||
createManifest,
|
||||
updateService,
|
||||
getActivities,
|
||||
getDatacenters,
|
||||
getDeployment,
|
||||
getDeployments,
|
||||
getManifest,
|
||||
getMetrics,
|
||||
getServices
|
||||
}
|
||||
};
|
||||
};
|
109
portal-api/lib/models/index.js
Normal file
109
portal-api/lib/models/index.js
Normal file
@ -0,0 +1,109 @@
|
||||
'use strict';
|
||||
|
||||
const Joi = require('joi');
|
||||
const Examples = require('./examples');
|
||||
|
||||
|
||||
// Shared schema between schema sections
|
||||
|
||||
const internals = {
|
||||
serviceName: Joi.string().required().description('Unique name to identify the service')
|
||||
};
|
||||
|
||||
|
||||
// Activity
|
||||
|
||||
exports.activity = Joi.object({
|
||||
date: Joi.date().required().description('Date/time when the activity occurred'),
|
||||
type: Joi.string().required().description('The type of activity that occurred'),
|
||||
meta: Joi.object().optional().description('Any metadata related to the activity')
|
||||
}).example(Examples.activities[0]);
|
||||
|
||||
exports.activities = Joi.array().items(exports.activity).example(Examples.activities);
|
||||
|
||||
|
||||
// Datacenters
|
||||
|
||||
exports.datacenter = Joi.object({
|
||||
name: Joi.string().required().description('Name of datacenter'),
|
||||
url: Joi.string().required().description('URL of datacenter')
|
||||
}).example(Examples.datacenters[0]);
|
||||
|
||||
exports.datacenters = Joi.array().items(exports.datacenter).example(Examples.datacenters);
|
||||
|
||||
|
||||
// Deployments
|
||||
|
||||
exports.deploymentId = Joi.number().required().description('ID of deployment group');
|
||||
|
||||
exports.deploymentCreate = Joi.object({
|
||||
name: Joi.string().required().description('Name of deployment group'),
|
||||
datacenter: Joi.string().required().description('Datacenter the deployment group belongs to')
|
||||
});
|
||||
|
||||
exports.deploymentUpdate = Joi.object({
|
||||
name: Joi.string().optional().description('Name of deployment group'),
|
||||
datacenter: Joi.string().optional().description('Datacenter the deployment group belongs to')
|
||||
}).or('name', 'datacenter');
|
||||
|
||||
exports.deployment = exports.deploymentCreate.keys({
|
||||
id: exports.deploymentId
|
||||
}).example(Examples.deployments[0]);
|
||||
|
||||
exports.deployments = Joi.array().items(exports.deployment);
|
||||
|
||||
|
||||
// Manifests
|
||||
|
||||
exports.manifestRevision = Joi.number().required().description('Revision number of manifest').example(Examples.manifest.revision);
|
||||
|
||||
exports.manifestCreate = Joi.object({
|
||||
file: Joi.object().required().description('Manifest file represented as JSON').example(Examples.manifest.file)
|
||||
});
|
||||
|
||||
exports.manifest = exports.manifestCreate.keys({
|
||||
revision: exports.manifestRevision
|
||||
}).example(Examples.manifest);
|
||||
|
||||
|
||||
// Metrics
|
||||
|
||||
exports.metric = Joi.object({
|
||||
service: internals.serviceName,
|
||||
cpu: Joi.number().required().description('CPU usage percentage'),
|
||||
memory: Joi.number().required().description('Total memory usage in bytes'),
|
||||
network: Joi.number().required().description('Total bytes per second transferred by the NIC')
|
||||
}).example(Examples.metrics[0]);
|
||||
|
||||
exports.metrics = Joi.array().items(exports.metric).example(Examples.metrics);
|
||||
|
||||
|
||||
// Services
|
||||
|
||||
exports.serviceName = internals.serviceName;
|
||||
|
||||
exports.serviceCount = Joi.number().default(1).description('Number of instances of the service');
|
||||
|
||||
exports.service = Joi.object({
|
||||
name: internals.serviceName,
|
||||
count: exports.serviceCount
|
||||
}).example(Examples.services[0]);
|
||||
|
||||
exports.services = Joi.array().items(exports.service).example(Examples.services);
|
||||
|
||||
exports.serviceUpdate = Joi.object({
|
||||
count: exports.serviceCount.required()
|
||||
});
|
||||
|
||||
|
||||
// State
|
||||
|
||||
exports.stateAction = Joi.object({
|
||||
action: Joi.string().required().valid(['start', 'stop', 'restart'])
|
||||
.description('Action being performed on the deployment group')
|
||||
});
|
||||
|
||||
exports.state = Joi.object({
|
||||
current: Joi.string().required().valid(['started', 'stopped'])
|
||||
.description('The current state of the deployment group')
|
||||
});
|
259
portal-api/lib/routes.js
Normal file
259
portal-api/lib/routes.js
Normal file
@ -0,0 +1,259 @@
|
||||
'use strict';
|
||||
|
||||
const Handlers = require('./handlers');
|
||||
const Models = require('./models');
|
||||
|
||||
|
||||
module.exports = [
|
||||
{
|
||||
path: '/deployment',
|
||||
method: 'post',
|
||||
config: {
|
||||
tags: ['api', 'deployment'],
|
||||
description: 'Create new deployment group',
|
||||
validate: {
|
||||
payload: Models.deploymentCreate
|
||||
},
|
||||
response: {
|
||||
schema: Models.deployment
|
||||
},
|
||||
handler: Handlers.deploymentCreate,
|
||||
plugins: {
|
||||
'hapi-swagger': {
|
||||
responses: {
|
||||
'201': {
|
||||
description: 'Deployment group created',
|
||||
schema: Models.deployment
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/deployment/{deploymentId}',
|
||||
method: 'get',
|
||||
config: {
|
||||
id: 'deploymentGet',
|
||||
tags: ['api', 'deployment'],
|
||||
description: 'Retrieve a deployment group',
|
||||
validate: {
|
||||
params: {
|
||||
deploymentId: Models.deploymentId
|
||||
}
|
||||
},
|
||||
response: {
|
||||
schema: Models.deployment
|
||||
},
|
||||
handler: Handlers.deploymentGet
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/deployment/{deploymentId}',
|
||||
method: 'put',
|
||||
config: {
|
||||
tags: ['api', 'deployment'],
|
||||
description: 'Update a deployment group',
|
||||
validate: {
|
||||
params: {
|
||||
deploymentId: Models.deploymentId
|
||||
},
|
||||
payload: Models.deploymentUpdate
|
||||
},
|
||||
response: {
|
||||
schema: Models.deployment
|
||||
},
|
||||
handler: Handlers.deploymentUpdate
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/deployment/{deploymentId}',
|
||||
method: 'delete',
|
||||
config: {
|
||||
tags: ['api', 'deployment'],
|
||||
description: 'Delete a deployment group',
|
||||
validate: {
|
||||
params: {
|
||||
deploymentId: Models.deploymentId
|
||||
}
|
||||
},
|
||||
handler: Handlers.deploymentDelete
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/deployments',
|
||||
method: 'get',
|
||||
config: {
|
||||
tags: ['api', 'deployment'],
|
||||
description: 'Retrieve a list of deployment groups',
|
||||
response: {
|
||||
schema: Models.deployments
|
||||
},
|
||||
handler: Handlers.deploymentsGet
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/datacenters',
|
||||
method: 'get',
|
||||
config: {
|
||||
tags: ['api', 'datacenter'],
|
||||
description: 'Retrieve a list of available datacenters',
|
||||
response: {
|
||||
schema: Models.datacenters
|
||||
},
|
||||
handler: Handlers.datacentersGet
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/deployment/{deploymentId}/manifest',
|
||||
method: 'post',
|
||||
config: {
|
||||
tags: ['api', 'deployment', 'manifest'],
|
||||
description: 'Create a new manifest revision for a deployment group',
|
||||
validate: {
|
||||
params: {
|
||||
deploymentId: Models.deploymentId
|
||||
},
|
||||
payload: Models.manifestCreate
|
||||
},
|
||||
response: {
|
||||
schema: Models.manifest
|
||||
},
|
||||
handler: Handlers.manifestCreate,
|
||||
plugins: {
|
||||
'hapi-swagger': {
|
||||
responses: {
|
||||
'201': {
|
||||
description: 'Manifest revision created',
|
||||
schema: Models.manifest
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/deployment/{deploymentId}/manifest/{revision}',
|
||||
method: 'get',
|
||||
config: {
|
||||
id: 'manifestGet',
|
||||
tags: ['api', 'deployment', 'manifest'],
|
||||
description: 'Retrieve a manifest revision for a deployment group',
|
||||
validate: {
|
||||
params: {
|
||||
deploymentId: Models.deploymentId,
|
||||
revision: Models.manifestRevision
|
||||
}
|
||||
},
|
||||
response: {
|
||||
schema: Models.manifest
|
||||
},
|
||||
handler: Handlers.manifestGet
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/deployment/{deploymentId}/activities',
|
||||
method: 'get',
|
||||
config: {
|
||||
tags: ['api', 'deployment', 'activity'],
|
||||
description: 'Retrieve the recent activities for the deployment group',
|
||||
validate: {
|
||||
params: {
|
||||
deploymentId: Models.deploymentId
|
||||
}
|
||||
},
|
||||
response: {
|
||||
schema: Models.activities
|
||||
},
|
||||
handler: Handlers.activitiesGet
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/deployment/{deploymentId}/metrics',
|
||||
method: 'get',
|
||||
config: {
|
||||
tags: ['api', 'deployment', 'metric'],
|
||||
description: 'Retrieve metrics for the deployment group',
|
||||
validate: {
|
||||
params: {
|
||||
deploymentId: Models.deploymentId
|
||||
}
|
||||
},
|
||||
response: {
|
||||
schema: Models.metrics
|
||||
},
|
||||
handler: Handlers.metricsGet
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/deployment/{deploymentId}/state',
|
||||
method: 'get',
|
||||
config: {
|
||||
tags: ['api', 'deployment', 'state'],
|
||||
description: 'Retrieve the current state of the deployment group',
|
||||
validate: {
|
||||
params: {
|
||||
deploymentId: Models.deploymentId
|
||||
}
|
||||
},
|
||||
response: {
|
||||
schema: Models.state
|
||||
},
|
||||
handler: Handlers.stateGet
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/deployment/{deploymentId}/state',
|
||||
method: 'put',
|
||||
config: {
|
||||
tags: ['api', 'deployment', 'state'],
|
||||
description: 'Perform an action on the deployment group state',
|
||||
validate: {
|
||||
params: {
|
||||
deploymentId: Models.deploymentId
|
||||
},
|
||||
payload: Models.stateAction
|
||||
},
|
||||
response: {
|
||||
schema: Models.state
|
||||
},
|
||||
handler: Handlers.stateUpdate
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/deployment/{deploymentId}/services',
|
||||
method: 'get',
|
||||
config: {
|
||||
tags: ['api', 'deployment', 'service'],
|
||||
description: 'Retrieve the services for a deployment group',
|
||||
validate: {
|
||||
params: {
|
||||
deploymentId: Models.deploymentId
|
||||
}
|
||||
},
|
||||
response: {
|
||||
schema: Models.services
|
||||
},
|
||||
handler: Handlers.servicesGet
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/deployment/{deploymentId}/service/{name}',
|
||||
method: 'put',
|
||||
config: {
|
||||
tags: ['api', 'deployment', 'service'],
|
||||
description: 'Perform an action on the named service',
|
||||
validate: {
|
||||
params: {
|
||||
deploymentId: Models.deploymentId,
|
||||
name: Models.serviceName
|
||||
},
|
||||
payload: Models.serviceUpdate
|
||||
},
|
||||
response: {
|
||||
schema: Models.service
|
||||
},
|
||||
handler: Handlers.serviceUpdate
|
||||
}
|
||||
}
|
||||
];
|
28
portal-api/package.json
Normal file
28
portal-api/package.json
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "portal-api",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "./lib/index.js",
|
||||
"scripts": {
|
||||
"lint": "belly-button",
|
||||
"test": "npm run lint && lab -t 97"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "wyatt",
|
||||
"license": "MPL-2.0",
|
||||
"devDependencies": {
|
||||
"belly-button": "^3.1.0",
|
||||
"code": "^4.0.0",
|
||||
"hapi": "^16.1.1",
|
||||
"hapi-swagger": "^7.7.0",
|
||||
"inert": "^4.2.0",
|
||||
"lab": "^13.0.2",
|
||||
"vision": "^4.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"boom": "^4.3.1",
|
||||
"graphql": "^0.9.3",
|
||||
"graphql-server-hapi": "^0.7.2",
|
||||
"joi": "^10.4.1"
|
||||
}
|
||||
}
|
276
portal-api/test/index.js
Normal file
276
portal-api/test/index.js
Normal file
@ -0,0 +1,276 @@
|
||||
'use strict';
|
||||
|
||||
const Code = require('code');
|
||||
const Hapi = require('hapi');
|
||||
const Lab = require('lab');
|
||||
const PortalApi = require('../');
|
||||
|
||||
|
||||
// Test shortcuts
|
||||
|
||||
const lab = exports.lab = Lab.script();
|
||||
const describe = lab.describe;
|
||||
const it = lab.it;
|
||||
const expect = Code.expect;
|
||||
|
||||
|
||||
describe('portal-api plugin', () => {
|
||||
it('can be registered with hapi', (done) => {
|
||||
const server = new Hapi.Server();
|
||||
server.connection();
|
||||
server.register(PortalApi, (err) => {
|
||||
expect(err).to.not.exist();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('deployments', () => {
|
||||
it('can be created', (done) => {
|
||||
const server = new Hapi.Server();
|
||||
server.connection();
|
||||
server.register(PortalApi, (err) => {
|
||||
expect(err).to.not.exist();
|
||||
const payload = {
|
||||
name: 'User Services',
|
||||
datacenter: 'us-sw-1'
|
||||
};
|
||||
|
||||
server.inject({ method: 'POST', url: '/deployment', payload }, (res) => {
|
||||
expect(res.statusCode).to.equal(201);
|
||||
expect(res.headers.location).to.exist();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('can be updated', (done) => {
|
||||
const server = new Hapi.Server();
|
||||
server.connection();
|
||||
server.register(PortalApi, (err) => {
|
||||
expect(err).to.not.exist();
|
||||
const payload = {
|
||||
name: 'User Services',
|
||||
datacenter: 'us-sw-1'
|
||||
};
|
||||
|
||||
server.inject({ method: 'PUT', url: '/deployment/42', payload }, (res) => {
|
||||
expect(res.statusCode).to.equal(200);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('can be retrieved', (done) => {
|
||||
const server = new Hapi.Server();
|
||||
server.connection();
|
||||
server.register(PortalApi, (err) => {
|
||||
expect(err).to.not.exist();
|
||||
|
||||
server.inject({ method: 'GET', url: '/deployment/42' }, (res) => {
|
||||
expect(res.statusCode).to.equal(200);
|
||||
expect(res.result.name).to.equal('User Services');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('can be deleted', (done) => {
|
||||
const server = new Hapi.Server();
|
||||
server.connection();
|
||||
server.register(PortalApi, (err) => {
|
||||
expect(err).to.not.exist();
|
||||
|
||||
server.inject({ method: 'DELETE', url: '/deployment/42' }, (res) => {
|
||||
expect(res.statusCode).to.equal(200);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('can all be retrieved', (done) => {
|
||||
const server = new Hapi.Server();
|
||||
server.connection();
|
||||
server.register(PortalApi, (err) => {
|
||||
expect(err).to.not.exist();
|
||||
|
||||
server.inject({ method: 'GET', url: '/deployments' }, (res) => {
|
||||
expect(res.statusCode).to.equal(200);
|
||||
expect(res.result.length).to.equal(1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('datacenters', () => {
|
||||
it('can be retrieved', (done) => {
|
||||
const server = new Hapi.Server();
|
||||
server.connection();
|
||||
server.register(PortalApi, (err) => {
|
||||
expect(err).to.not.exist();
|
||||
|
||||
server.inject({ method: 'GET', url: '/datacenters' }, (res) => {
|
||||
expect(res.statusCode).to.equal(200);
|
||||
expect(res.result.length).to.equal(2);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('manifests', () => {
|
||||
it('can be created', (done) => {
|
||||
const server = new Hapi.Server();
|
||||
server.connection();
|
||||
server.register(PortalApi, (err) => {
|
||||
expect(err).to.not.exist();
|
||||
const payload = {
|
||||
file: {}
|
||||
};
|
||||
|
||||
server.inject({ method: 'POST', url: '/deployment/42/manifest', payload }, (res) => {
|
||||
expect(res.statusCode).to.equal(201);
|
||||
expect(res.headers.location).to.exist();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('can be retrieved', (done) => {
|
||||
const server = new Hapi.Server();
|
||||
server.connection();
|
||||
server.register(PortalApi, (err) => {
|
||||
expect(err).to.not.exist();
|
||||
|
||||
server.inject({ method: 'GET', url: '/deployment/42/manifest/5' }, (res) => {
|
||||
expect(res.statusCode).to.equal(200);
|
||||
expect(res.result.file).to.exist();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('activities', () => {
|
||||
it('can be retrieved', (done) => {
|
||||
const server = new Hapi.Server();
|
||||
server.connection();
|
||||
server.register(PortalApi, (err) => {
|
||||
expect(err).to.not.exist();
|
||||
|
||||
server.inject({ method: 'GET', url: '/deployment/42/activities' }, (res) => {
|
||||
expect(res.statusCode).to.equal(200);
|
||||
expect(res.result.length).to.equal(2);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('metrics', () => {
|
||||
it('can be retrieved', (done) => {
|
||||
const server = new Hapi.Server();
|
||||
server.connection();
|
||||
server.register(PortalApi, (err) => {
|
||||
expect(err).to.not.exist();
|
||||
|
||||
server.inject({ method: 'GET', url: '/deployment/42/metrics' }, (res) => {
|
||||
expect(res.statusCode).to.equal(200);
|
||||
expect(res.result.length).to.equal(2);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('deployment state', () => {
|
||||
it('can be retrieved', (done) => {
|
||||
const server = new Hapi.Server();
|
||||
server.connection();
|
||||
server.register(PortalApi, (err) => {
|
||||
expect(err).to.not.exist();
|
||||
|
||||
server.inject({ method: 'GET', url: '/deployment/42/state' }, (res) => {
|
||||
expect(res.statusCode).to.equal(200);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('can be updated', (done) => {
|
||||
const server = new Hapi.Server();
|
||||
server.connection();
|
||||
server.register(PortalApi, (err) => {
|
||||
expect(err).to.not.exist();
|
||||
const payload = {
|
||||
action: 'restart'
|
||||
};
|
||||
|
||||
server.inject({ method: 'PUT', url: '/deployment/42/state', payload }, (res) => {
|
||||
expect(res.statusCode).to.equal(200);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('services', () => {
|
||||
it('can be retrieved', (done) => {
|
||||
const server = new Hapi.Server();
|
||||
server.connection();
|
||||
server.register(PortalApi, (err) => {
|
||||
expect(err).to.not.exist();
|
||||
|
||||
server.inject({ method: 'GET', url: '/deployment/42/services' }, (res) => {
|
||||
expect(res.statusCode).to.equal(200);
|
||||
expect(res.result.length).to.equal(2);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('can be updated', (done) => {
|
||||
const server = new Hapi.Server();
|
||||
server.connection();
|
||||
server.register(PortalApi, (err) => {
|
||||
expect(err).to.not.exist();
|
||||
const payload = {
|
||||
count: 3
|
||||
};
|
||||
|
||||
server.inject({ method: 'PUT', url: '/deployment/42/service/consul', payload }, (res) => {
|
||||
expect(res.statusCode).to.equal(200);
|
||||
expect(res.result.count).to.equal(3);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('graphql', () => {
|
||||
it('route exists', (done) => {
|
||||
const server = new Hapi.Server();
|
||||
server.connection();
|
||||
server.register(PortalApi, (err) => {
|
||||
expect(err).to.not.exist();
|
||||
const url = '/graphql?query=%7B%0A%20%20getDeployment(id%3A%201)%20%7B%0A%20%20%20%20id%0A%20%20%7D%0A%7D';
|
||||
|
||||
server.inject({ method: 'GET', url }, (res) => {
|
||||
expect(res.statusCode).to.equal(200);
|
||||
const result = JSON.parse(res.result);
|
||||
expect(result.data).to.exist();
|
||||
expect(result.data.getDeployment).to.exist();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user