parent
8a0a0a4457
commit
d8f0dec487
@ -4,13 +4,7 @@ module.exports = {
|
|||||||
'scope-enum': [
|
'scope-enum': [
|
||||||
2,
|
2,
|
||||||
'always',
|
'always',
|
||||||
[
|
['ui-toolkit', 'my-joy-beta', 'boilerplate', 'create-instance']
|
||||||
'ui-toolkit',
|
|
||||||
'my-joy-beta',
|
|
||||||
'cloudapi-gql',
|
|
||||||
'boilerplate',
|
|
||||||
'create-instance'
|
|
||||||
]
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -19,9 +19,6 @@
|
|||||||
"test-ci": "lerna run test-ci",
|
"test-ci": "lerna run test-ci",
|
||||||
"test": "lerna run test",
|
"test": "lerna run test",
|
||||||
"clean": "lerna clean --yes",
|
"clean": "lerna clean --yes",
|
||||||
"bootstrap": "lerna bootstrap",
|
|
||||||
"dev": "lerna run dev --stream --parallel --scope my-joy-beta --scope cloudapi-gql",
|
|
||||||
"start": "lerna run start --stream --parallel --scope my-joy-beta --scope cloudapi-gql",
|
|
||||||
"commitmsg": "commitlint -e",
|
"commitmsg": "commitlint -e",
|
||||||
"precommit": "cross-env CI=1 redrun -s lint-staged format-staged",
|
"precommit": "cross-env CI=1 redrun -s lint-staged format-staged",
|
||||||
"postinstall": "lerna run prepublish",
|
"postinstall": "lerna run prepublish",
|
||||||
@ -66,10 +63,7 @@
|
|||||||
"staged-git-files": "0.0.4",
|
"staged-git-files": "0.0.4",
|
||||||
"yargs": "^10.0.3"
|
"yargs": "^10.0.3"
|
||||||
},
|
},
|
||||||
"workspaces": [
|
"workspaces": ["packages/*", "prototypes/*"],
|
||||||
"packages/*",
|
|
||||||
"prototypes/*"
|
|
||||||
],
|
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"lodash": "4.17.4",
|
"lodash": "4.17.4",
|
||||||
"lodash.keys": "4.2.0",
|
"lodash.keys": "4.2.0",
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
.nyc_output
|
|
||||||
coverage
|
|
||||||
doc
|
|
@ -1,15 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "joyent-portal",
|
|
||||||
"plugins": ["graphql"],
|
|
||||||
"rules": {
|
|
||||||
"jsx-a11y/href-no-hash": 0,
|
|
||||||
"graphql/template-strings": ["error", {
|
|
||||||
"env": "apollo"
|
|
||||||
}],
|
|
||||||
"graphql/named-operations": ["error"],
|
|
||||||
"graphql/required-fields": ["error", {
|
|
||||||
"requiredFields": ["id"]
|
|
||||||
}],
|
|
||||||
"graphql/capitalized-type-name": ["error"]
|
|
||||||
}
|
|
||||||
}
|
|
1
packages/cloudapi-gql/.gitignore
vendored
1
packages/cloudapi-gql/.gitignore
vendored
@ -1 +0,0 @@
|
|||||||
doc
|
|
@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"schemaPath": "src/schema/schema.graphql",
|
|
||||||
"extensions": {
|
|
||||||
"endpoints": {
|
|
||||||
"dev": "http://localhost:4000/graphql"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"libs": [
|
|
||||||
"ecmascript"
|
|
||||||
],
|
|
||||||
"plugins": {
|
|
||||||
"doc_comment": true,
|
|
||||||
"local-scope": true,
|
|
||||||
"node": true
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,53 +0,0 @@
|
|||||||
# cloudapi-gql
|
|
||||||
|
|
||||||
[![License: MPL 2.0](https://img.shields.io/badge/License-MPL%202.0-brightgreen.svg)](https://opensource.org/licenses/MPL-2.0)
|
|
||||||
[![standard-readme compliant](https://img.shields.io/badge/standard--readme-OK-green.svg)](https://github.com/RichardLitt/standard-readme)
|
|
||||||
|
|
||||||
Server that exposes [CloudApi](https://apidocs.joyent.com/cloudapi/) through
|
|
||||||
[GraphQL](http://graphql.org).
|
|
||||||
|
|
||||||
## Table of Contents
|
|
||||||
|
|
||||||
* [Install](#install)
|
|
||||||
* [Usage](#usage)
|
|
||||||
* [Todo](#todo)
|
|
||||||
* [License](#license)
|
|
||||||
|
|
||||||
## Install
|
|
||||||
|
|
||||||
```
|
|
||||||
yarn add cloudapi-gql
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
```
|
|
||||||
yarn run start
|
|
||||||
```
|
|
||||||
|
|
||||||
* [GraphiQL](http://0.0.0.0:4000/graphiql)
|
|
||||||
* [Graphidoc](http://0.0.0.0:4000/doc)
|
|
||||||
* [Voyager](http://0.0.0.0:4000/voyager)
|
|
||||||
* [Playground](http://0.0.0.0:4000/playground)
|
|
||||||
|
|
||||||
![](https://cldup.com/StGgfIbD3N.png) ![](https://cldup.com/fhpul_AJ13.png)
|
|
||||||
![](https://cldup.com/A-VwSbvWBe.png) ![](https://cldup.com/08P360Skhx.png)
|
|
||||||
|
|
||||||
```
|
|
||||||
yarn run faker
|
|
||||||
```
|
|
||||||
|
|
||||||
* [GraphQL Faker Interactive Editor](http://0.0.0.0:9002/editor)
|
|
||||||
* [GraphQL Faker API](http://0.0.0.0:9002/graphql)
|
|
||||||
|
|
||||||
![](https://cldup.com/VWadVMorQ0.png)
|
|
||||||
|
|
||||||
## Todo
|
|
||||||
|
|
||||||
* [ ] Finish missing connections, transforms, and mutations
|
|
||||||
* [ ] remove node-triton dependency
|
|
||||||
* [ ] support multiple users on the same server
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
MPL-2.0
|
|
@ -1,56 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "cloudapi-gql",
|
|
||||||
"version": "2.0.0",
|
|
||||||
"license": "MPL-2.0",
|
|
||||||
"repository": "github:yldio/joyent-portal",
|
|
||||||
"main": "src/schema/index.js",
|
|
||||||
"scripts": {
|
|
||||||
"lint": "eslint . --fix --ext .js --ext .graphql",
|
|
||||||
"fmt":
|
|
||||||
"prettier --write --single-quote src/**/*.js src/*.js src/**/*.graphql",
|
|
||||||
"test": "echo 0",
|
|
||||||
"test-ci": "echo 0",
|
|
||||||
"start": "PORT=4000 node src/server.js",
|
|
||||||
"dev": "CORS=1 PORT=4000 nodemon src/server.js",
|
|
||||||
"fake": "graphql-faker ./src/schema/schema.graphql -p 4000",
|
|
||||||
"prepublish": "echo 0",
|
|
||||||
"graphdoc": "graphdoc -s ./src/schema/schema.graphql -o ./doc --force",
|
|
||||||
"faker": "graphql-faker ./src/schema/schema.graphql"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@2fd/graphdoc": "^2.4.0",
|
|
||||||
"apollo-errors": "^1.5.1",
|
|
||||||
"apollo-server-hapi": "^1.1.7",
|
|
||||||
"apr-awaitify": "^1.0.4",
|
|
||||||
"boom": "^6.0.0",
|
|
||||||
"bunyan": "^1.8.12",
|
|
||||||
"dotenv": "^4.0.0",
|
|
||||||
"execa": "^0.8.0",
|
|
||||||
"force-array": "^3.1.0",
|
|
||||||
"good": "^7.3.0",
|
|
||||||
"good-console": "^6.4.0",
|
|
||||||
"good-squeeze": "^5.0.2",
|
|
||||||
"graphql-playground": "^1.0.33",
|
|
||||||
"graphql-tools": "^2.6.1",
|
|
||||||
"graphql-voyager": "^1.0.0-rc.9",
|
|
||||||
"hapi": "^16.6.2",
|
|
||||||
"hasha": "^3.0.0",
|
|
||||||
"inert": "^4.2.1",
|
|
||||||
"lodash.get": "^4.4.2",
|
|
||||||
"node-fetch": "^1.7.3",
|
|
||||||
"smartdc-auth": "^2.5.6",
|
|
||||||
"triton": "^5.4.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"graphql-faker": "^1.5.0",
|
|
||||||
"eslint": "^4.9.0",
|
|
||||||
"eslint-config-joyent-portal": "^3.2.0",
|
|
||||||
"eslint-plugin-graphql": "^1.4.0-1",
|
|
||||||
"graphql-faker": "^1.5.0",
|
|
||||||
"nodemon": "^1.12.1",
|
|
||||||
"prettier": "^1.7.4"
|
|
||||||
},
|
|
||||||
"nodemonConfig": {
|
|
||||||
"ignore": ["doc/*"]
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
const request = require('./request');
|
|
||||||
|
|
||||||
module.exports.get = () => request('getAccount');
|
|
||||||
module.exports.update = ctx => request('updateAccount', ctx);
|
|
@ -1,3 +0,0 @@
|
|||||||
const { fetch } = require('./request');
|
|
||||||
|
|
||||||
module.exports = () => fetch('/:login/config');
|
|
@ -1,5 +0,0 @@
|
|||||||
const request = require('./request');
|
|
||||||
|
|
||||||
module.exports = () => request('listDatacenters');
|
|
||||||
// this method is useless since it only "returns an HTTP redirect to your client, where the datacenter url is in the Location header"
|
|
||||||
// module.exports.get = ({ name }) => request.fetch(`/:login/datacenters/${name}`);
|
|
@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"BadRequest": "You sent bad HTTP",
|
|
||||||
"InternalError": "Something went wrong in Triton",
|
|
||||||
"InUseError": "The object is in use and cannot be operated on",
|
|
||||||
"InvalidArgument": "You sent bad arguments or a bad value for an argument",
|
|
||||||
"InvalidCredentials": "Authentication failed",
|
|
||||||
"InvalidHeader": "You sent a bad HTTP header",
|
|
||||||
"InvalidVersion": "You sent a bad Api-Version string",
|
|
||||||
"MissingParameter": "You didn't send a required parameter",
|
|
||||||
"NotAuthorized": "You don't have access to the requested resource",
|
|
||||||
"RequestThrottled": "You were throttled",
|
|
||||||
"RequestTooLarge": "You sent too much request data",
|
|
||||||
"RequestMoved": "HTTP Redirect",
|
|
||||||
"ResourceNotFound": "What you asked for wasn't found",
|
|
||||||
"UnknownError": "Something completely unexpected happened!"
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
const request = require('./request');
|
|
||||||
|
|
||||||
module.exports.list = () => request('listFirewallRules', {});
|
|
||||||
module.exports.listByMachine = ctx => request('listMachineFirewallRules', ctx);
|
|
||||||
module.exports.listMachines = ctx => request('listFirewallRuleMachines', ctx);
|
|
||||||
module.exports.get = ({ id }) => request('getFirewallRule', id);
|
|
||||||
module.exports.create = ctx => request('createFirewallRule', ctx);
|
|
||||||
module.exports.update = ctx => request('updateFirewallRule', ctx);
|
|
||||||
module.exports.enable = ctx => request('enableFirewallRule', ctx);
|
|
||||||
module.exports.disable = ctx => request('disableFirewallRule', ctx);
|
|
||||||
module.exports.destroy = ctx => request('deleteFirewallRule', ctx);
|
|
@ -1,15 +0,0 @@
|
|||||||
const request = require('./request');
|
|
||||||
|
|
||||||
const transform = ({ os, type, state, ...rest }) =>
|
|
||||||
Object.assign(rest, {
|
|
||||||
type: type ? type.toLowerCase() : type,
|
|
||||||
os: os ? os.toLowerCase() : os,
|
|
||||||
state: state ? state.toLowerCase() : state
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports.list = ctx => request('listImages', transform(ctx));
|
|
||||||
module.exports.get = ctx => request('getImage', ctx);
|
|
||||||
module.exports.destroy = uuid => request('deleteImage', uuid);
|
|
||||||
module.exports.export = uuid => request('deleteImage', uuid);
|
|
||||||
module.exports.create = ctx => request('createImageFromMachine', ctx);
|
|
||||||
module.exports.update = ctx => request('UpdateImage', ctx);
|
|
@ -1,17 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
account: require('./account'),
|
|
||||||
keys: require('./keys'),
|
|
||||||
users: require('./users'),
|
|
||||||
roles: require('./roles'),
|
|
||||||
policies: require('./policies'),
|
|
||||||
config: require('./config'),
|
|
||||||
datacenters: require('./datacenters'),
|
|
||||||
services: require('./services'),
|
|
||||||
images: require('./images'),
|
|
||||||
packages: require('./packages'),
|
|
||||||
machines: require('./machines'),
|
|
||||||
firewall: require('./firewall-rules'),
|
|
||||||
vlans: require('./vlans'),
|
|
||||||
networks: require('./networks'),
|
|
||||||
nics: require('./nics')
|
|
||||||
};
|
|
@ -1,19 +0,0 @@
|
|||||||
const forceArray = require('force-array');
|
|
||||||
const hasha = require('hasha');
|
|
||||||
|
|
||||||
module.exports.toKeyValue = r =>
|
|
||||||
r &&
|
|
||||||
Object.keys(r).map(name => ({
|
|
||||||
id: hasha(JSON.stringify({ name, value: r[name] })),
|
|
||||||
name,
|
|
||||||
value: r[name]
|
|
||||||
}));
|
|
||||||
|
|
||||||
module.exports.fromKeyValue = kvs =>
|
|
||||||
forceArray(kvs).reduce(
|
|
||||||
(rest, { name, value }) =>
|
|
||||||
Object.assign(rest, {
|
|
||||||
[name]: value
|
|
||||||
}),
|
|
||||||
{}
|
|
||||||
);
|
|
@ -1,25 +0,0 @@
|
|||||||
const { fetch, client } = require('./request');
|
|
||||||
|
|
||||||
const { principal } = client;
|
|
||||||
|
|
||||||
const getLoginPrefix = user =>
|
|
||||||
user && principal.account !== user
|
|
||||||
? `:login/users/${user}`
|
|
||||||
: principal.user && principal.user.length
|
|
||||||
? `:login/users/${principal.user}`
|
|
||||||
: ':login';
|
|
||||||
|
|
||||||
module.exports.list = (opts = {}) =>
|
|
||||||
fetch(`/${getLoginPrefix(opts.login)}/keys`);
|
|
||||||
|
|
||||||
module.exports.get = ({ login, name }) =>
|
|
||||||
fetch(`/${getLoginPrefix(login)}/keys/${name}`);
|
|
||||||
|
|
||||||
module.exports.create = ({ login, name, key }) =>
|
|
||||||
fetch(`/${getLoginPrefix(login)}/keys`, {
|
|
||||||
method: 'POST',
|
|
||||||
body: { name, key }
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports.destroy = ({ login, name }) =>
|
|
||||||
fetch(`/${getLoginPrefix(login)}/keys/${name}`, { method: 'DELETE' });
|
|
@ -1,47 +0,0 @@
|
|||||||
const request = require('./request');
|
|
||||||
|
|
||||||
const snapshots = {
|
|
||||||
list: ctx => request('listMachineSnapshots', ctx),
|
|
||||||
get: ctx => request('getMachineSnapshot', ctx),
|
|
||||||
create: ctx => request('createMachineSnapshot', ctx),
|
|
||||||
destroy: ctx => request('deleteMachineSnapshot', ctx)
|
|
||||||
};
|
|
||||||
|
|
||||||
const metadata = {
|
|
||||||
list: ({ id }) => request.fetch(`/:login/machines/${id}/metadata`),
|
|
||||||
get: ({ id, key }) => request.fetch(`/:login/machines/${id}/metadata/${key}`),
|
|
||||||
destroy: ctx => request('', ctx)
|
|
||||||
};
|
|
||||||
|
|
||||||
const firewall = {
|
|
||||||
enable: ctx => request('enableMachineFirewall', ctx),
|
|
||||||
disable: ctx => request('disableMachineFirewall', ctx)
|
|
||||||
};
|
|
||||||
|
|
||||||
const tags = {
|
|
||||||
list: ctx => request('listMachineTags', ctx),
|
|
||||||
get: ctx => request('getMachineTag', ctx),
|
|
||||||
add: ctx => request('addMachineTags', ctx),
|
|
||||||
replace: ctx => request('replaceMachineTags', ctx),
|
|
||||||
destroy: ctx =>
|
|
||||||
request(ctx.tag ? 'deleteMachineTag' : 'deleteMachineTags', ctx)
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports.list = ctx => request('listMachines', ctx);
|
|
||||||
module.exports.get = ctx => request('getMachine', ctx);
|
|
||||||
module.exports.create = ctx => request('createMachine', ctx);
|
|
||||||
module.exports.stop = ctx => request('stopMachine', ctx);
|
|
||||||
module.exports.start = uuid => request('startMachine', uuid);
|
|
||||||
module.exports.startFromSnapshot = ctx =>
|
|
||||||
request('startMachineFromSnapshot', ctx);
|
|
||||||
module.exports.reboot = ctx => request('rebootMachine', ctx);
|
|
||||||
module.exports.resize = ({ id, ...rest }) =>
|
|
||||||
request.fetch(`/:login/machines/${id}?action=resize?package=${rest.package}`);
|
|
||||||
module.exports.rename = ctx => request('', ctx);
|
|
||||||
module.exports.destroy = ctx => request('deleteMachine', ctx);
|
|
||||||
module.exports.audit = ({ id }) => request('machineAudit', id);
|
|
||||||
|
|
||||||
module.exports.snapshots = snapshots;
|
|
||||||
module.exports.metadata = metadata;
|
|
||||||
module.exports.firewall = firewall;
|
|
||||||
module.exports.tags = tags;
|
|
@ -1,9 +0,0 @@
|
|||||||
const request = require('./request');
|
|
||||||
|
|
||||||
// lists all networks, including fabric networks
|
|
||||||
module.exports.list = () => request('listNetworks');
|
|
||||||
module.exports.get = ({ id }) => request('getNetwork', id);
|
|
||||||
// create fabric network
|
|
||||||
module.exports.create = () => request('');
|
|
||||||
// destroy fabric network
|
|
||||||
module.exports.destroy = () => request('');
|
|
@ -1,6 +0,0 @@
|
|||||||
const request = require('./request');
|
|
||||||
|
|
||||||
module.exports.list = () => request('listNics');
|
|
||||||
module.exports.get = ctx => request('getNic', ctx);
|
|
||||||
module.exports.add = ctx => request('');
|
|
||||||
module.exports.destroy = ctx => request('');
|
|
@ -1,5 +0,0 @@
|
|||||||
const request = require('./request');
|
|
||||||
|
|
||||||
module.exports.list = ctx => request('listPackages', ctx);
|
|
||||||
module.exports.get = ({ id, name }) =>
|
|
||||||
request.fetch(`/:login/packages/${id || name}`);
|
|
@ -1,23 +0,0 @@
|
|||||||
const request = require('./request');
|
|
||||||
// const aperture = require('aperture');
|
|
||||||
// const { config } = require('aperture-config');
|
|
||||||
//
|
|
||||||
// const parser = aperture.createParser({
|
|
||||||
// types: aperture.types,
|
|
||||||
// typeTable: config.typeTable
|
|
||||||
// });
|
|
||||||
// .then(policies =>
|
|
||||||
// policies.map(({ rules, ...policy }) =>
|
|
||||||
// Object.assign(policy, {
|
|
||||||
// rules: Object.assign(rules.map(parser.parse.bind(parser)), {
|
|
||||||
// str: rule
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
// )
|
|
||||||
// );
|
|
||||||
|
|
||||||
module.exports.list = () => request('listPolicies');
|
|
||||||
module.exports.get = ctx => request('getPolicy', ctx);
|
|
||||||
module.exports.create = ctx => request('createPolicy', ctx);
|
|
||||||
module.exports.update = ctx => request('updatePolicy', ctx);
|
|
||||||
module.exports.destroy = ctx => request('deletePolicy', ctx);
|
|
@ -1,108 +0,0 @@
|
|||||||
const { createError } = require('apollo-errors');
|
|
||||||
const awaitify = require('apr-awaitify');
|
|
||||||
const auth = require('smartdc-auth');
|
|
||||||
const cloudapi = require('triton/lib/cloudapi2');
|
|
||||||
const bunyan = require('bunyan');
|
|
||||||
const fetch = require('node-fetch');
|
|
||||||
const url = require('url');
|
|
||||||
|
|
||||||
const pkg = require('../../package.json');
|
|
||||||
const credentials = require('../credentials');
|
|
||||||
const errors = require('./errors.json');
|
|
||||||
|
|
||||||
const STATUSES = [
|
|
||||||
400,
|
|
||||||
401,
|
|
||||||
403,
|
|
||||||
404,
|
|
||||||
405,
|
|
||||||
406,
|
|
||||||
409,
|
|
||||||
413,
|
|
||||||
415,
|
|
||||||
420,
|
|
||||||
449,
|
|
||||||
500,
|
|
||||||
503
|
|
||||||
];
|
|
||||||
|
|
||||||
const ERRORS = Object.keys(errors).reduce(
|
|
||||||
(errs, code) =>
|
|
||||||
Object.assign(errs, {
|
|
||||||
[code]: createError(code, { message: errors[code] })
|
|
||||||
}),
|
|
||||||
{}
|
|
||||||
);
|
|
||||||
|
|
||||||
const log = bunyan.createLogger({
|
|
||||||
name: pkg.name
|
|
||||||
});
|
|
||||||
|
|
||||||
const client = cloudapi.createClient({
|
|
||||||
log,
|
|
||||||
url: credentials.url,
|
|
||||||
account: credentials.account,
|
|
||||||
user: credentials.user,
|
|
||||||
sign: auth.cliSigner({
|
|
||||||
log,
|
|
||||||
keyId: credentials.keyId,
|
|
||||||
user: credentials.account,
|
|
||||||
subuser: credentials.user
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
const { _path, _getAuthHeaders, account, url: host } = client;
|
|
||||||
const getAuthHeaders = awaitify(_getAuthHeaders.bind(client));
|
|
||||||
|
|
||||||
module.exports = (method, args) => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const fn = client[method].bind(client);
|
|
||||||
|
|
||||||
const cb = (err, res) => {
|
|
||||||
if (err) {
|
|
||||||
return reject(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve(res);
|
|
||||||
};
|
|
||||||
|
|
||||||
return args ? fn(args, cb) : fn(cb);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports.client = client;
|
|
||||||
|
|
||||||
module.exports.fetch = async (_pathanme, reqOpts = {}) => {
|
|
||||||
const method = (reqOpts.method || 'get').toUpperCase();
|
|
||||||
const pathname = _path.call(client, _pathanme.replace(/:login/, account));
|
|
||||||
const headers = await getAuthHeaders(method, pathname);
|
|
||||||
|
|
||||||
const href = url.format({
|
|
||||||
protocol: 'https',
|
|
||||||
host: host.replace(/^https:\/\//, ''),
|
|
||||||
pathname
|
|
||||||
});
|
|
||||||
|
|
||||||
return fetch(
|
|
||||||
href,
|
|
||||||
Object.assign(reqOpts, {
|
|
||||||
method,
|
|
||||||
headers: Object.assign({}, reqOpts.headers, headers)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.then(async response => [response.status, await response.json()])
|
|
||||||
.then(([status, body]) => {
|
|
||||||
// eslint-disable-next-line no-implicit-coercion
|
|
||||||
if (~STATUSES.indexOf(status)) {
|
|
||||||
const { code, message } = body;
|
|
||||||
const CustomError = ERRORS[code] || ERRORS.UnknownError;
|
|
||||||
|
|
||||||
throw new CustomError({
|
|
||||||
message,
|
|
||||||
data: { pathname, body: reqOpts.body }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return body;
|
|
||||||
});
|
|
||||||
};
|
|
@ -1,21 +0,0 @@
|
|||||||
const request = require('./request');
|
|
||||||
|
|
||||||
module.exports.list = () => request('listRoles');
|
|
||||||
|
|
||||||
module.exports.get = ({ id, name }) =>
|
|
||||||
request.fetch(`/:login/roles/${id || name}`);
|
|
||||||
|
|
||||||
module.exports.create = ctx => request('createRole', ctx);
|
|
||||||
|
|
||||||
module.exports.set = ctx => {
|
|
||||||
const id = ctx.id ? `/${ctx.id}` : '';
|
|
||||||
const resource = `/${request.client.account}/${ctx.resource}${id}`;
|
|
||||||
|
|
||||||
return request('setRoleTags', {
|
|
||||||
roleTags: ctx.role,
|
|
||||||
resource
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports.update = ctx => request('updateRole', ctx);
|
|
||||||
module.exports.destroy = ctx => request('deleteRole', ctx);
|
|
@ -1,3 +0,0 @@
|
|||||||
const request = require('./request');
|
|
||||||
|
|
||||||
module.exports = () => request('listServices');
|
|
@ -1,7 +0,0 @@
|
|||||||
const request = require('./request');
|
|
||||||
|
|
||||||
module.exports.list = () => request('listUsers');
|
|
||||||
module.exports.get = ctx => request('getUser', ctx);
|
|
||||||
module.exports.create = ctx => request('createUser', ctx);
|
|
||||||
module.exports.destroy = ctx => request('deleteUser', ctx);
|
|
||||||
module.exports.update = ctx => request('updateUser', ctx);
|
|
@ -1,21 +0,0 @@
|
|||||||
const { fetch } = require('./request');
|
|
||||||
|
|
||||||
module.exports.list = () => fetch('/:login/fabrics/default/vlans');
|
|
||||||
module.exports.get = ({ id }) => fetch(`/:login/fabrics/default/vlans/${id}`);
|
|
||||||
|
|
||||||
module.exports.create = ctx =>
|
|
||||||
fetch(`/:login/fabrics/default/vlans`, {
|
|
||||||
method: 'POST',
|
|
||||||
body: ctx
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports.update = ({ id, ...rest }) =>
|
|
||||||
fetch(`/:login/fabrics/default/vlans/${id}`, {
|
|
||||||
method: 'PUT',
|
|
||||||
body: Object.assign({ id }, rest)
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports.destroy = ({ id }) =>
|
|
||||||
fetch(`/:login/fabrics/default/vlans/${id}`, {
|
|
||||||
method: 'DELETE'
|
|
||||||
});
|
|
@ -1,28 +0,0 @@
|
|||||||
const path = require('path');
|
|
||||||
|
|
||||||
const json = (() => {
|
|
||||||
try {
|
|
||||||
const res = require('dotenv').config({
|
|
||||||
path: path.join(__dirname, '../.env'),
|
|
||||||
silent: true
|
|
||||||
});
|
|
||||||
if (res.error) {
|
|
||||||
throw res.error;
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
try {
|
|
||||||
return require('../credentials.json');
|
|
||||||
} catch (err) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
})();
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
url: process.env.SDC_URL || json.SDC_URL || json.url || '',
|
|
||||||
account: process.env.SDC_ACCOUNT || json.SDC_ACCOUNT || json.account || '',
|
|
||||||
user: process.env.SDC_USER || json.SDC_USER || json.user || '',
|
|
||||||
keyId: process.env.SDC_KEY_ID || json.SDC_KEY_ID || json.keyId || ''
|
|
||||||
};
|
|
@ -1,17 +0,0 @@
|
|||||||
const path = require('path');
|
|
||||||
const { makeExecutableSchema } = require('graphql-tools');
|
|
||||||
const { readFileSync } = require('fs');
|
|
||||||
|
|
||||||
const resolvers = require('./resolvers');
|
|
||||||
const typeDefs = readFileSync(
|
|
||||||
path.join(__dirname, './schema.graphql'),
|
|
||||||
'utf-8'
|
|
||||||
);
|
|
||||||
|
|
||||||
module.exports = makeExecutableSchema({
|
|
||||||
typeDefs,
|
|
||||||
resolvers
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports.typeDefs = typeDefs;
|
|
||||||
module.exports.resolvers = resolvers;
|
|
@ -1,264 +0,0 @@
|
|||||||
const { toKeyValue, fromKeyValue } = require('../api/key-value');
|
|
||||||
const api = require('../api');
|
|
||||||
const forceArray = require('force-array');
|
|
||||||
const get = require('lodash.get');
|
|
||||||
|
|
||||||
const resolvers = {
|
|
||||||
Query: {
|
|
||||||
account: () => api.account.get(),
|
|
||||||
|
|
||||||
keys: (root, { login, name }) =>
|
|
||||||
name
|
|
||||||
? api.keys.get({ login, name }).then(key => [key])
|
|
||||||
: api.keys.list({ login, name }),
|
|
||||||
|
|
||||||
key: (root, { login, name }) => api.keys.get({ login, name }),
|
|
||||||
|
|
||||||
users: (root, { id }) =>
|
|
||||||
id ? api.users.get({ id }).then(user => [user]) : api.users.list(),
|
|
||||||
|
|
||||||
user: (root, { id }) => api.users.get({ id }),
|
|
||||||
|
|
||||||
roles: (root, { id, name }) =>
|
|
||||||
id || name
|
|
||||||
? api.roles.get({ id, name }).then(role => [role])
|
|
||||||
: api.roles.list(),
|
|
||||||
|
|
||||||
role: (root, { id, name }) => api.roles.get({ id, name }),
|
|
||||||
|
|
||||||
policies: (root, { id }) =>
|
|
||||||
id
|
|
||||||
? api.policies.get({ id }).then(policy => [policy])
|
|
||||||
: api.policies.list(),
|
|
||||||
|
|
||||||
policy: (root, { id }) => api.policies.get({ id }),
|
|
||||||
|
|
||||||
config: () => api.config().then(toKeyValue),
|
|
||||||
|
|
||||||
datacenters: () =>
|
|
||||||
api.datacenters().then(dcs =>
|
|
||||||
Object.keys(dcs).map(name => ({
|
|
||||||
name,
|
|
||||||
url: dcs[name]
|
|
||||||
}))
|
|
||||||
),
|
|
||||||
|
|
||||||
services: () => api.services().then(toKeyValue),
|
|
||||||
|
|
||||||
images: (root, { id, ...rest }) =>
|
|
||||||
id
|
|
||||||
? api.images.get({ id }).then(image => [image])
|
|
||||||
: api.images.list(rest),
|
|
||||||
|
|
||||||
image: (root, { id }) => api.images.get({ id }),
|
|
||||||
|
|
||||||
packages: (root, { id, ...rest }) =>
|
|
||||||
id
|
|
||||||
? api.packages.get({ id }).then(pkg => [pkg])
|
|
||||||
: api.packages.list(rest),
|
|
||||||
|
|
||||||
package: (root, { id, name }) => api.packages.get({ id, name }),
|
|
||||||
|
|
||||||
machines: (root, { id, brand, state, tags, ...rest }, _, ctx) =>
|
|
||||||
id
|
|
||||||
? api.machines.get({ id }).then(machine => [machine])
|
|
||||||
: api.machines
|
|
||||||
.list(
|
|
||||||
Object.assign(rest, {
|
|
||||||
brand: brand ? brand.toLowerCase() : brand,
|
|
||||||
state: state ? state.toLowerCase() : state,
|
|
||||||
tags: fromKeyValue(tags)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.then(machines => {
|
|
||||||
const field = forceArray(ctx.fieldNodes)
|
|
||||||
.filter(({ name }) => name.value === 'machines')
|
|
||||||
.shift();
|
|
||||||
|
|
||||||
if (!field) {
|
|
||||||
return machines;
|
|
||||||
}
|
|
||||||
|
|
||||||
const prop = get(field, 'selectionSet.selections', [])
|
|
||||||
.filter(({ name }) => name.value === 'dns_names')
|
|
||||||
.shift();
|
|
||||||
|
|
||||||
if (!prop) {
|
|
||||||
return machines;
|
|
||||||
}
|
|
||||||
|
|
||||||
return machines.map(({ id }) => api.machines.get({ id }));
|
|
||||||
}),
|
|
||||||
|
|
||||||
machine: (root, { id }) => api.machines.get({ id }),
|
|
||||||
|
|
||||||
snapshots: (root, { name, machine }) =>
|
|
||||||
name
|
|
||||||
? api.machines.snapshots
|
|
||||||
.get({ id: machine, name })
|
|
||||||
.then(snapshot => [snapshot])
|
|
||||||
: api.machines.snapshots.list({ id: machine }),
|
|
||||||
|
|
||||||
snapshot: (root, { name, machine }) =>
|
|
||||||
api.machines.snapshots.get({ name, id: machine }),
|
|
||||||
|
|
||||||
metadata: (root, { machine, name, ...rest }) =>
|
|
||||||
name
|
|
||||||
? api.machines.metadata
|
|
||||||
.get(Object.assign(rest, { id: machine, key: name }))
|
|
||||||
.then(value => toKeyValue({ [name]: value }))
|
|
||||||
: api.machines.metadata.list({ id: machine }).then(toKeyValue),
|
|
||||||
|
|
||||||
metadataValue: (root, { name, machine }) =>
|
|
||||||
api.machines.metadata
|
|
||||||
.get({ key: name, id: machine })
|
|
||||||
.then(value => toKeyValue({ [name]: value }).shift()),
|
|
||||||
|
|
||||||
tags: (root, { machine, name }) =>
|
|
||||||
name
|
|
||||||
? api.machines.tags
|
|
||||||
.get({ id: machine, tag: name })
|
|
||||||
.then(value => toKeyValue({ [name]: value }))
|
|
||||||
: api.machines.tags.list({ id: machine }).then(toKeyValue),
|
|
||||||
|
|
||||||
tag: (root, { machine, name }) =>
|
|
||||||
api.machines.tags
|
|
||||||
.get({ id: machine, tag: name })
|
|
||||||
.then(value => toKeyValue({ [name]: value }).shift()),
|
|
||||||
|
|
||||||
actions: (root, { machine }) => api.machines.audit({ id: machine }),
|
|
||||||
|
|
||||||
// eslint-disable-next-line camelcase
|
|
||||||
firewall_rules: (root, { machine, id }) =>
|
|
||||||
id
|
|
||||||
? api.firewall.get({ id })
|
|
||||||
: machine
|
|
||||||
? api.firewall.listByMachine({ id: machine })
|
|
||||||
: api.firewall.list(),
|
|
||||||
|
|
||||||
// eslint-disable-next-line camelcase
|
|
||||||
firewall_rule: (root, { id }) => api.firewall.get({ id }),
|
|
||||||
|
|
||||||
vlans: (root, { id }) => (id ? api.vlans.get({ id }) : api.vlans.list()),
|
|
||||||
|
|
||||||
vlan: (root, { id }) => api.vlans.get({ id }),
|
|
||||||
|
|
||||||
networks: (root, { id, vlan }) =>
|
|
||||||
id ? api.networks.get({ id, vlan }) : api.networks.list({ vlan }),
|
|
||||||
|
|
||||||
network: (root, { id, vlan }) => api.networks.get({ id, vlan }),
|
|
||||||
|
|
||||||
nics: (root, { machine, mac }) =>
|
|
||||||
mac ? api.nics.get({ machine, mac }) : api.nics.list({ machine }),
|
|
||||||
|
|
||||||
nic: (root, { machine, mac }) => api.nics.get({ machine, mac })
|
|
||||||
},
|
|
||||||
User: {
|
|
||||||
keys: ({ login }, { name }) => resolvers.Query.keys(null, { login, name })
|
|
||||||
},
|
|
||||||
Machine: {
|
|
||||||
brand: ({ brand }) => (brand ? brand.toUpperCase() : brand),
|
|
||||||
|
|
||||||
state: ({ state }) => (state ? state.toUpperCase() : state),
|
|
||||||
|
|
||||||
image: ({ image }) => resolvers.Query.image(null, { id: image }),
|
|
||||||
|
|
||||||
// eslint-disable-next-line camelcase
|
|
||||||
primary_ip: ({ primaryIp }) => primaryIp,
|
|
||||||
|
|
||||||
tags: ({ id }, { name }) =>
|
|
||||||
resolvers.Query.tags(null, { machine: id, name }),
|
|
||||||
|
|
||||||
metadata: ({ id }, { name }) =>
|
|
||||||
resolvers.Query.metadata(null, { machine: id, name }),
|
|
||||||
|
|
||||||
networks: ({ networks }) =>
|
|
||||||
Promise.all(networks.map(id => resolvers.Query.network(null, { id }))),
|
|
||||||
|
|
||||||
// eslint-disable-next-line camelcase
|
|
||||||
package: root => resolvers.Query.package(null, { name: root.package }),
|
|
||||||
|
|
||||||
snapshots: ({ id }, { name }) =>
|
|
||||||
resolvers.Query.snapshots(null, { machine: id, name }),
|
|
||||||
|
|
||||||
// eslint-disable-next-line camelcase
|
|
||||||
firewall_rules: ({ id: machine }, { id }) =>
|
|
||||||
resolvers.Query.firewall_rules(null, { machine, id }),
|
|
||||||
|
|
||||||
actions: ({ id }) => resolvers.Query.actions(null, { machine: id })
|
|
||||||
},
|
|
||||||
Image: {
|
|
||||||
os: ({ os }) => (os ? os.toUpperCase() : os),
|
|
||||||
|
|
||||||
state: ({ state }) => (state ? state.toUpperCase() : state),
|
|
||||||
|
|
||||||
type: ({ type }) => (type ? type.toUpperCase() : type)
|
|
||||||
},
|
|
||||||
Action: {
|
|
||||||
name: ({ action }) => action,
|
|
||||||
|
|
||||||
parameters: ({ parameters }) => toKeyValue(parameters)
|
|
||||||
},
|
|
||||||
Caller: {
|
|
||||||
type: ({ type }) => (type ? type.toUpperCase() : type),
|
|
||||||
|
|
||||||
// eslint-disable-next-line camelcase
|
|
||||||
key_id: ({ keyId }) => keyId
|
|
||||||
},
|
|
||||||
FirewallRule: {
|
|
||||||
machines: ({ id }) => api.firewall.listMachines({ id })
|
|
||||||
},
|
|
||||||
Snapshot: {
|
|
||||||
state: ({ state }) => (state ? state.toUpperCase() : state)
|
|
||||||
},
|
|
||||||
ImageError: {
|
|
||||||
code: ({ code }) => (code ? code.toUpperCase() : code)
|
|
||||||
},
|
|
||||||
ImageFile: {
|
|
||||||
compression: ({ compression }) =>
|
|
||||||
compression ? compression.toUpperCase() : compression
|
|
||||||
},
|
|
||||||
Mutation: {
|
|
||||||
stopMachine: (root, { id }) =>
|
|
||||||
api.machines.stop(id).then(() => resolvers.Query.machine(null, { id })),
|
|
||||||
|
|
||||||
startMachine: (root, { id }) =>
|
|
||||||
api.machines.start(id).then(() => resolvers.Query.machine(null, { id })),
|
|
||||||
|
|
||||||
rebootMachine: (root, { id }) =>
|
|
||||||
api.machines.reboot(id).then(() => resolvers.Query.machine(null, { id })),
|
|
||||||
|
|
||||||
resizeMachine: (root, { id, ...args }) =>
|
|
||||||
api.machines
|
|
||||||
.resize({ id, package: args.package })
|
|
||||||
.then(() => resolvers.Query.machine(null, { id })),
|
|
||||||
|
|
||||||
enableMachineFirewall: (root, { id }) =>
|
|
||||||
api.machines.firewall
|
|
||||||
.enable(id)
|
|
||||||
.then(() => resolvers.Query.machine(null, { id })),
|
|
||||||
|
|
||||||
disableMachineFirewall: (root, { id }) =>
|
|
||||||
api.machines.firewall
|
|
||||||
.disable(id)
|
|
||||||
.then(() => resolvers.Query.machine(null, { id })),
|
|
||||||
|
|
||||||
createMachineSnapshot: (root, { id, name }) =>
|
|
||||||
api.machines.snapshots
|
|
||||||
.create({ id, name })
|
|
||||||
.then(() => resolvers.Query.snapshots(null, { machine: id, name })),
|
|
||||||
|
|
||||||
startMachineFromSnapshot: (root, { id, name }) =>
|
|
||||||
api.machines.snapshots
|
|
||||||
.startFromSnapshot({ id, name })
|
|
||||||
.then(() => resolvers.Query.machine(null, { id })),
|
|
||||||
|
|
||||||
deleteMachineSnapshot: async (root, { id, snapshot: name }) => {
|
|
||||||
const snapshot = await api.machines.snapshots.get({ id, name });
|
|
||||||
await api.machines.snapshots.destroy({ id, name });
|
|
||||||
return snapshot;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = resolvers;
|
|
File diff suppressed because it is too large
Load Diff
@ -1,122 +0,0 @@
|
|||||||
const { hapi: Voyager } = require('graphql-voyager/middleware');
|
|
||||||
const { hapi: Playground } = require('graphql-playground/middleware');
|
|
||||||
const { graphqlHapi, graphiqlHapi } = require('apollo-server-hapi');
|
|
||||||
const { formatError } = require('apollo-errors');
|
|
||||||
const Hapi = require('hapi');
|
|
||||||
const Good = require('good');
|
|
||||||
const Path = require('path');
|
|
||||||
const Inert = require('inert');
|
|
||||||
const Execa = require('execa');
|
|
||||||
|
|
||||||
const schema = require('./schema');
|
|
||||||
|
|
||||||
const { CORS, PORT } = process.env;
|
|
||||||
|
|
||||||
const server = new Hapi.Server({
|
|
||||||
debug: {
|
|
||||||
log: ['error'],
|
|
||||||
request: ['error']
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const handlerError = err => {
|
|
||||||
if (err) {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.error(err);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// compile docs
|
|
||||||
// eslint-disable-next-line new-cap
|
|
||||||
Execa('npm', ['run', 'graphdoc']).catch(handlerError);
|
|
||||||
|
|
||||||
server.connection({
|
|
||||||
port: PORT,
|
|
||||||
routes: {
|
|
||||||
files: {
|
|
||||||
relativeTo: Path.join(__dirname, './../doc')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
server.register(
|
|
||||||
[
|
|
||||||
{
|
|
||||||
register: Good,
|
|
||||||
options: {
|
|
||||||
reporters: {
|
|
||||||
console: [
|
|
||||||
{
|
|
||||||
module: 'good-squeeze',
|
|
||||||
name: 'Squeeze',
|
|
||||||
args: [{ log: '*', response: '*' }]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
module: 'good-console'
|
|
||||||
},
|
|
||||||
'stdout'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Inert,
|
|
||||||
{
|
|
||||||
register: graphqlHapi,
|
|
||||||
options: {
|
|
||||||
path: '/graphql',
|
|
||||||
graphqlOptions: {
|
|
||||||
formatError,
|
|
||||||
schema
|
|
||||||
},
|
|
||||||
route: {
|
|
||||||
cors: Boolean(CORS)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
register: graphiqlHapi,
|
|
||||||
options: {
|
|
||||||
path: '/graphiql',
|
|
||||||
graphiqlOptions: {
|
|
||||||
endpointURL: '/graphql'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
register: Playground,
|
|
||||||
options: {
|
|
||||||
path: '/playground',
|
|
||||||
endpointUrl: '/graphql'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
register: Voyager,
|
|
||||||
options: {
|
|
||||||
path: '/voyager',
|
|
||||||
endpointUrl: '/graphql'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
err => {
|
|
||||||
handlerError(err);
|
|
||||||
|
|
||||||
server.route({
|
|
||||||
method: 'GET',
|
|
||||||
path: '/doc/{param*}',
|
|
||||||
handler: {
|
|
||||||
directory: {
|
|
||||||
path: '.',
|
|
||||||
redirectToSlash: true,
|
|
||||||
index: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
server.start(err => {
|
|
||||||
handlerError(err);
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log(`server started at http://0.0.0.0:${server.info.port}`);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
Loading…
Reference in New Issue
Block a user