feat(gql-cloudapi): template tag schema re-write
- uniform api usage for some models (account/user, networks/vlans/fabrics, etc) - graphidoc, playground, faker, and voyager support - schema in a template tag and documented - apollo-errors - apollo-server-hapi and schema using graphql-tools/makeExecutableSchema - replace express with Hapi - eslint support for graphql - updated dependencies
This commit is contained in:
parent
b64f345e13
commit
ed4ce42237
@ -53,6 +53,7 @@
|
||||
"eslint-config-xo-space": "^0.16.0",
|
||||
"eslint-gh-status-reporter": "^1.0.7",
|
||||
"eslint-plugin-flowtype": "^2.35.1",
|
||||
"eslint-plugin-graphql": "^1.3.0",
|
||||
"eslint-plugin-import": "^2.7.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.0.2",
|
||||
"eslint-plugin-prettier": "^2.2.0",
|
||||
|
@ -1,2 +1,3 @@
|
||||
.nyc_output
|
||||
coverage
|
||||
coverage
|
||||
doc
|
@ -1,3 +1,14 @@
|
||||
{
|
||||
"extends": "joyent-portal"
|
||||
"extends": "joyent-portal",
|
||||
"plugins": ["graphql"],
|
||||
"rules": {
|
||||
"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
Normal file
1
packages/cloudapi-gql/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
doc
|
8
packages/cloudapi-gql/.graphqlconfig
Normal file
8
packages/cloudapi-gql/.graphqlconfig
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"schemaPath": "src/schema/schema.graphql",
|
||||
"extensions": {
|
||||
"endpoints": {
|
||||
"dev": "http://localhost:4000/graphql"
|
||||
}
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ Server that exposes [CloudApi](https://apidocs.joyent.com/cloudapi/) through [Gr
|
||||
|
||||
- [Install](#install)
|
||||
- [Usage](#usage)
|
||||
- [Todo](#todo)
|
||||
- [License](#license)
|
||||
|
||||
## Install
|
||||
@ -23,6 +24,32 @@ yarn add joyent-portal-cloudapi-gql
|
||||
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,34 +1,56 @@
|
||||
{
|
||||
"name": "cloudapi-gql",
|
||||
"version": "1.0.4",
|
||||
"version": "2.0.0",
|
||||
"private": true,
|
||||
"license": "MPL-2.0",
|
||||
"repository": "github:yldio/joyent-portal",
|
||||
"main": "src/index.js",
|
||||
"main": "src/schema/index.js",
|
||||
"scripts": {
|
||||
"lint": "eslint . --fix",
|
||||
"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": "node src/index.js",
|
||||
"prepublish": "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.2",
|
||||
"apr-awaitify": "^1.0.4",
|
||||
"boom": "^6.0.0",
|
||||
"bunyan": "^1.8.12",
|
||||
"cors": "^2.8.4",
|
||||
"dotenv": "^4.0.0",
|
||||
"express": "^4.15.4",
|
||||
"express-graphql": "^0.6.11",
|
||||
"got": "^7.1.0",
|
||||
"graphql": "^0.11.2",
|
||||
"graphql-tools": "^1.2.2",
|
||||
"minimist": "^1.2.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.4",
|
||||
"graphql-tools": "^2.0.0",
|
||||
"graphql-voyager": "^1.0.0-rc.9",
|
||||
"hapi": "^16.6.2",
|
||||
"hasha": "^3.0.0",
|
||||
"inert": "^4.2.1",
|
||||
"node-fetch": "^1.7.3",
|
||||
"smartdc-auth": "^2.5.5",
|
||||
"triton": "^5.3.1"
|
||||
"smartdc-auth": "^2.5.6",
|
||||
"triton": "^5.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^4.5.0",
|
||||
"eslint-config-joyent-portal": "3.0.0"
|
||||
"graphql-faker": "^1.4.0",
|
||||
"eslint": "^4.8.0",
|
||||
"eslint-config-joyent-portal": "3.0.0",
|
||||
"eslint-plugin-graphql": "^1.3.0",
|
||||
"nodemon": "^1.12.1",
|
||||
"prettier": "^1.7.4"
|
||||
},
|
||||
"nodemonConfig": {
|
||||
"ignore": [
|
||||
"doc/*"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,4 @@
|
||||
const request = require('./request');
|
||||
|
||||
module.exports.get = () => {
|
||||
return request('getAccount');
|
||||
};
|
||||
|
||||
module.exports.update = ctx => {
|
||||
return request('updateAccount', ctx);
|
||||
};
|
||||
module.exports.get = () => request('getAccount');
|
||||
module.exports.update = ctx => request('updateAccount', ctx);
|
||||
|
@ -1,5 +1,3 @@
|
||||
// Const request = require('./request');
|
||||
const { fetch } = require('./request');
|
||||
|
||||
module.exports.get = () => {
|
||||
// Return request('', ctx);
|
||||
};
|
||||
module.exports = () => fetch('/:login/config');
|
||||
|
@ -1,5 +1,5 @@
|
||||
const request = require('./request');
|
||||
|
||||
module.exports = () => {
|
||||
return request('listDatacenters');
|
||||
};
|
||||
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}`);
|
||||
|
16
packages/cloudapi-gql/src/api/errors.json
Normal file
16
packages/cloudapi-gql/src/api/errors.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"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,9 +0,0 @@
|
||||
const request = require('./request');
|
||||
|
||||
module.exports.list = () => {
|
||||
return request('listFirewallRules', {});
|
||||
};
|
||||
|
||||
module.exports.get = ctx => {
|
||||
return request('getFirewallRule', ctx);
|
||||
};
|
@ -1,37 +1,11 @@
|
||||
const request = require('./request');
|
||||
|
||||
module.exports.list = () => {
|
||||
return request('listFirewallRules', {});
|
||||
};
|
||||
|
||||
module.exports.listByMachine = ctx => {
|
||||
return request('listMachineFirewallRules', ctx);
|
||||
};
|
||||
|
||||
module.exports.listMachines = ctx => {
|
||||
return request('listFirewallRuleMachines', ctx);
|
||||
};
|
||||
|
||||
module.exports.get = ctx => {
|
||||
return request('getFirewallRule', ctx);
|
||||
};
|
||||
|
||||
module.exports.create = ctx => {
|
||||
return request('createFirewallRule', ctx);
|
||||
};
|
||||
|
||||
module.exports.update = ctx => {
|
||||
return request('updateFirewallRule', ctx);
|
||||
};
|
||||
|
||||
module.exports.enable = ctx => {
|
||||
return request('enableFirewallRule', ctx);
|
||||
};
|
||||
|
||||
module.exports.disable = ctx => {
|
||||
return request('disableFirewallRule', ctx);
|
||||
};
|
||||
|
||||
module.exports.destroy = ctx => {
|
||||
return request('deleteFirewallRule', ctx);
|
||||
};
|
||||
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,25 +1,8 @@
|
||||
const request = require('./request');
|
||||
|
||||
module.exports.list = ctx => {
|
||||
return request('listImages', ctx);
|
||||
};
|
||||
|
||||
module.exports.get = ctx => {
|
||||
return request('getImage', ctx);
|
||||
};
|
||||
|
||||
module.exports.create = ctx => {
|
||||
return request('createImageFromMachine', ctx);
|
||||
};
|
||||
|
||||
// Module.exports.update = (ctx) => {
|
||||
// return request('UpdateImage', ctx);
|
||||
// };
|
||||
|
||||
module.exports.destroy = uuid => {
|
||||
return request('deleteImage', uuid);
|
||||
};
|
||||
|
||||
// Module.exports.xport = (uuid) => {
|
||||
// return request('deleteImage', uuid);
|
||||
// };
|
||||
module.exports.list = ctx => request('listImages', 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,16 +1,17 @@
|
||||
module.exports = {
|
||||
account: require('./account'),
|
||||
users: require('./users'),
|
||||
policies: require('./policies'),
|
||||
roles: require('./roles'),
|
||||
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'),
|
||||
firewallRules: require('./firewall-rules'),
|
||||
// Fabrics: require('./fabrics'),
|
||||
firewall: require('./firewall-rules'),
|
||||
vlans: require('./vlans'),
|
||||
networks: require('./networks'),
|
||||
nics: require('./nics')
|
||||
};
|
||||
|
18
packages/cloudapi-gql/src/api/key-value.js
Normal file
18
packages/cloudapi-gql/src/api/key-value.js
Normal file
@ -0,0 +1,18 @@
|
||||
const forceArray = require('force-array');
|
||||
const hasha = require('hasha');
|
||||
|
||||
module.exports.toKeyValue = 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,35 +1,25 @@
|
||||
const request = require('./request');
|
||||
const { fetch, client } = require('./request');
|
||||
|
||||
module.exports = {
|
||||
user: {
|
||||
list: ctx => {
|
||||
return request('listUserKeys', ctx);
|
||||
},
|
||||
get: ctx => {
|
||||
return request('getUserKey', ctx);
|
||||
},
|
||||
create: ctx => {
|
||||
return request('createUserKey', ctx);
|
||||
},
|
||||
destroy: ctx => {
|
||||
return request('deleteUserKey', ctx);
|
||||
}
|
||||
},
|
||||
account: {
|
||||
list: () => {
|
||||
return request('listKeys', {});
|
||||
},
|
||||
const { principal } = client;
|
||||
|
||||
get: ctx => {
|
||||
return request('getKey', ctx);
|
||||
},
|
||||
const getLoginPrefix = user =>
|
||||
user && principal.account !== user
|
||||
? `:login/users/${user}`
|
||||
: principal.user && principal.user.length
|
||||
? `:login/users/${principal.user}`
|
||||
: ':login';
|
||||
|
||||
create: ctx => {
|
||||
return request('createKey', ctx);
|
||||
},
|
||||
module.exports.list = (opts = {}) =>
|
||||
fetch(`/${getLoginPrefix(opts.login)}/keys`);
|
||||
|
||||
destroy: ctx => {
|
||||
return request('deleteKey', ctx);
|
||||
}
|
||||
}
|
||||
};
|
||||
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,119 +1,44 @@
|
||||
const awaitify = require('apr-awaitify');
|
||||
const fetch = require('node-fetch');
|
||||
const url = require('url');
|
||||
|
||||
const request = require('./request');
|
||||
|
||||
const { _path, _getAuthHeaders, account, url: host } = request.client;
|
||||
const client = request.client;
|
||||
const getAuthHeaders = awaitify(_getAuthHeaders.bind(client));
|
||||
|
||||
const snapshots = {
|
||||
list: ctx => {
|
||||
return request('listMachineSnapshots', ctx);
|
||||
},
|
||||
get: ctx => {
|
||||
return request('getMachineSnapshot', ctx);
|
||||
},
|
||||
create: ctx => {
|
||||
return request('createMachineSnapshot', ctx);
|
||||
},
|
||||
destroy: ctx => {
|
||||
return request('deleteMachineSnapshot', ctx);
|
||||
}
|
||||
list: ctx => request('listMachineSnapshots', ctx),
|
||||
get: ctx => request('getMachineSnapshot', ctx),
|
||||
create: ctx => request('createMachineSnapshot', ctx),
|
||||
destroy: ctx => request('deleteMachineSnapshot', ctx)
|
||||
};
|
||||
|
||||
const metadata = {
|
||||
list: async ({ id }) => {
|
||||
const pathname = _path.call(client, `/${account}/machines/${id}/metadata`);
|
||||
const headers = await getAuthHeaders('GET', pathname);
|
||||
|
||||
const href = url.format({
|
||||
protocol: 'https',
|
||||
host: host.replace(/^https:\/\//, ''),
|
||||
pathname
|
||||
});
|
||||
|
||||
return fetch(href, { method: 'GET', headers }).then(response =>
|
||||
response.json()
|
||||
);
|
||||
},
|
||||
get: ctx => {
|
||||
return request('getMachineMetadata', ctx);
|
||||
}
|
||||
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 => {
|
||||
return request('enableMachineFirewall', ctx);
|
||||
},
|
||||
disable: ctx => {
|
||||
return request('disableMachineFirewall', ctx);
|
||||
}
|
||||
enable: ctx => request('enableMachineFirewall', ctx),
|
||||
disable: ctx => request('disableMachineFirewall', ctx)
|
||||
};
|
||||
|
||||
const tags = {
|
||||
list: ctx => {
|
||||
return request('listMachineTags', ctx);
|
||||
},
|
||||
get: ctx => {
|
||||
return request('getMachineTag', ctx);
|
||||
},
|
||||
add: ctx => {
|
||||
return request('addMachineTags', ctx);
|
||||
},
|
||||
replace: ctx => {
|
||||
return request('replaceMachineTags', ctx);
|
||||
},
|
||||
destroy: ctx => {
|
||||
const method = ctx.tag ? 'deleteMachineTag' : 'deleteMachineTags';
|
||||
return request(method, ctx);
|
||||
}
|
||||
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 => {
|
||||
return request('listMachines', ctx);
|
||||
};
|
||||
|
||||
module.exports.get = ctx => {
|
||||
return request('getMachine', ctx);
|
||||
};
|
||||
|
||||
module.exports.create = ctx => {
|
||||
return request('createMachine', ctx);
|
||||
};
|
||||
|
||||
module.exports.stop = ctx => {
|
||||
return request('stopMachine', ctx);
|
||||
};
|
||||
|
||||
module.exports.start = uuid => {
|
||||
return request('startMachine', uuid);
|
||||
};
|
||||
|
||||
module.exports.startFromSnapshot = ctx => {
|
||||
return request('startMachineFromSnapshot', ctx);
|
||||
};
|
||||
|
||||
module.exports.reboot = ctx => {
|
||||
return request('rebootMachine', ctx);
|
||||
};
|
||||
|
||||
module.exports.resize = ctx => {
|
||||
return request('', ctx);
|
||||
};
|
||||
|
||||
module.exports.rename = ctx => {
|
||||
return request('', ctx);
|
||||
};
|
||||
|
||||
module.exports.destroy = ctx => {
|
||||
return request('deleteMachine', ctx);
|
||||
};
|
||||
|
||||
module.exports.audit = ctx => {
|
||||
return request('machineAudit', 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 = ctx => request('', ctx);
|
||||
module.exports.rename = ctx => request('', ctx);
|
||||
module.exports.destroy = ctx => request('deleteMachine', ctx);
|
||||
module.exports.audit = ctx => request('machineAudit', ctx);
|
||||
|
||||
module.exports.snapshots = snapshots;
|
||||
module.exports.metadata = metadata;
|
||||
|
@ -1,9 +1,9 @@
|
||||
const request = require('./request');
|
||||
|
||||
module.exports.list = () => {
|
||||
return request('listNetworks');
|
||||
};
|
||||
|
||||
module.exports.get = ctx => {
|
||||
return request('getNetwork', ctx);
|
||||
};
|
||||
// lists all networks, including fabric networks
|
||||
module.exports.list = () => request('listNetworks');
|
||||
module.exports.get = ctx => request('getNetwork', ctx);
|
||||
// create fabric network
|
||||
module.exports.create = () => request('');
|
||||
// destroy fabric network
|
||||
module.exports.destroy = () => request('');
|
||||
|
@ -1,9 +1,6 @@
|
||||
const request = require('./request');
|
||||
|
||||
module.exports.list = () => {
|
||||
return request('listNics');
|
||||
};
|
||||
|
||||
module.exports.get = ctx => {
|
||||
return request('getNic', ctx);
|
||||
};
|
||||
module.exports.list = () => request('listNics');
|
||||
module.exports.get = ctx => request('getNic', ctx);
|
||||
module.exports.add = ctx => request('');
|
||||
module.exports.destroy = ctx => request('');
|
||||
|
@ -1,9 +1,4 @@
|
||||
const request = require('./request');
|
||||
|
||||
module.exports.list = ctx => {
|
||||
return request('listPackages', ctx);
|
||||
};
|
||||
|
||||
module.exports.get = ctx => {
|
||||
return request('getPackage', ctx);
|
||||
};
|
||||
module.exports.list = ctx => request('listPackages', ctx);
|
||||
module.exports.get = ctx => request('getPackage', ctx);
|
||||
|
@ -1,21 +1,23 @@
|
||||
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 = () => {
|
||||
return request('listPolicies');
|
||||
};
|
||||
|
||||
module.exports.get = ctx => {
|
||||
return request('getPolicy', ctx);
|
||||
};
|
||||
|
||||
module.exports.create = ctx => {
|
||||
return request('createPolicy', ctx);
|
||||
};
|
||||
|
||||
module.exports.update = ctx => {
|
||||
return request('updatePolicy', ctx);
|
||||
};
|
||||
|
||||
module.exports.destroy = ctx => {
|
||||
return request('deletePolicy', ctx);
|
||||
};
|
||||
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,8 +1,38 @@
|
||||
const credentials = require('../credentials');
|
||||
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
|
||||
@ -21,6 +51,9 @@ const client = cloudapi.createClient({
|
||||
})
|
||||
});
|
||||
|
||||
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);
|
||||
@ -38,3 +71,38 @@ module.exports = (method, args) => {
|
||||
};
|
||||
|
||||
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,16 +1,11 @@
|
||||
const request = require('./request');
|
||||
|
||||
module.exports.list = () => {
|
||||
return request('listRoles');
|
||||
};
|
||||
module.exports.list = () => request('listRoles');
|
||||
|
||||
module.exports.get = ctx => {
|
||||
return request('getRole', ctx);
|
||||
};
|
||||
module.exports.get = ({ id, name }) =>
|
||||
request.fetch(`/:login/roles/${id || name}`);
|
||||
|
||||
module.exports.create = ctx => {
|
||||
return request('createRole', ctx);
|
||||
};
|
||||
module.exports.create = ctx => request('createRole', ctx);
|
||||
|
||||
module.exports.set = ctx => {
|
||||
const id = ctx.id ? `/${ctx.id}` : '';
|
||||
@ -22,10 +17,5 @@ module.exports.set = ctx => {
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.update = ctx => {
|
||||
return request('updateRole', ctx);
|
||||
};
|
||||
|
||||
module.exports.destroy = ctx => {
|
||||
return request('deleteRole', ctx);
|
||||
};
|
||||
module.exports.update = ctx => request('updateRole', ctx);
|
||||
module.exports.destroy = ctx => request('deleteRole', ctx);
|
||||
|
@ -1,5 +1,3 @@
|
||||
const request = require('./request');
|
||||
|
||||
module.exports = () => {
|
||||
return request('listServices');
|
||||
};
|
||||
module.exports = () => request('listServices');
|
||||
|
@ -1,21 +1,7 @@
|
||||
const request = require('./request');
|
||||
|
||||
module.exports.list = () => {
|
||||
return request('listUsers');
|
||||
};
|
||||
|
||||
module.exports.get = ctx => {
|
||||
return request('getUser', ctx);
|
||||
};
|
||||
|
||||
module.exports.create = ctx => {
|
||||
return request('createUser', ctx);
|
||||
};
|
||||
|
||||
module.exports.destroy = ctx => {
|
||||
return request('deleteUser', ctx);
|
||||
};
|
||||
|
||||
module.exports.update = ctx => {
|
||||
return request('updateUser', ctx);
|
||||
};
|
||||
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);
|
||||
|
21
packages/cloudapi-gql/src/api/vlans.js
Normal file
21
packages/cloudapi-gql/src/api/vlans.js
Normal file
@ -0,0 +1,21 @@
|
||||
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,11 +0,0 @@
|
||||
// const argv = require('minimist')(process.argv.slice(2));
|
||||
// const { makeExecutableSchema, addMockFunctionsToSchema } = require('graphql-tools');
|
||||
|
||||
// const { query, mutation } = require('./schema');
|
||||
|
||||
// console.log(new GraphQLSchema({
|
||||
// query,
|
||||
// mutation
|
||||
// }));
|
||||
//
|
||||
//
|
@ -1,37 +0,0 @@
|
||||
const express = require('express');
|
||||
const graphqlHTTP = require('express-graphql');
|
||||
const cors = require('cors');
|
||||
|
||||
const schema = require('./schema');
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(cors());
|
||||
app.options('*', cors());
|
||||
|
||||
app.post(
|
||||
'/graphql',
|
||||
graphqlHTTP({
|
||||
schema,
|
||||
graphiql: false
|
||||
})
|
||||
);
|
||||
|
||||
app.get(
|
||||
'/graphql',
|
||||
graphqlHTTP({
|
||||
schema,
|
||||
graphiql: true
|
||||
})
|
||||
);
|
||||
|
||||
const server = app.listen(4000, err => {
|
||||
if (err) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(err);
|
||||
throw err;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`Listening at http://0.0.0.0:${server.address().port}/graphql`);
|
||||
});
|
@ -1,9 +1,17 @@
|
||||
const { GraphQLSchema } = require('graphql');
|
||||
const path = require('path');
|
||||
const { makeExecutableSchema } = require('graphql-tools');
|
||||
const { readFileSync } = require('fs');
|
||||
|
||||
const query = require('./queries');
|
||||
const mutation = require('./mutations');
|
||||
const resolvers = require('./resolvers');
|
||||
const typeDefs = readFileSync(
|
||||
path.join(__dirname, './schema.graphql'),
|
||||
'utf-8'
|
||||
);
|
||||
|
||||
module.exports = new GraphQLSchema({
|
||||
query,
|
||||
mutation
|
||||
module.exports = makeExecutableSchema({
|
||||
typeDefs,
|
||||
resolvers
|
||||
});
|
||||
|
||||
module.exports.typeDefs = typeDefs;
|
||||
module.exports.resolvers = resolvers;
|
||||
|
@ -1,56 +0,0 @@
|
||||
const AccountType = require('../types/login');
|
||||
const api = require('../../api');
|
||||
|
||||
const { GraphQLBoolean, GraphQLString } = require('graphql');
|
||||
|
||||
module.exports.updateAccount = {
|
||||
type: AccountType,
|
||||
description: 'Update your account details',
|
||||
args: {
|
||||
email: {
|
||||
type: GraphQLString
|
||||
},
|
||||
companyName: {
|
||||
type: GraphQLString
|
||||
},
|
||||
firstName: {
|
||||
type: GraphQLString
|
||||
},
|
||||
lastName: {
|
||||
type: GraphQLString
|
||||
},
|
||||
address: {
|
||||
type: GraphQLString
|
||||
},
|
||||
postalCode: {
|
||||
type: GraphQLString
|
||||
},
|
||||
city: {
|
||||
type: GraphQLString
|
||||
},
|
||||
state: {
|
||||
type: GraphQLString
|
||||
},
|
||||
country: {
|
||||
type: GraphQLString
|
||||
},
|
||||
phone: {
|
||||
type: GraphQLString
|
||||
},
|
||||
cnsEnabled: {
|
||||
type: GraphQLBoolean
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
return api.account.get().then(account => {
|
||||
return api.account.update(
|
||||
Object.assign(account, args, {
|
||||
firstName: args.firstName || account.firstName,
|
||||
lastName: args.firstName || account.lastName,
|
||||
companyName: args.companyName || account.companyName,
|
||||
postalCode: args.postalCode || account.postalCode
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
};
|
@ -1,103 +0,0 @@
|
||||
const FirewallRuleType = require('../types/firewall-rule');
|
||||
const api = require('../../api');
|
||||
|
||||
const { GraphQLID, GraphQLBoolean, GraphQLString } = require('graphql');
|
||||
|
||||
module.exports.createFirewallRule = {
|
||||
type: FirewallRuleType,
|
||||
description:
|
||||
"Adds a new firewall rule for the specified account. This rule will be added to all the account's instances where it may be necessary",
|
||||
args: {
|
||||
enabled: {
|
||||
type: GraphQLBoolean,
|
||||
description:
|
||||
'Indicates if the rule is enabled (optional, false by default)'
|
||||
},
|
||||
rule: {
|
||||
type: GraphQLString,
|
||||
description: 'Firewall rule text'
|
||||
},
|
||||
description: {
|
||||
type: GraphQLString,
|
||||
description: 'Human-readable description for the rule (optional)'
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
return api.firewallRules.create({
|
||||
rule: args.rule,
|
||||
description: args.description,
|
||||
enabled: Boolean(args.enabled)
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.updateFirewallRule = {
|
||||
type: FirewallRuleType,
|
||||
description:
|
||||
'Updates the given rule record and -- depending on rule contents -- adds/removes/updates the rule on all the required instances',
|
||||
args: {
|
||||
id: {
|
||||
type: GraphQLID,
|
||||
description: 'Firewall rule id'
|
||||
},
|
||||
enabled: {
|
||||
type: GraphQLBoolean,
|
||||
description:
|
||||
'Indicates if the rule is enabled (optional, false by default)'
|
||||
},
|
||||
rule: {
|
||||
type: GraphQLString,
|
||||
description: 'Firewall rule text'
|
||||
},
|
||||
description: {
|
||||
type: GraphQLString,
|
||||
description: 'Human-readable description for the rule (optional)'
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
return api.firewallRules.update(args);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.enableFirewallRule = {
|
||||
type: FirewallRuleType,
|
||||
description: 'Enables the given firewall rule if it is disabled',
|
||||
args: {
|
||||
id: {
|
||||
type: GraphQLID,
|
||||
description: 'Firewall rule id'
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
return api.firewallRules.enable(args);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.disableFirewallRule = {
|
||||
type: FirewallRuleType,
|
||||
description: 'Disables the given firewall rule if it is enabled',
|
||||
args: {
|
||||
id: {
|
||||
type: GraphQLID,
|
||||
description: 'Firewall rule id'
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
return api.firewallRules.disable(args);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.deleteFirewallRule = {
|
||||
type: FirewallRuleType,
|
||||
description:
|
||||
'Removes the given firewall rule from all the required instances',
|
||||
args: {
|
||||
id: {
|
||||
type: GraphQLID,
|
||||
description: 'Firewall rule id'
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
return api.firewallRules.destroy(args);
|
||||
}
|
||||
};
|
@ -1,62 +0,0 @@
|
||||
const AccountType = require('../types/login');
|
||||
const DynamicObjectType = require('../types/dynamic-object');
|
||||
const api = require('../../api');
|
||||
|
||||
const {
|
||||
GraphQLString,
|
||||
GraphQLList,
|
||||
GraphQLNonNull,
|
||||
GraphQLID
|
||||
} = require('graphql');
|
||||
|
||||
module.exports.createImage = {
|
||||
type: AccountType,
|
||||
description: 'Create a new custom image from an instance',
|
||||
args: {
|
||||
machine: {
|
||||
type: new GraphQLNonNull(GraphQLID),
|
||||
description:
|
||||
'The prepared and stopped instance UUID from which the image is to be created'
|
||||
},
|
||||
name: {
|
||||
type: new GraphQLNonNull(GraphQLString),
|
||||
description:
|
||||
'The name of the custom image, e.g. "my-image". Maximum 512 characters. However, typical names should be much shorter, e.g. 5-20 characters'
|
||||
},
|
||||
version: {
|
||||
type: new GraphQLNonNull(GraphQLString),
|
||||
description:
|
||||
'The version of the custom image, e.g. "1.0.0". Maximum 128 characters'
|
||||
},
|
||||
description: {
|
||||
type: GraphQLString,
|
||||
description:
|
||||
'A short prose description of this image. Maximum 512 characters'
|
||||
},
|
||||
homepage: {
|
||||
type: GraphQLString,
|
||||
description:
|
||||
'Homepage URL where users can find more information about the image. Maximum 128 characters'
|
||||
},
|
||||
eula: {
|
||||
type: GraphQLString,
|
||||
description:
|
||||
'URL of the End User License Agreement (EULA) for the image. Maximum 128 characters'
|
||||
},
|
||||
acl: {
|
||||
type: new GraphQLList(GraphQLID),
|
||||
description:
|
||||
'An array of user/account UUIDs to which to give read access to a private image. I.e. this is only relevant for images with public === false'
|
||||
},
|
||||
tags: {
|
||||
type: DynamicObjectType,
|
||||
description:
|
||||
'An object of key/value pairs that allows clients to categorize images by any given criteria'
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
const { create } = api.images;
|
||||
|
||||
return create(args);
|
||||
}
|
||||
};
|
@ -1,16 +0,0 @@
|
||||
const { GraphQLObjectType } = require('graphql');
|
||||
|
||||
module.exports = new GraphQLObjectType({
|
||||
name: 'RootMutationType',
|
||||
fields: Object.assign(
|
||||
require('./account'),
|
||||
require('./keys'),
|
||||
require('./users'),
|
||||
require('./roles'),
|
||||
require('./policies'),
|
||||
require('./machines'),
|
||||
require('./images'),
|
||||
require('./firewall-rules'),
|
||||
require('./snapshots')
|
||||
)
|
||||
});
|
@ -1,52 +0,0 @@
|
||||
const KeyType = require('../types/key');
|
||||
const api = require('../../api');
|
||||
|
||||
const { GraphQLNonNull, GraphQLString, GraphQLID } = require('graphql');
|
||||
|
||||
module.exports.createKey = {
|
||||
type: KeyType,
|
||||
description:
|
||||
'Uploads a new OpenSSH key to Triton for use in HTTP signing and SSH',
|
||||
args: {
|
||||
name: {
|
||||
type: new GraphQLNonNull(GraphQLString)
|
||||
},
|
||||
key: {
|
||||
type: new GraphQLNonNull(GraphQLString)
|
||||
},
|
||||
userId: {
|
||||
type: GraphQLID,
|
||||
description:
|
||||
'UserId to add this key to. Leaving this in blank will add the key to the account'
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
const _api = args.userId ? api.keys.user : api.keys.account;
|
||||
return _api.create(args);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.deleteKey = {
|
||||
type: GraphQLID,
|
||||
description: 'Deletes a single SSH key, by name or fingerprint',
|
||||
args: {
|
||||
name: {
|
||||
type: GraphQLString
|
||||
},
|
||||
fingerprint: {
|
||||
type: GraphQLString
|
||||
},
|
||||
userId: {
|
||||
type: GraphQLID,
|
||||
description:
|
||||
'UserId who this key belongs to. Leaving this in blank will delete an account key'
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
const _api = args.userId ? api.keys.user : api.keys.account;
|
||||
|
||||
return _api.destroy(args).then(() => {
|
||||
return args.name || args.fingerprint;
|
||||
});
|
||||
}
|
||||
};
|
@ -1,328 +0,0 @@
|
||||
const MachineType = require('../types/machine');
|
||||
const DynamicObjectType = require('../types/dynamic-object');
|
||||
const api = require('../../api');
|
||||
|
||||
const {
|
||||
GraphQLNonNull,
|
||||
GraphQLString,
|
||||
GraphQLBoolean,
|
||||
GraphQLID,
|
||||
GraphQLList
|
||||
} = require('graphql');
|
||||
|
||||
module.exports.createMachine = {
|
||||
type: MachineType,
|
||||
description: 'Allows you to provision an instance',
|
||||
args: {
|
||||
name: {
|
||||
type: GraphQLString,
|
||||
description:
|
||||
'Friendly name for this instance; default is the first 8 characters of the machine id'
|
||||
},
|
||||
package: {
|
||||
type: new GraphQLNonNull(GraphQLString),
|
||||
description:
|
||||
'Id of the package to use on provisioning, obtained from ListPackages'
|
||||
},
|
||||
image: {
|
||||
type: new GraphQLNonNull(GraphQLString),
|
||||
description: 'The image UUID (from images { id })'
|
||||
},
|
||||
networks: {
|
||||
type: new GraphQLList(GraphQLString),
|
||||
description: 'Desired networks ids (from networks { id })'
|
||||
},
|
||||
locality: {
|
||||
type: MachineType.locality,
|
||||
description:
|
||||
'Optionally specify which instances the new instance should be near or far from'
|
||||
},
|
||||
metadata: {
|
||||
type: DynamicObjectType,
|
||||
description:
|
||||
'An arbitrary set of metadata key/value pairs can be set at provision time'
|
||||
},
|
||||
tags: {
|
||||
type: DynamicObjectType,
|
||||
description: 'An arbitrary set of tags can be set at provision time'
|
||||
},
|
||||
firewallEnabled: {
|
||||
type: GraphQLBoolean,
|
||||
description:
|
||||
'Completely enable or disable firewall for this instance. Default is false'
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
const resolveNames = (obj = {}, namespace) => {
|
||||
return Object.keys(obj).reduce((all, name) => {
|
||||
return Object.assign(all, {
|
||||
[`${namespace}.${name}`]: obj[name]
|
||||
});
|
||||
}, {});
|
||||
};
|
||||
|
||||
const tags = resolveNames(args.tags, 'tag');
|
||||
const metadata = resolveNames(args.tags, 'metadata');
|
||||
|
||||
const machine = Object.assign(
|
||||
{
|
||||
name: args.name,
|
||||
package: args.package,
|
||||
image: args.image,
|
||||
networks: args.networks,
|
||||
locality: args.locality,
|
||||
firewallEnabled: args.firewallEnabled
|
||||
},
|
||||
tags,
|
||||
metadata
|
||||
);
|
||||
|
||||
return api.machines.create(machine);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.startMachine = {
|
||||
type: MachineType,
|
||||
description: 'Allows you to boot up an instance',
|
||||
args: {
|
||||
id: {
|
||||
type: new GraphQLNonNull(GraphQLID),
|
||||
description: 'The machine id'
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
return api.machines.start(args.id).then(machine => {
|
||||
if (machine) {
|
||||
return machine;
|
||||
}
|
||||
|
||||
return api.machines.get(args);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.startMachineFromSnapshot = {
|
||||
type: MachineType,
|
||||
description:
|
||||
'If an instance is in the "stopped" state, you can choose to start the instance from the referenced snapshot',
|
||||
args: {
|
||||
id: {
|
||||
type: new GraphQLNonNull(GraphQLID),
|
||||
description: 'The machine id'
|
||||
},
|
||||
name: {
|
||||
type: new GraphQLNonNull(GraphQLID),
|
||||
description: 'The snapshot id'
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
return api.machines.startFromSnapshot(args).then(machine => {
|
||||
if (machine) {
|
||||
return machine;
|
||||
}
|
||||
|
||||
return api.machines.get(args);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.stopMachine = {
|
||||
type: MachineType,
|
||||
description: 'Allows you to shut down an instance',
|
||||
args: {
|
||||
id: {
|
||||
type: new GraphQLNonNull(GraphQLID),
|
||||
description: 'The machine id'
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
return api.machines.stop(args.id).then(machine => {
|
||||
if (machine) {
|
||||
return machine;
|
||||
}
|
||||
|
||||
return api.machines.get(args);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.rebootMachine = {
|
||||
type: MachineType,
|
||||
description: 'Allows you to reboot an instance',
|
||||
args: {
|
||||
id: {
|
||||
type: new GraphQLNonNull(GraphQLID),
|
||||
description: 'The machine id'
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
return api.machines.reboot(args.id).then(machine => {
|
||||
if (machine) {
|
||||
return machine;
|
||||
}
|
||||
|
||||
return api.machines.get(args);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.deleteMachine = {
|
||||
type: DynamicObjectType,
|
||||
description: 'Allows you to completely destroy an instance',
|
||||
args: {
|
||||
id: {
|
||||
type: new GraphQLNonNull(GraphQLID),
|
||||
description: 'The machine id'
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
return api.machines.destroy(args.id);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.auditMachine = {
|
||||
type: new GraphQLList(DynamicObjectType),
|
||||
description:
|
||||
"Provides a list of an instance's accomplished actions. Results are sorted from newest to oldest action",
|
||||
args: {
|
||||
id: {
|
||||
type: new GraphQLNonNull(GraphQLID),
|
||||
description: 'The machine id'
|
||||
}
|
||||
}
|
||||
// resolve: (root, args) => {
|
||||
// return api.machines.destroy(args.id);
|
||||
// }
|
||||
};
|
||||
|
||||
module.exports.setMachineFirewall = {
|
||||
type: MachineType,
|
||||
description: 'Allows you to set the firewall state for an instance',
|
||||
args: {
|
||||
id: {
|
||||
type: new GraphQLNonNull(GraphQLID),
|
||||
description: 'The machine id'
|
||||
},
|
||||
enabled: {
|
||||
type: new GraphQLNonNull(GraphQLBoolean)
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
const { firewall } = api.machines;
|
||||
|
||||
const fn = args.enabled ? firewall.enable : firewall.disable;
|
||||
|
||||
return fn(args.id).then(machine => {
|
||||
if (machine) {
|
||||
return machine;
|
||||
}
|
||||
|
||||
return api.machines.get(args);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.enableMachineFirewall = {
|
||||
type: MachineType,
|
||||
description: 'Allows you to enable the firewall for an instance',
|
||||
args: {
|
||||
id: {
|
||||
type: new GraphQLNonNull(GraphQLID),
|
||||
description: 'The machine id'
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
const { firewall } = api.machines;
|
||||
|
||||
return firewall.enable(args.id).then(machine => {
|
||||
if (machine) {
|
||||
return machine;
|
||||
}
|
||||
|
||||
return api.machines.get(args);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.disableMachineFirewall = {
|
||||
type: MachineType,
|
||||
description: 'Allows you to completely disable the firewall of an instance',
|
||||
args: {
|
||||
id: {
|
||||
type: new GraphQLNonNull(GraphQLID),
|
||||
description: 'The machine id'
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
const { firewall } = api.machines;
|
||||
|
||||
return firewall.disable(args.id).then(machine => {
|
||||
if (machine) {
|
||||
return machine;
|
||||
}
|
||||
|
||||
return api.machines.get(args);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.addMachineTags = {
|
||||
type: DynamicObjectType,
|
||||
description: 'Set tags on the given instance',
|
||||
args: {
|
||||
id: {
|
||||
type: new GraphQLNonNull(GraphQLID),
|
||||
description: 'The machine id'
|
||||
},
|
||||
tags: {
|
||||
type: new GraphQLNonNull(DynamicObjectType),
|
||||
description: 'Tag name/value pairs'
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
const { tags } = api.machines;
|
||||
|
||||
return tags.add(args);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.replaceMachineTags = {
|
||||
type: DynamicObjectType,
|
||||
description: 'Fully replace all tags on an instance with the given tags',
|
||||
args: {
|
||||
id: {
|
||||
type: new GraphQLNonNull(GraphQLID),
|
||||
description: 'The machine id'
|
||||
},
|
||||
tags: {
|
||||
type: new GraphQLNonNull(DynamicObjectType),
|
||||
description: 'Tag name/value pairs'
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
const { tags } = api.machines;
|
||||
|
||||
return tags.replace(args);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.deleteMachineTags = {
|
||||
type: DynamicObjectType,
|
||||
description: 'Deletes tags from an instance',
|
||||
args: {
|
||||
id: {
|
||||
type: new GraphQLNonNull(GraphQLID),
|
||||
description: 'The machine id'
|
||||
},
|
||||
tag: {
|
||||
type: GraphQLString,
|
||||
description:
|
||||
'Tag name to remove. If value is not supplied, all machine tags are removed'
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
const { tags } = api.machines;
|
||||
|
||||
return tags.destroy(args);
|
||||
}
|
||||
};
|
@ -1,74 +0,0 @@
|
||||
const PolicyType = require('../types/policy');
|
||||
const api = require('../../api');
|
||||
|
||||
const {
|
||||
GraphQLNonNull,
|
||||
GraphQLString,
|
||||
GraphQLID,
|
||||
GraphQLList
|
||||
} = require('graphql');
|
||||
|
||||
module.exports.createPolicy = {
|
||||
type: PolicyType,
|
||||
description: 'Creates a new account policy',
|
||||
args: {
|
||||
name: {
|
||||
type: new GraphQLNonNull(GraphQLString),
|
||||
description: 'The policy name'
|
||||
},
|
||||
rules: {
|
||||
type: new GraphQLNonNull(new GraphQLList(GraphQLString)),
|
||||
description:
|
||||
'One or more Aperture sentences to be added to the current policy'
|
||||
},
|
||||
description: {
|
||||
type: GraphQLString,
|
||||
description: 'A description for this policy (Optional)'
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
return api.policies.create(args);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.updatePolicy = {
|
||||
type: PolicyType,
|
||||
description:
|
||||
'Upgrades an existing account policy. Everything but id can be modified',
|
||||
args: {
|
||||
id: {
|
||||
type: new GraphQLNonNull(GraphQLID)
|
||||
},
|
||||
name: {
|
||||
type: new GraphQLNonNull(GraphQLString),
|
||||
description: 'The policy name'
|
||||
},
|
||||
rules: {
|
||||
type: new GraphQLNonNull(new GraphQLList(GraphQLString)),
|
||||
description:
|
||||
'One or more Aperture sentences to be added to the current policy'
|
||||
},
|
||||
description: {
|
||||
type: GraphQLString,
|
||||
description: 'A description for this policy (Optional)'
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
return api.policies.update(args);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.deletePolicy = {
|
||||
type: GraphQLID,
|
||||
description: 'Delete an RBAC policy',
|
||||
args: {
|
||||
id: {
|
||||
type: new GraphQLNonNull(GraphQLID)
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
return api.policies.destroy(args).then(() => {
|
||||
return args.id;
|
||||
});
|
||||
}
|
||||
};
|
@ -1,108 +0,0 @@
|
||||
const RoleType = require('../types/role');
|
||||
const api = require('../../api');
|
||||
|
||||
const {
|
||||
GraphQLNonNull,
|
||||
GraphQLString,
|
||||
GraphQLID,
|
||||
GraphQLList
|
||||
} = require('graphql');
|
||||
|
||||
module.exports.createRole = {
|
||||
type: RoleType,
|
||||
description: 'Create a new role for your account',
|
||||
args: {
|
||||
name: {
|
||||
type: new GraphQLNonNull(GraphQLString),
|
||||
description: "The role's name"
|
||||
},
|
||||
policies: {
|
||||
type: new GraphQLList(GraphQLString),
|
||||
description: "This account's policies to be given to this role (Optional)"
|
||||
},
|
||||
members: {
|
||||
type: new GraphQLList(GraphQLString),
|
||||
description:
|
||||
"This account's user logins to be added to this role (Optional)"
|
||||
},
|
||||
defaultMembers: {
|
||||
type: new GraphQLList(GraphQLString),
|
||||
description:
|
||||
"This account's user logins to be added to this role and have it enabled by default (Optional)"
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
return api.roles.create(args);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.updateRole = {
|
||||
type: RoleType,
|
||||
description: 'Modifies an account role. Anything but id can be modified',
|
||||
args: {
|
||||
id: {
|
||||
type: new GraphQLNonNull(GraphQLID)
|
||||
},
|
||||
name: {
|
||||
type: GraphQLString,
|
||||
description: "The role's name"
|
||||
},
|
||||
policies: {
|
||||
type: new GraphQLList(GraphQLString),
|
||||
description: "This account's policies to be given to this role (Optional)"
|
||||
},
|
||||
members: {
|
||||
type: new GraphQLList(GraphQLString),
|
||||
description:
|
||||
"This account's user logins to be added to this role (Optional)"
|
||||
},
|
||||
defaultMembers: {
|
||||
type: new GraphQLList(GraphQLString),
|
||||
description:
|
||||
"This account's user logins to be added to this role and have it enabled by default (Optional)"
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
return api.roles.update(args);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.deleteRole = {
|
||||
type: GraphQLID,
|
||||
description: 'Remove a role',
|
||||
args: {
|
||||
id: {
|
||||
type: new GraphQLNonNull(GraphQLID)
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
return api.roles.destroy(args).then(() => {
|
||||
return args.id;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.setRoleTags = {
|
||||
type: RoleType.tag,
|
||||
description:
|
||||
"Sets the given role tags to the provided resource path. resource_path can be the path to any of the CloudAPI resources described in this document: account, keys, users, roles, policies, user's ssh keys, datacenters, images, packages, instances, analytics, instrumentations, firewall rules and networks.",
|
||||
args: {
|
||||
resource: {
|
||||
type: new GraphQLNonNull(GraphQLString),
|
||||
description: 'The resource type e.g. `machines`, `policies`...'
|
||||
},
|
||||
id: {
|
||||
type: GraphQLID,
|
||||
description: 'The resource id'
|
||||
},
|
||||
role: {
|
||||
type: new GraphQLNonNull(new GraphQLList(GraphQLString)),
|
||||
description: 'The list role-tags to be added to this resource'
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
const { set } = api.roles;
|
||||
|
||||
return set(args);
|
||||
}
|
||||
};
|
@ -1,60 +0,0 @@
|
||||
const SnapshotType = require('../types/snapshot');
|
||||
const api = require('../../api');
|
||||
|
||||
const { GraphQLNonNull, GraphQLString, GraphQLID } = require('graphql');
|
||||
|
||||
module.exports.createSnapshot = {
|
||||
type: SnapshotType,
|
||||
description: 'Allows you to take a snapshot of a machine instance',
|
||||
args: {
|
||||
machine: {
|
||||
type: new GraphQLNonNull(GraphQLID),
|
||||
description: 'The machine id'
|
||||
},
|
||||
name: {
|
||||
type: GraphQLString,
|
||||
description: 'The name to assign to the new snapshot'
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
const { snapshot: { create, get } } = api.machines;
|
||||
|
||||
const newArgs = {
|
||||
id: args.machine,
|
||||
name: args.name
|
||||
};
|
||||
|
||||
return create(newArgs).then(snapshot => {
|
||||
if (snapshot) {
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
return get(newArgs);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.deleteSnapshot = {
|
||||
type: GraphQLID,
|
||||
description: 'Deletes the specified snapshot of an instance',
|
||||
args: {
|
||||
machine: {
|
||||
type: new GraphQLNonNull(GraphQLID),
|
||||
description: 'The machine id'
|
||||
},
|
||||
name: {
|
||||
type: GraphQLString,
|
||||
description: 'The name to assign to the new snapshot'
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
const { snapshot: { destroy } } = api.machines;
|
||||
|
||||
const newArgs = {
|
||||
id: args.machine,
|
||||
name: args.name
|
||||
};
|
||||
|
||||
return destroy(newArgs).then(() => args.name);
|
||||
}
|
||||
};
|
@ -1,144 +0,0 @@
|
||||
const UserType = require('../types/login');
|
||||
const api = require('../../api');
|
||||
|
||||
const { GraphQLNonNull, GraphQLString, GraphQLID } = require('graphql');
|
||||
|
||||
module.exports.createUser = {
|
||||
type: UserType,
|
||||
description: 'Creates a new user under an account',
|
||||
args: {
|
||||
login: {
|
||||
type: new GraphQLNonNull(GraphQLString)
|
||||
},
|
||||
email: {
|
||||
type: new GraphQLNonNull(GraphQLString)
|
||||
},
|
||||
password: {
|
||||
type: new GraphQLNonNull(GraphQLString)
|
||||
},
|
||||
companyName: {
|
||||
type: GraphQLString
|
||||
},
|
||||
firstName: {
|
||||
type: GraphQLString
|
||||
},
|
||||
lastName: {
|
||||
type: GraphQLString
|
||||
},
|
||||
address: {
|
||||
type: GraphQLString
|
||||
},
|
||||
postalCode: {
|
||||
type: GraphQLString
|
||||
},
|
||||
city: {
|
||||
type: GraphQLString
|
||||
},
|
||||
state: {
|
||||
type: GraphQLString
|
||||
},
|
||||
country: {
|
||||
type: GraphQLString
|
||||
},
|
||||
phone: {
|
||||
type: GraphQLString
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
return api.users.create(
|
||||
Object.assign(args, {
|
||||
firstName: args.firstName,
|
||||
lastName: args.firstName,
|
||||
companyName: args.companyName,
|
||||
postalCode: args.postalCode
|
||||
})
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.deleteUser = {
|
||||
type: GraphQLID,
|
||||
description: 'Remove a user',
|
||||
args: {
|
||||
id: {
|
||||
type: new GraphQLNonNull(GraphQLID)
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
return api.users.destroy(args).then(() => {
|
||||
return args.id;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.updateUser = {
|
||||
type: UserType,
|
||||
description: "Update a user's modifiable properties",
|
||||
args: {
|
||||
id: {
|
||||
type: new GraphQLNonNull(GraphQLID)
|
||||
},
|
||||
login: {
|
||||
type: GraphQLString
|
||||
},
|
||||
email: {
|
||||
type: GraphQLString
|
||||
},
|
||||
companyName: {
|
||||
type: GraphQLString
|
||||
},
|
||||
firstName: {
|
||||
type: GraphQLString
|
||||
},
|
||||
lastName: {
|
||||
type: GraphQLString
|
||||
},
|
||||
address: {
|
||||
type: GraphQLString
|
||||
},
|
||||
postalCode: {
|
||||
type: GraphQLString
|
||||
},
|
||||
city: {
|
||||
type: GraphQLString
|
||||
},
|
||||
state: {
|
||||
type: GraphQLString
|
||||
},
|
||||
country: {
|
||||
type: GraphQLString
|
||||
},
|
||||
phone: {
|
||||
type: GraphQLString
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
return api.users.update(
|
||||
Object.assign(args, {
|
||||
firstName: args.firstName,
|
||||
lastName: args.firstName,
|
||||
companyName: args.companyName,
|
||||
postalCode: args.postalCode
|
||||
})
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// Module.exports.changeUserPassword = {
|
||||
// type: UserType,
|
||||
// description: 'This is a separate rule for password changes, so different policies can be used for an user trying to modify other data, or only their own password',
|
||||
// args: {
|
||||
// id: {
|
||||
// type: new GraphQLNonNull(GraphQLID)
|
||||
// },
|
||||
// password: {
|
||||
// type: GraphQLString
|
||||
// },
|
||||
// password_confirmation: {
|
||||
// type: GraphQLString
|
||||
// }
|
||||
// },
|
||||
// resolve: (root, args) => {
|
||||
// return api.users.updatePassword(args);
|
||||
// }
|
||||
// };
|
@ -1,13 +0,0 @@
|
||||
const AccountType = require('../types/login');
|
||||
const api = require('../../api');
|
||||
|
||||
module.exports = {
|
||||
type: AccountType,
|
||||
resolve() {
|
||||
return api.account.get().then(account => {
|
||||
return Object.assign(account, {
|
||||
isUser: false
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
@ -1,19 +0,0 @@
|
||||
const DatacenterType = require('../types/datacenter');
|
||||
const graphql = require('graphql');
|
||||
const api = require('../../api');
|
||||
|
||||
const { GraphQLList } = graphql;
|
||||
|
||||
module.exports = {
|
||||
type: new GraphQLList(DatacenterType),
|
||||
resolve() {
|
||||
return api.datacenters().then(datacenters => {
|
||||
return Object.keys(datacenters).map(name => {
|
||||
return {
|
||||
url: datacenters[name],
|
||||
name
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
@ -1,12 +0,0 @@
|
||||
const FabricType = require('../types/fabrics');
|
||||
const graphql = require('graphql');
|
||||
const api = require('../../api');
|
||||
|
||||
const { GraphQLList } = graphql;
|
||||
|
||||
module.exports = {
|
||||
type: new GraphQLList(FabricType),
|
||||
resolve() {
|
||||
return api.fabrics.list();
|
||||
}
|
||||
};
|
@ -1,19 +0,0 @@
|
||||
const FirewallRuleType = require('../types/firewall-rule');
|
||||
const graphql = require('graphql');
|
||||
const api = require('../../api');
|
||||
|
||||
const { GraphQLList, GraphQLID } = graphql;
|
||||
|
||||
module.exports = {
|
||||
type: new GraphQLList(FirewallRuleType),
|
||||
args: {
|
||||
id: {
|
||||
type: GraphQLID,
|
||||
description: 'Filter on id'
|
||||
}
|
||||
},
|
||||
resolve(root, args) {
|
||||
const { list, get } = api.firewallRules;
|
||||
return args.id ? get(args.id).then(rule => [rule]) : list();
|
||||
}
|
||||
};
|
@ -1,53 +0,0 @@
|
||||
const ImageType = require('../types/image');
|
||||
const graphql = require('graphql');
|
||||
const api = require('../../api');
|
||||
|
||||
const { GraphQLList, GraphQLBoolean, GraphQLString, GraphQLID } = graphql;
|
||||
|
||||
module.exports = {
|
||||
type: new GraphQLList(ImageType),
|
||||
args: {
|
||||
id: {
|
||||
type: GraphQLID,
|
||||
description: 'Filter on id'
|
||||
},
|
||||
name: {
|
||||
type: GraphQLString,
|
||||
description: 'Filter on "friendly" name'
|
||||
},
|
||||
os: {
|
||||
type: GraphQLString,
|
||||
description: 'Filter on the underlying operating system'
|
||||
},
|
||||
version: {
|
||||
type: GraphQLString,
|
||||
description: 'Filter on the version'
|
||||
},
|
||||
public: {
|
||||
type: GraphQLBoolean,
|
||||
description: 'Filter public/private images'
|
||||
},
|
||||
state: {
|
||||
type: GraphQLString,
|
||||
description:
|
||||
'Filter on image state. By default only active images are shown. Use "all" to list all images'
|
||||
},
|
||||
owner: {
|
||||
type: GraphQLString,
|
||||
description: 'Filter on owner UUID'
|
||||
},
|
||||
type: {
|
||||
type: GraphQLString,
|
||||
description: 'Filter on image type'
|
||||
}
|
||||
},
|
||||
resolve(root, args) {
|
||||
const { list, get } = api.images;
|
||||
|
||||
return args.id
|
||||
? get({
|
||||
id: args.id
|
||||
}).then(img => [img])
|
||||
: list(args);
|
||||
}
|
||||
};
|
@ -1,20 +0,0 @@
|
||||
const { GraphQLObjectType } = require('graphql');
|
||||
|
||||
module.exports = new GraphQLObjectType({
|
||||
name: 'RootQueryType',
|
||||
fields: {
|
||||
account: require('./account'),
|
||||
users: require('./users'),
|
||||
policies: require('./policies'),
|
||||
roles: require('./roles'),
|
||||
datacenters: require('./datacenters'),
|
||||
services: require('./services'),
|
||||
images: require('./images'),
|
||||
packages: require('./packages'),
|
||||
machines: require('./machines'),
|
||||
firewallRules: require('./firewall-rules'),
|
||||
// Fabrics: require('./fabrics')
|
||||
networks: require('./networks')
|
||||
// Nics: require('./nics')
|
||||
}
|
||||
});
|
@ -1,78 +0,0 @@
|
||||
const MachineType = require('../types/machine');
|
||||
const graphql = require('graphql');
|
||||
const api = require('../../api');
|
||||
|
||||
const { GraphQLInt, GraphQLList, GraphQLString, GraphQLID } = graphql;
|
||||
|
||||
module.exports = {
|
||||
type: new GraphQLList(MachineType),
|
||||
args: {
|
||||
id: {
|
||||
type: GraphQLID
|
||||
},
|
||||
brand: {
|
||||
type: GraphQLString,
|
||||
description: 'Filter on the type of instance (e.g. lx)'
|
||||
},
|
||||
name: {
|
||||
type: GraphQLString,
|
||||
description:
|
||||
'Machine name to find (will make your list size 1, or 0 if nothing found)'
|
||||
},
|
||||
image: {
|
||||
type: GraphQLString,
|
||||
description: 'Image id; returns instances provisioned with that image'
|
||||
},
|
||||
state: {
|
||||
type: GraphQLString,
|
||||
description: 'Filter on the current state (e.g. running)'
|
||||
},
|
||||
memory: {
|
||||
type: GraphQLInt,
|
||||
description: 'Filter on the current size of the RAM deployed (in MiB)'
|
||||
},
|
||||
tombstone: {
|
||||
type: GraphQLInt,
|
||||
description: 'Filter on instances destroyed in the last N minutes'
|
||||
},
|
||||
first: {
|
||||
type: GraphQLInt,
|
||||
description:
|
||||
'Return a max of N instances; default is 1000 (which is also the maximum allowable result set size)'
|
||||
},
|
||||
after: {
|
||||
type: GraphQLInt,
|
||||
description: 'Get a `first` number of instances starting at this offset'
|
||||
},
|
||||
tags: {
|
||||
type: new GraphQLList(GraphQLString),
|
||||
description: 'Filter on existing tags'
|
||||
},
|
||||
docker: {
|
||||
type: GraphQLString,
|
||||
description:
|
||||
'Whether to only list Docker instances, or only non-Docker instances, if present. Defaults to showing all instances.'
|
||||
},
|
||||
credentials: {
|
||||
type: GraphQLString,
|
||||
description:
|
||||
'Whether to include the generated credentials for instances, if present. Defaults to false'
|
||||
}
|
||||
},
|
||||
resolve(root, args) {
|
||||
const { list, get } = api.machines;
|
||||
|
||||
const { after, first } = args;
|
||||
|
||||
const newArgs = Object.assign(args, {
|
||||
limit: first,
|
||||
offset: after
|
||||
});
|
||||
|
||||
return args.id
|
||||
? get({
|
||||
id: args.id
|
||||
}).then(machine => [machine])
|
||||
: list(newArgs);
|
||||
}
|
||||
};
|
@ -1,19 +0,0 @@
|
||||
const NetworkType = require('../types/network');
|
||||
const graphql = require('graphql');
|
||||
const api = require('../../api');
|
||||
|
||||
const { GraphQLList, GraphQLID } = graphql;
|
||||
|
||||
module.exports = {
|
||||
type: new GraphQLList(NetworkType),
|
||||
args: {
|
||||
id: {
|
||||
type: GraphQLID
|
||||
}
|
||||
},
|
||||
resolve(root, args) {
|
||||
const { list, get } = api.networks;
|
||||
|
||||
return args.id ? get(args).then(network => [network]) : list();
|
||||
}
|
||||
};
|
@ -1,19 +0,0 @@
|
||||
const NicType = require('../types/nic');
|
||||
const graphql = require('graphql');
|
||||
const api = require('../../api');
|
||||
|
||||
const { GraphQLList, GraphQLString } = graphql;
|
||||
|
||||
module.exports = {
|
||||
type: new GraphQLList(NicType),
|
||||
args: {
|
||||
mac: {
|
||||
type: GraphQLString
|
||||
}
|
||||
},
|
||||
resolve(root, args) {
|
||||
const { list, get } = api.nics;
|
||||
|
||||
return args.id ? get(args).then(nic => [nic]) : list();
|
||||
}
|
||||
};
|
@ -1,57 +0,0 @@
|
||||
const PackageType = require('../types/package');
|
||||
const graphql = require('graphql');
|
||||
const api = require('../../api');
|
||||
|
||||
const { GraphQLInt, GraphQLList, GraphQLString, GraphQLID } = graphql;
|
||||
|
||||
module.exports = {
|
||||
type: new GraphQLList(PackageType),
|
||||
args: {
|
||||
id: {
|
||||
type: GraphQLID,
|
||||
description: 'Filter on package id'
|
||||
},
|
||||
name: {
|
||||
type: GraphQLString,
|
||||
description: 'Filter on the "friendly" name'
|
||||
},
|
||||
memory: {
|
||||
type: GraphQLInt,
|
||||
description: 'Filter on how much memory will by available (in MiB)'
|
||||
},
|
||||
disk: {
|
||||
type: GraphQLInt,
|
||||
description: 'Filter on how much disk space will be available (in MiB)'
|
||||
},
|
||||
swap: {
|
||||
type: GraphQLInt,
|
||||
description: 'Filter on how much swap space will be available (in MiB)'
|
||||
},
|
||||
lwps: {
|
||||
type: GraphQLInt,
|
||||
description:
|
||||
'Filter on maximum number of light-weight processes (threads) allowed'
|
||||
},
|
||||
vcpus: {
|
||||
type: GraphQLInt,
|
||||
description: 'Filter on number of vCPUs'
|
||||
},
|
||||
version: {
|
||||
type: GraphQLString,
|
||||
description: 'Filter on the version'
|
||||
},
|
||||
group: {
|
||||
type: GraphQLString,
|
||||
description: 'Filter on the group belonging to'
|
||||
}
|
||||
},
|
||||
resolve(root, args) {
|
||||
const { list, get } = api.packages;
|
||||
|
||||
return args.id
|
||||
? get({
|
||||
id: args.id
|
||||
}).then(pkg => [pkg])
|
||||
: list(args);
|
||||
}
|
||||
};
|
@ -1,20 +0,0 @@
|
||||
const PolicyType = require('../types/policy');
|
||||
const graphql = require('graphql');
|
||||
const api = require('../../api');
|
||||
|
||||
const { GraphQLList, GraphQLID } = graphql;
|
||||
|
||||
module.exports = {
|
||||
type: new GraphQLList(PolicyType),
|
||||
args: {
|
||||
id: {
|
||||
type: GraphQLID,
|
||||
description: '`id` of the `PolicyType` to filter'
|
||||
}
|
||||
},
|
||||
resolve(root, args) {
|
||||
const { list, get } = api.policies;
|
||||
|
||||
return args.id ? get(args).then(policy => [policy]) : list();
|
||||
}
|
||||
};
|
@ -1,20 +0,0 @@
|
||||
const RoleType = require('../types/role');
|
||||
const graphql = require('graphql');
|
||||
const api = require('../../api');
|
||||
|
||||
const { GraphQLList, GraphQLID } = graphql;
|
||||
|
||||
module.exports = {
|
||||
type: new GraphQLList(RoleType),
|
||||
args: {
|
||||
id: {
|
||||
type: GraphQLID,
|
||||
description: '`id` or `name` of the `RoleType` to filter'
|
||||
}
|
||||
},
|
||||
resolve(root, args) {
|
||||
const { list, get } = api.roles;
|
||||
|
||||
return args.id ? get(args).then(role => [role]) : list();
|
||||
}
|
||||
};
|
@ -1,19 +0,0 @@
|
||||
const ServiceType = require('../types/service');
|
||||
const graphql = require('graphql');
|
||||
const api = require('../../api');
|
||||
|
||||
const { GraphQLList } = graphql;
|
||||
|
||||
module.exports = {
|
||||
type: new GraphQLList(ServiceType),
|
||||
resolve() {
|
||||
return api.services().then(services => {
|
||||
return Object.keys(services).map(name => {
|
||||
return {
|
||||
url: services[name],
|
||||
name
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
@ -1,28 +0,0 @@
|
||||
const UserType = require('../types/login');
|
||||
const graphql = require('graphql');
|
||||
const api = require('../../api');
|
||||
|
||||
const { GraphQLList, GraphQLID } = graphql;
|
||||
|
||||
module.exports = {
|
||||
type: new GraphQLList(UserType),
|
||||
args: {
|
||||
id: {
|
||||
type: GraphQLID,
|
||||
description: '`id` or `login` of the `UserType` to filter'
|
||||
}
|
||||
},
|
||||
resolve(root, args) {
|
||||
const { list, get } = api.users;
|
||||
|
||||
return args.id
|
||||
? get(args)
|
||||
.then(user => [user])
|
||||
.then(user =>
|
||||
Object.assign(user, {
|
||||
isUser: true
|
||||
})
|
||||
)
|
||||
: list();
|
||||
}
|
||||
};
|
133
packages/cloudapi-gql/src/schema/resolvers.js
Normal file
133
packages/cloudapi-gql/src/schema/resolvers.js
Normal file
@ -0,0 +1,133 @@
|
||||
const { toKeyValue, fromKeyValue } = require('../api/key-value');
|
||||
const api = require('../api');
|
||||
|
||||
const transform = {
|
||||
toImage: ({ os, ...rest }) => {
|
||||
console.log(rest);
|
||||
return Object.assign(rest, {
|
||||
os: os ? os.toUpperCase() : os
|
||||
});
|
||||
},
|
||||
fromImage: ({ os, state, type, ...rest }) => Object.assign(rest, {
|
||||
os: os ? os.toLowerCase() : os,
|
||||
state: state ? state.toLowerCase() : state,
|
||||
type: type ? type.toLowerCase() : type
|
||||
})
|
||||
};
|
||||
|
||||
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])
|
||||
.then((imgs) => imgs.map(transform.toImage))
|
||||
: api.images.list(transform.fromImage(rest))
|
||||
.then((imgs) => imgs.map(transform.toImage)),
|
||||
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 }) => api.packages.get({ id }),
|
||||
machines: (root, { id, brand, state, tags, ...rest }) =>
|
||||
id
|
||||
? api.machines.get({ id })
|
||||
: api.machines.list(
|
||||
Object.assign(rest, {
|
||||
brand: brand ? brand.toLowerCase() : brand,
|
||||
state: state ? state.toLowerCase() : state,
|
||||
tags: fromKeyValue(tags)
|
||||
})
|
||||
),
|
||||
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()),
|
||||
// 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: {
|
||||
tags: ({ id }, { name }) =>
|
||||
resolvers.Query.tags(null, { machine: id, name }),
|
||||
metadata: ({ id }, { name }) =>
|
||||
resolvers.Query.metadata(null, { machine: id, name }),
|
||||
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 })
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = resolvers;
|
1144
packages/cloudapi-gql/src/schema/schema.graphql
Normal file
1144
packages/cloudapi-gql/src/schema/schema.graphql
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,59 +0,0 @@
|
||||
const DynamicObjectType = require('./dynamic-object');
|
||||
|
||||
const { GraphQLString, GraphQLObjectType, GraphQLBoolean } = require('graphql');
|
||||
|
||||
const CallerType = new GraphQLObjectType({
|
||||
name: 'CallerType',
|
||||
fields: {
|
||||
type: {
|
||||
type: GraphQLString,
|
||||
description:
|
||||
'Authentication type for the action request. One of "basic", "operator", "signature" or "token"'
|
||||
},
|
||||
user: {
|
||||
type: GraphQLString,
|
||||
description:
|
||||
'When the authentication type is "basic", this member will be present and include user login'
|
||||
},
|
||||
ip: {
|
||||
type: GraphQLString,
|
||||
description:
|
||||
'The IP addresses this from which the action was requested. Not present if type is "operator"'
|
||||
},
|
||||
keyId: {
|
||||
type: GraphQLString,
|
||||
description:
|
||||
'When authentication type is either "signature" or "token", SSH key identifier'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = new GraphQLObjectType({
|
||||
name: 'AuditType',
|
||||
fields: {
|
||||
action: {
|
||||
type: GraphQLString,
|
||||
description: 'The name of the action'
|
||||
},
|
||||
parameters: {
|
||||
type: DynamicObjectType,
|
||||
description:
|
||||
'The original set of parameters sent when the action was requested'
|
||||
},
|
||||
success: {
|
||||
type: GraphQLBoolean,
|
||||
description: "`true` or `false`, depending on the action's success",
|
||||
resolve: root => {
|
||||
return root.success === 'yes';
|
||||
}
|
||||
},
|
||||
caller: {
|
||||
type: CallerType,
|
||||
description: 'Account requesting the action'
|
||||
},
|
||||
time: {
|
||||
type: GraphQLString,
|
||||
description: 'When the action finished'
|
||||
}
|
||||
}
|
||||
});
|
@ -1,14 +0,0 @@
|
||||
const { GraphQLString, GraphQLObjectType } = require('graphql');
|
||||
|
||||
module.exports = new GraphQLObjectType({
|
||||
name: 'DatacenterType',
|
||||
fields: {
|
||||
name: {
|
||||
type: GraphQLString,
|
||||
description: 'location of the datacenter'
|
||||
},
|
||||
url: {
|
||||
type: GraphQLString
|
||||
}
|
||||
}
|
||||
});
|
@ -1,41 +0,0 @@
|
||||
const { GraphQLScalarType, Kind } = require('graphql');
|
||||
|
||||
const kinds = {
|
||||
[Kind.STRING]: ast => {
|
||||
return ast.value;
|
||||
},
|
||||
[Kind.BOOLEAN]: ast => {
|
||||
return kinds[Kind.STRING](ast);
|
||||
},
|
||||
[Kind.INT]: ast => {
|
||||
return Number(ast.value);
|
||||
},
|
||||
[Kind.FLOAT]: ast => {
|
||||
return kinds[Kind.INT](ast);
|
||||
},
|
||||
[Kind.OBJECT]: ast => {
|
||||
const value = Object.create(null);
|
||||
ast.fields.forEach(field => {
|
||||
value[field.name.value] = parseLiteral(field.value);
|
||||
});
|
||||
|
||||
return value;
|
||||
},
|
||||
[Kind.LIST]: ast => {
|
||||
return ast.values.map(parseLiteral);
|
||||
}
|
||||
};
|
||||
|
||||
// https://github.com/taion/graphql-type-json/blob/master/src/index.js
|
||||
const parseLiteral = ast => {
|
||||
const kind = kinds[ast.kind];
|
||||
return kind ? kinds[ast.kind](ast) : null;
|
||||
};
|
||||
|
||||
// From http://stackoverflow.com/a/34229603
|
||||
module.exports = new GraphQLScalarType({
|
||||
name: 'DynamicObjectType',
|
||||
serialize: v => v,
|
||||
parseValue: v => v,
|
||||
parseLiteral
|
||||
});
|
@ -1,19 +0,0 @@
|
||||
const { GraphQLString, GraphQLObjectType, GraphQLInt } = require('graphql');
|
||||
|
||||
module.exports = new GraphQLObjectType({
|
||||
name: 'FabricsType',
|
||||
fields: {
|
||||
name: {
|
||||
type: GraphQLString,
|
||||
description: 'A unique name to identify the VLAN'
|
||||
},
|
||||
vlanId: {
|
||||
type: GraphQLInt,
|
||||
description: "A number from 0-4095 that indicates the VLAN's id"
|
||||
},
|
||||
description: {
|
||||
type: GraphQLString,
|
||||
description: 'An optional description of the VLAN'
|
||||
}
|
||||
}
|
||||
});
|
@ -1,92 +0,0 @@
|
||||
const api = require('../../api');
|
||||
|
||||
const {
|
||||
GraphQLString,
|
||||
GraphQLBoolean,
|
||||
GraphQLObjectType,
|
||||
GraphQLList,
|
||||
GraphQLID,
|
||||
GraphQLInt
|
||||
} = require('graphql');
|
||||
|
||||
const FirewallRuleSyntaxType = new GraphQLObjectType({
|
||||
name: 'FirewallRuleSyntaxType',
|
||||
fields: {
|
||||
text: {
|
||||
type: GraphQLString
|
||||
},
|
||||
from: {
|
||||
type: GraphQLString
|
||||
},
|
||||
to: {
|
||||
type: GraphQLString
|
||||
},
|
||||
action: {
|
||||
type: GraphQLString
|
||||
},
|
||||
protocol: {
|
||||
type: GraphQLString
|
||||
},
|
||||
port: {
|
||||
type: GraphQLInt
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = new GraphQLObjectType({
|
||||
name: 'FirewallRuleType',
|
||||
// Function to allow circular dependencies
|
||||
fields: () => ({
|
||||
id: {
|
||||
type: GraphQLID,
|
||||
description: 'Unique identifier for this rule'
|
||||
},
|
||||
enabled: {
|
||||
type: GraphQLBoolean,
|
||||
description: 'Indicates if the rule is enabled',
|
||||
resolve: root => {
|
||||
return Boolean(root.enabled);
|
||||
}
|
||||
},
|
||||
rule: {
|
||||
type: GraphQLString, // FirewallRuleSyntaxType,
|
||||
description: 'Firewall rule',
|
||||
resolve: ({ rule }) => {
|
||||
return rule;
|
||||
// console.log(rule);
|
||||
// const regex = /from (.*?) to (.*?) (allow|deny) (.*?) port (\d*)/i;
|
||||
// const tokens = rule.match(regex);
|
||||
//
|
||||
// return {
|
||||
// from: tokens[1],
|
||||
// to: tokens[2],
|
||||
// action: tokens[3],
|
||||
// protocol: tokens[4],
|
||||
// port: tokens[5],
|
||||
// text: rule
|
||||
// };
|
||||
}
|
||||
},
|
||||
global: {
|
||||
type: GraphQLBoolean,
|
||||
description: 'Indicates if the rule is global',
|
||||
resolve: root => {
|
||||
return Boolean(root.global);
|
||||
}
|
||||
},
|
||||
description: {
|
||||
type: GraphQLString,
|
||||
description: 'Human-readable description for the rule'
|
||||
},
|
||||
machines: {
|
||||
// Circular dependency
|
||||
type: new GraphQLList(require('./machine')),
|
||||
description: 'Lists all instances a firewall rule is applied to',
|
||||
resolve: root => {
|
||||
return api.firewallRules.listMachines({
|
||||
id: root.id
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
@ -1,127 +0,0 @@
|
||||
const DynamicObjectType = require('./dynamic-object');
|
||||
|
||||
const {
|
||||
GraphQLBoolean,
|
||||
GraphQLString,
|
||||
GraphQLObjectType,
|
||||
GraphQLInt,
|
||||
GraphQLList,
|
||||
GraphQLID
|
||||
} = require('graphql');
|
||||
|
||||
const ErrorType = new GraphQLObjectType({
|
||||
name: 'ErrorType',
|
||||
fields: {
|
||||
code: {
|
||||
type: GraphQLString,
|
||||
description:
|
||||
'A CamelCase string code for this error, e.g. "PrepareImageDidNotRun". See GetImage docs for a table of error.code values'
|
||||
},
|
||||
message: {
|
||||
type: GraphQLString,
|
||||
description: 'A short description of the image creation failure'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const ImageFileType = new GraphQLObjectType({
|
||||
name: 'ImageFileType',
|
||||
fields: {
|
||||
compression: {
|
||||
type: GraphQLString,
|
||||
description:
|
||||
'The type of file compression used for the image file. One of "bzip2", "gzip", "none"'
|
||||
},
|
||||
sha1: {
|
||||
type: GraphQLString,
|
||||
description:
|
||||
'SHA-1 hex digest of the file content. Used for corruption checking'
|
||||
},
|
||||
size: {
|
||||
type: GraphQLInt,
|
||||
description: 'File size in bytes'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = new GraphQLObjectType({
|
||||
name: 'ImageType',
|
||||
description:
|
||||
'An image contains the software packages that will be available on newly-provisioned instance. In the case of hardware virtual machines, the image also includes the operating system',
|
||||
fields: {
|
||||
id: {
|
||||
type: GraphQLID,
|
||||
description: 'Unique id for this image'
|
||||
},
|
||||
name: {
|
||||
type: GraphQLString,
|
||||
description: 'The "friendly" name for this image'
|
||||
},
|
||||
os: {
|
||||
type: GraphQLString,
|
||||
description: 'The underlying operating system for this image'
|
||||
},
|
||||
version: {
|
||||
type: GraphQLString,
|
||||
description: 'The version for this image'
|
||||
},
|
||||
type: {
|
||||
type: GraphQLString,
|
||||
description: 'What kind of image this is. The values differ after v8.0.0+'
|
||||
},
|
||||
requirements: {
|
||||
type: DynamicObjectType,
|
||||
description:
|
||||
'Contains a grouping of various minimum requirements for provisioning an instance with this image. For example "password" indicates that a password must be provided'
|
||||
},
|
||||
homepage: {
|
||||
type: GraphQLString,
|
||||
description:
|
||||
'The URL for a web page with more detailed information for this image'
|
||||
},
|
||||
files: {
|
||||
type: new GraphQLList(ImageFileType),
|
||||
description:
|
||||
'An array of image files that make up each image. Currently only a single file per image is supported'
|
||||
},
|
||||
publishedAt: {
|
||||
type: GraphQLString,
|
||||
description: 'The time this image has been made publicly available'
|
||||
},
|
||||
owner: {
|
||||
type: GraphQLString,
|
||||
description: 'The UUID of the user who owns this image'
|
||||
},
|
||||
public: {
|
||||
type: GraphQLBoolean,
|
||||
description: 'Indicates if this image is publicly available',
|
||||
resolve: root => {
|
||||
return Boolean(root.public);
|
||||
}
|
||||
},
|
||||
state: {
|
||||
type: GraphQLString,
|
||||
description:
|
||||
'The current state of the image. One of "active", "unactivated", "disabled", "creating", "failed"'
|
||||
},
|
||||
tags: {
|
||||
type: DynamicObjectType,
|
||||
description:
|
||||
'An object of key/value pairs that allows clients to categorize images by any given criteria'
|
||||
},
|
||||
eula: {
|
||||
type: GraphQLString,
|
||||
description: 'URL of the End User License Agreement (EULA) for the image'
|
||||
},
|
||||
acl: {
|
||||
type: new GraphQLList(GraphQLString),
|
||||
description:
|
||||
'Access Control List. An array of account UUIDs given access to a private image. The field is only relevant to private images'
|
||||
},
|
||||
error: {
|
||||
type: ErrorType,
|
||||
description:
|
||||
'If state=="failed", resulting from CreateImageFromMachine failure, then there may be an error object of the form {"code": "<string error code>", "message": "<string desc>"}'
|
||||
}
|
||||
}
|
||||
});
|
@ -1,16 +0,0 @@
|
||||
const { GraphQLString, GraphQLObjectType } = require('graphql');
|
||||
|
||||
module.exports = new GraphQLObjectType({
|
||||
name: 'KeyType',
|
||||
fields: {
|
||||
name: {
|
||||
type: GraphQLString
|
||||
},
|
||||
fingerprint: {
|
||||
type: GraphQLString
|
||||
},
|
||||
key: {
|
||||
type: GraphQLString
|
||||
}
|
||||
}
|
||||
});
|
@ -1,108 +0,0 @@
|
||||
const KeyType = require('./key');
|
||||
const api = require('../../api');
|
||||
|
||||
const {
|
||||
GraphQLBoolean,
|
||||
GraphQLString,
|
||||
GraphQLList,
|
||||
GraphQLObjectType,
|
||||
GraphQLID
|
||||
} = require('graphql');
|
||||
|
||||
module.exports = new GraphQLObjectType({
|
||||
name: 'LoginType',
|
||||
fields: {
|
||||
id: {
|
||||
type: GraphQLID,
|
||||
description: 'Unique id for this user/account'
|
||||
},
|
||||
login: {
|
||||
type: GraphQLString,
|
||||
description: 'Account/Sub-user login name'
|
||||
},
|
||||
email: {
|
||||
type: GraphQLString,
|
||||
description: 'Email address'
|
||||
},
|
||||
companyName: {
|
||||
type: GraphQLString,
|
||||
resolve: root => {
|
||||
return Boolean(root.companyName) || root.companyName;
|
||||
}
|
||||
},
|
||||
firstName: {
|
||||
type: GraphQLString,
|
||||
resolve: root => {
|
||||
return Boolean(root.firstName) || root.firstName;
|
||||
}
|
||||
},
|
||||
lastName: {
|
||||
type: GraphQLString,
|
||||
resolve: root => {
|
||||
return Boolean(root.lastName) || root.lastName;
|
||||
}
|
||||
},
|
||||
address: {
|
||||
type: GraphQLString
|
||||
},
|
||||
postalCode: {
|
||||
type: GraphQLString,
|
||||
resolve: root => {
|
||||
return Boolean(root.postalCode) || root.postalCode;
|
||||
}
|
||||
},
|
||||
city: {
|
||||
type: GraphQLString
|
||||
},
|
||||
state: {
|
||||
type: GraphQLString
|
||||
},
|
||||
country: {
|
||||
type: GraphQLString
|
||||
},
|
||||
phone: {
|
||||
type: GraphQLString
|
||||
},
|
||||
cnsEnabled: {
|
||||
type: GraphQLBoolean,
|
||||
description: 'true if Triton CNS is enabled for account',
|
||||
resolve: root => {
|
||||
return root.isUser ? null : Boolean(root.tritonCnsEnabled);
|
||||
}
|
||||
},
|
||||
keys: {
|
||||
type: new GraphQLList(KeyType),
|
||||
description: 'Get keys for user/account',
|
||||
args: {
|
||||
name: {
|
||||
type: GraphQLString,
|
||||
description: 'Filter on key name'
|
||||
},
|
||||
fingerprint: {
|
||||
type: GraphQLString,
|
||||
description: 'Filter on key fingerprint'
|
||||
}
|
||||
},
|
||||
resolve(root, args) {
|
||||
const _api = root.isUser ? api.keys.user : api.keys.account;
|
||||
|
||||
const { list, get } = _api;
|
||||
|
||||
const newArgs = Object.assign(args, {
|
||||
userId: root.id
|
||||
});
|
||||
|
||||
const filtered = args.name || args.fingerprint;
|
||||
return filtered ? get(newArgs).then(key => [key]) : list(newArgs);
|
||||
}
|
||||
},
|
||||
updated: {
|
||||
type: GraphQLString,
|
||||
description: "When this user/account's details was last updated"
|
||||
},
|
||||
created: {
|
||||
type: GraphQLString,
|
||||
description: 'When this user/account was created'
|
||||
}
|
||||
}
|
||||
});
|
@ -1,181 +0,0 @@
|
||||
const api = require('../../api');
|
||||
const DynamicObjectType = require('./dynamic-object');
|
||||
const SnapshotType = require('./snapshot');
|
||||
|
||||
const {
|
||||
GraphQLBoolean,
|
||||
GraphQLString,
|
||||
GraphQLInputObjectType,
|
||||
GraphQLObjectType,
|
||||
GraphQLInt,
|
||||
GraphQLList,
|
||||
GraphQLID
|
||||
} = require('graphql');
|
||||
|
||||
module.exports = new GraphQLObjectType({
|
||||
name: 'MachineType',
|
||||
description:
|
||||
'An image contains the software packages that will be available on newly-provisioned instance. In the case of hardware virtual machines, the image also includes the operating system',
|
||||
// Function to allow circular dependencies
|
||||
fields: () => ({
|
||||
id: {
|
||||
type: GraphQLID,
|
||||
description: 'Unique id for this instance'
|
||||
},
|
||||
name: {
|
||||
type: GraphQLString,
|
||||
description: 'The "friendly" name for this instance'
|
||||
},
|
||||
brand: {
|
||||
type: GraphQLString,
|
||||
description: 'The type of instance (e.g. lx)'
|
||||
},
|
||||
state: {
|
||||
type: GraphQLString,
|
||||
description: 'The current state of this instance (e.g. running)'
|
||||
},
|
||||
image: {
|
||||
type: GraphQLString,
|
||||
description: 'The image id this instance was provisioned with'
|
||||
},
|
||||
memory: {
|
||||
type: GraphQLInt,
|
||||
description: 'The amount of RAM this instance has (in MiB)'
|
||||
},
|
||||
disk: {
|
||||
type: GraphQLInt,
|
||||
description: 'The amount of disk this instance has (in MiB)'
|
||||
},
|
||||
metadata: {
|
||||
type: DynamicObjectType,
|
||||
description: 'Any additional metadata this instance has',
|
||||
args: {
|
||||
name: {
|
||||
type: GraphQLString,
|
||||
description: 'Filter on the name of the metadata field'
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
const { metadata } = api.machines;
|
||||
const { list, get } = metadata;
|
||||
|
||||
return args.name
|
||||
? get({
|
||||
id: root.id,
|
||||
key: args.name
|
||||
}).then(value => ({
|
||||
[args.name]: value
|
||||
}))
|
||||
: list({ id: root.id });
|
||||
}
|
||||
},
|
||||
tags: {
|
||||
type: DynamicObjectType,
|
||||
description: 'Any tags this instance has',
|
||||
args: {
|
||||
name: {
|
||||
type: GraphQLString,
|
||||
description: 'Filter on the name of the tag'
|
||||
}
|
||||
},
|
||||
resolve: (root, args) => {
|
||||
const { tags: { get } } = api.machines;
|
||||
|
||||
return args.name
|
||||
? get({
|
||||
id: root.id,
|
||||
tag: args.name
|
||||
}).then(value => ({
|
||||
[args.name]: value
|
||||
}))
|
||||
: root.tags;
|
||||
}
|
||||
},
|
||||
created: {
|
||||
type: GraphQLString,
|
||||
description: 'When this instance was created'
|
||||
},
|
||||
updated: {
|
||||
type: GraphQLString,
|
||||
description: "When this instance's details was last updated"
|
||||
},
|
||||
docker: {
|
||||
type: GraphQLBoolean,
|
||||
description: 'Whether this instance is a Docker container, if present',
|
||||
resolve: root => {
|
||||
return Boolean(root.docker);
|
||||
}
|
||||
},
|
||||
ips: {
|
||||
type: new GraphQLList(GraphQLString),
|
||||
description: 'The IP addresses this instance has'
|
||||
},
|
||||
networks: {
|
||||
type: new GraphQLList(require('./network')),
|
||||
description: 'The networks of the nics this instance has',
|
||||
resolve: (root, args) => {
|
||||
const { networks } = root;
|
||||
const { get } = api.networks;
|
||||
|
||||
return Promise.all(networks.map(id => get(id)));
|
||||
}
|
||||
},
|
||||
primaryIp: {
|
||||
type: GraphQLString,
|
||||
description: 'IP address of the primary nic of this instance'
|
||||
},
|
||||
firewallEnabled: {
|
||||
type: GraphQLBoolean,
|
||||
description: 'Whether firewall rules are enforced on this instance',
|
||||
resolve: root => {
|
||||
return Boolean(root.firewallEnabled);
|
||||
}
|
||||
},
|
||||
firewallRules: {
|
||||
// Circular dependency
|
||||
type: new GraphQLList(require('./firewall-rule')),
|
||||
description: 'List of FirewallRules affecting this machine',
|
||||
resolve: ({ id }) => {
|
||||
return api.firewallRules.listByMachine({ id });
|
||||
}
|
||||
},
|
||||
computeNode: {
|
||||
type: GraphQLString,
|
||||
description: 'UUID of the server on which the instance is located'
|
||||
},
|
||||
package: {
|
||||
type: GraphQLString,
|
||||
description: 'The id or name of the package used to create this instance'
|
||||
},
|
||||
snapshots: {
|
||||
type: new GraphQLList(SnapshotType),
|
||||
description: 'The snapshots based on this instance',
|
||||
args: {
|
||||
name: {
|
||||
type: GraphQLString,
|
||||
description: 'Filter on the name of the snapshot'
|
||||
}
|
||||
},
|
||||
resolve: ({ id }, args) => {
|
||||
const { list, get } = api.machines.snapshots;
|
||||
|
||||
return args.name ? get({ name: args.name, id: root.id }) : list({ id });
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
module.exports.locality = new GraphQLInputObjectType({
|
||||
name: 'LocalityType',
|
||||
fields: {
|
||||
strict: {
|
||||
type: GraphQLBoolean
|
||||
},
|
||||
near: {
|
||||
type: new GraphQLList(GraphQLID)
|
||||
},
|
||||
far: {
|
||||
type: new GraphQLList(GraphQLID)
|
||||
}
|
||||
}
|
||||
});
|
@ -1,74 +0,0 @@
|
||||
const DynamicObjectType = require('./dynamic-object');
|
||||
|
||||
const {
|
||||
GraphQLBoolean,
|
||||
GraphQLString,
|
||||
GraphQLObjectType,
|
||||
GraphQLList,
|
||||
GraphQLID
|
||||
} = require('graphql');
|
||||
|
||||
module.exports = new GraphQLObjectType({
|
||||
name: 'NetworkType',
|
||||
description:
|
||||
'Logical networks in Triton model core network configurations to enable Triton to define Virtual Network Interfaces and IP addresses for instances',
|
||||
fields: {
|
||||
id: {
|
||||
type: GraphQLID,
|
||||
description: 'Unique id for this network'
|
||||
},
|
||||
name: {
|
||||
type: GraphQLString,
|
||||
description: 'The network name'
|
||||
},
|
||||
public: {
|
||||
type: GraphQLBoolean,
|
||||
description: 'Whether this a public or private (rfc1918) network',
|
||||
resolve: root => {
|
||||
return Boolean(root.public);
|
||||
}
|
||||
},
|
||||
fabric: {
|
||||
type: GraphQLBoolean,
|
||||
description: 'Whether this network is created on a fabric',
|
||||
resolve: root => {
|
||||
return Boolean(root.fabric);
|
||||
}
|
||||
},
|
||||
description: {
|
||||
type: GraphQLString,
|
||||
description: 'Description of this network'
|
||||
},
|
||||
subnet: {
|
||||
type: GraphQLString,
|
||||
description: 'A CIDR formatted string that describes the network'
|
||||
},
|
||||
provisionStartIp: {
|
||||
type: GraphQLString,
|
||||
description: 'The first IP on the network that may be assigned'
|
||||
},
|
||||
provisionEndIp: {
|
||||
type: GraphQLString,
|
||||
description: 'The last IP on the network that may be assigned'
|
||||
},
|
||||
gateway: {
|
||||
type: GraphQLString,
|
||||
description: 'Optional Gateway IP address'
|
||||
},
|
||||
resolvers: {
|
||||
type: new GraphQLList(GraphQLString),
|
||||
description: 'Optional Resolver IP addresses'
|
||||
},
|
||||
routes: {
|
||||
type: DynamicObjectType,
|
||||
description: 'Optional Static routes for hosts on this network'
|
||||
},
|
||||
internetNat: {
|
||||
type: GraphQLBoolean,
|
||||
description: 'Provision internet NAT zone on gateway address',
|
||||
resolve: root => {
|
||||
return Boolean(root.internetNat);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
@ -1,41 +0,0 @@
|
||||
const { GraphQLBoolean, GraphQLObjectType, GraphQLString } = require('graphql');
|
||||
|
||||
module.exports = new GraphQLObjectType({
|
||||
name: 'NicType',
|
||||
description:
|
||||
'Logical networks are used both on head nodes and compute nodes, and are associated with physical interfaces by using a system called NIC Tags',
|
||||
fields: {
|
||||
ip: {
|
||||
type: GraphQLString,
|
||||
description: "NIC's IPv4 address"
|
||||
},
|
||||
mac: {
|
||||
type: GraphQLString,
|
||||
description: "NIC's MAC address"
|
||||
},
|
||||
primary: {
|
||||
type: GraphQLBoolean,
|
||||
description: "Whether this is the instance's primary NIC",
|
||||
resolve: root => {
|
||||
return root.primary;
|
||||
}
|
||||
},
|
||||
netmask: {
|
||||
type: GraphQLString,
|
||||
description: 'IPv4 netmask'
|
||||
},
|
||||
gateway: {
|
||||
type: GraphQLString,
|
||||
description: 'IPv4 gateway'
|
||||
},
|
||||
state: {
|
||||
type: GraphQLString,
|
||||
description:
|
||||
'Describes the state of the NIC (e.g. provisioning, running, or stopped)'
|
||||
},
|
||||
network: {
|
||||
type: GraphQLString,
|
||||
description: "The NIC's network id (see ListNetworks)"
|
||||
}
|
||||
}
|
||||
});
|
@ -1,52 +0,0 @@
|
||||
const {
|
||||
GraphQLString,
|
||||
GraphQLObjectType,
|
||||
GraphQLInt,
|
||||
GraphQLID
|
||||
} = require('graphql');
|
||||
|
||||
module.exports = new GraphQLObjectType({
|
||||
name: 'PackageType',
|
||||
fields: {
|
||||
id: {
|
||||
type: GraphQLID,
|
||||
description: 'Unique id for this package'
|
||||
},
|
||||
name: {
|
||||
type: GraphQLString,
|
||||
description: 'The "friendly" name for this package'
|
||||
},
|
||||
memory: {
|
||||
type: GraphQLInt,
|
||||
description: 'How much memory will by available (in MiB)'
|
||||
},
|
||||
disk: {
|
||||
type: GraphQLInt,
|
||||
description: 'How much disk space will be available (in MiB)'
|
||||
},
|
||||
swap: {
|
||||
type: GraphQLInt,
|
||||
description: 'How much swap space will be available (in MiB)'
|
||||
},
|
||||
lwps: {
|
||||
type: GraphQLInt,
|
||||
description: 'Maximum number of light-weight processes (threads) allowed'
|
||||
},
|
||||
vcpus: {
|
||||
type: GraphQLInt,
|
||||
description: 'Number of vCPUs for this package'
|
||||
},
|
||||
version: {
|
||||
type: GraphQLString,
|
||||
description: 'The version of this package'
|
||||
},
|
||||
group: {
|
||||
type: GraphQLString,
|
||||
description: 'The group this package belongs to'
|
||||
},
|
||||
description: {
|
||||
type: GraphQLString,
|
||||
description: 'A human-friendly description about this package'
|
||||
}
|
||||
}
|
||||
});
|
@ -1,29 +0,0 @@
|
||||
const {
|
||||
GraphQLString,
|
||||
GraphQLObjectType,
|
||||
GraphQLList,
|
||||
GraphQLID
|
||||
} = require('graphql');
|
||||
|
||||
module.exports = new GraphQLObjectType({
|
||||
name: 'PolicyType',
|
||||
description: 'Policies are lists of rules that describe access to resources',
|
||||
fields: {
|
||||
id: {
|
||||
type: GraphQLID,
|
||||
description: 'Unique id for this policy'
|
||||
},
|
||||
name: {
|
||||
type: GraphQLString,
|
||||
description: 'The policy name'
|
||||
},
|
||||
rules: {
|
||||
type: new GraphQLList(GraphQLString),
|
||||
description: 'One or more Aperture sentences applying to the policy'
|
||||
},
|
||||
description: {
|
||||
type: GraphQLString,
|
||||
description: 'A description for this policy'
|
||||
}
|
||||
}
|
||||
});
|
@ -1,52 +0,0 @@
|
||||
const {
|
||||
GraphQLString,
|
||||
GraphQLObjectType,
|
||||
GraphQLList,
|
||||
GraphQLID
|
||||
} = require('graphql');
|
||||
|
||||
module.exports = new GraphQLObjectType({
|
||||
name: 'RoleType',
|
||||
description:
|
||||
'Roles are lists of users and policies. Roles describe which users are allowed access according to the policies',
|
||||
fields: {
|
||||
id: {
|
||||
type: GraphQLID,
|
||||
description: 'Unique id for this role'
|
||||
},
|
||||
name: {
|
||||
type: GraphQLString,
|
||||
description: 'The role name'
|
||||
},
|
||||
policies: {
|
||||
type: new GraphQLList(GraphQLString),
|
||||
description: "This account's policies which this role obeys (Optional)"
|
||||
},
|
||||
members: {
|
||||
type: new GraphQLList(GraphQLString),
|
||||
description: "This account's user logins this role applies to (Optional)"
|
||||
},
|
||||
defaultMembers: {
|
||||
type: new GraphQLList(GraphQLString),
|
||||
description:
|
||||
"This account's user logins this role applies to by default (Optional)"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
module.exports.tag = new GraphQLObjectType({
|
||||
name: 'RoleTagType',
|
||||
fields: {
|
||||
name: {
|
||||
type: GraphQLString,
|
||||
description: 'Path to the resource'
|
||||
},
|
||||
roleTag: {
|
||||
type: new GraphQLList(GraphQLString),
|
||||
description: 'The role name',
|
||||
resolve: root => {
|
||||
return root['role-tag'] || root.roleTag;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
@ -1,13 +0,0 @@
|
||||
const { GraphQLString, GraphQLObjectType } = require('graphql');
|
||||
|
||||
module.exports = new GraphQLObjectType({
|
||||
name: 'ServiceType',
|
||||
fields: {
|
||||
name: {
|
||||
type: GraphQLString
|
||||
},
|
||||
url: {
|
||||
type: GraphQLString
|
||||
}
|
||||
}
|
||||
});
|
@ -1,16 +0,0 @@
|
||||
const { GraphQLString, GraphQLObjectType, GraphQLID } = require('graphql');
|
||||
|
||||
module.exports = new GraphQLObjectType({
|
||||
name: 'SnapshotType',
|
||||
description: 'Policies are lists of rules that describe access to resources',
|
||||
fields: {
|
||||
name: {
|
||||
type: GraphQLID,
|
||||
description: 'The name of this snapshot'
|
||||
},
|
||||
state: {
|
||||
type: GraphQLString,
|
||||
description: 'The current state of the snapshot'
|
||||
}
|
||||
}
|
||||
});
|
122
packages/cloudapi-gql/src/server.js
Normal file
122
packages/cloudapi-gql/src/server.js
Normal file
@ -0,0 +1,122 @@
|
||||
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}`);
|
||||
});
|
||||
}
|
||||
);
|
@ -31,13 +31,13 @@ const Firewall = ({
|
||||
/>
|
||||
));
|
||||
|
||||
const _error = !(error && !_loading) ? null : (
|
||||
const _error = (error && !values.length && !_loading) ? (
|
||||
<Message
|
||||
title="Ooops!"
|
||||
message="An error occurred while loading your instance firewall rules"
|
||||
error
|
||||
/>
|
||||
);
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<ViewContainer center={Boolean(_loading)} main>
|
||||
|
@ -22,13 +22,13 @@ const List = ({ instances = [], loading = false, error }) => {
|
||||
const _instances = forceArray(instances);
|
||||
const _loading = !instances.length && loading;
|
||||
|
||||
const _error = !error ? null : (
|
||||
const _error = (error && !_instances.length && !_loading) ? (
|
||||
<Message
|
||||
title="Ooops!"
|
||||
message="An error occurred while loading your instances."
|
||||
error
|
||||
/>
|
||||
);
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<ViewContainer main>
|
||||
|
@ -36,20 +36,21 @@ const MetadataForms = (metadata = []) =>
|
||||
});
|
||||
|
||||
const Metadata = ({ metadata = [], loading, error }) => {
|
||||
const values = forceArray(metadata);
|
||||
const _title = <Title>Metadata</Title>;
|
||||
const _loading = !(loading && !forceArray(metadata).length) ? null : (
|
||||
const _loading = !(loading && !values.length) ? null : (
|
||||
<StatusLoader />
|
||||
);
|
||||
|
||||
const _metadata = !_loading && MetadataForms(metadata);
|
||||
const _metadata = !_loading && MetadataForms(values);
|
||||
|
||||
const _error = !(error && !_loading) ? null : (
|
||||
const _error = (error && !values.length && !_loading) ? (
|
||||
<Message
|
||||
title="Ooops!"
|
||||
message="An error occurred while loading your instance metadata"
|
||||
error
|
||||
/>
|
||||
);
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<ViewContainer center={Boolean(_loading)} main>
|
||||
|
@ -26,13 +26,13 @@ const Networks = ({ networks = [], loading, error }) => {
|
||||
/>
|
||||
));
|
||||
|
||||
const _error = !(error && !_loading) ? null : (
|
||||
const _error = (error && !values.length && !_loading) ? (
|
||||
<Message
|
||||
title="Ooops!"
|
||||
message="An error occurred while loading your instance networks"
|
||||
error
|
||||
/>
|
||||
);
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<ViewContainer center={Boolean(_loading)} main>
|
||||
|
@ -36,20 +36,21 @@ const TagForms = (tags = []) =>
|
||||
});
|
||||
|
||||
const Tags = ({ tags = [], loading, error }) => {
|
||||
const values = forceArray(tags);
|
||||
const _title = <Title>Tags</Title>;
|
||||
const _loading = !(loading && !forceArray(tags).length) ? null : (
|
||||
const _loading = (loading && !values.length) ? (
|
||||
<StatusLoader />
|
||||
);
|
||||
) : null;
|
||||
|
||||
const _tags = !_loading && TagForms(tags);
|
||||
|
||||
const _error = !(error && !_loading) ? null : (
|
||||
const _error = (error && !values.length && !_loading) ? (
|
||||
<Message
|
||||
title="Ooops!"
|
||||
message="An error occurred while loading your instance tags"
|
||||
error
|
||||
/>
|
||||
);
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<ViewContainer center={Boolean(_loading)} main>
|
||||
|
Loading…
Reference in New Issue
Block a user