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:
Sérgio Ramos 2017-10-03 11:57:18 +01:00 committed by Sérgio Ramos
parent b64f345e13
commit ed4ce42237
79 changed files with 3178 additions and 3101 deletions

View File

@ -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",

View File

@ -1,2 +1,3 @@
.nyc_output
coverage
coverage
doc

View File

@ -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
View File

@ -0,0 +1 @@
doc

View File

@ -0,0 +1,8 @@
{
"schemaPath": "src/schema/schema.graphql",
"extensions": {
"endpoints": {
"dev": "http://localhost:4000/graphql"
}
}
}

View File

@ -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

View File

@ -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/*"
]
}
}

View File

@ -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);

View File

@ -1,5 +1,3 @@
// Const request = require('./request');
const { fetch } = require('./request');
module.exports.get = () => {
// Return request('', ctx);
};
module.exports = () => fetch('/:login/config');

View File

@ -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}`);

View 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!"
}

View File

@ -1,9 +0,0 @@
const request = require('./request');
module.exports.list = () => {
return request('listFirewallRules', {});
};
module.exports.get = ctx => {
return request('getFirewallRule', ctx);
};

View File

@ -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);

View File

@ -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);

View File

@ -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')
};

View 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
}),
{}
);

View File

@ -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' });

View File

@ -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;

View File

@ -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('');

View File

@ -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('');

View File

@ -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);

View File

@ -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);

View File

@ -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;
});
};

View File

@ -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);

View File

@ -1,5 +1,3 @@
const request = require('./request');
module.exports = () => {
return request('listServices');
};
module.exports = () => request('listServices');

View File

@ -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);

View 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'
});

View File

@ -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
// }));
//
//

View File

@ -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`);
});

View File

@ -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;

View File

@ -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
})
);
});
}
};

View File

@ -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);
}
};

View File

@ -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);
}
};

View File

@ -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')
)
});

View File

@ -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;
});
}
};

View File

@ -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);
}
};

View File

@ -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;
});
}
};

View File

@ -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);
}
};

View File

@ -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);
}
};

View File

@ -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);
// }
// };

View File

@ -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
});
});
}
};

View File

@ -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
};
});
});
}
};

View File

@ -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();
}
};

View File

@ -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();
}
};

View File

@ -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);
}
};

View File

@ -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')
}
});

View File

@ -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);
}
};

View File

@ -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();
}
};

View File

@ -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();
}
};

View File

@ -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);
}
};

View File

@ -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();
}
};

View File

@ -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();
}
};

View File

@ -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
};
});
});
}
};

View File

@ -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();
}
};

View 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;

File diff suppressed because it is too large Load Diff

View File

@ -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'
}
}
});

View File

@ -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
}
}
});

View File

@ -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
});

View File

@ -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'
}
}
});

View File

@ -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
});
}
}
})
});

View File

@ -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>"}'
}
}
});

View File

@ -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
}
}
});

View File

@ -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'
}
}
});

View File

@ -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)
}
}
});

View File

@ -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);
}
}
}
});

View File

@ -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)"
}
}
});

View File

@ -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'
}
}
});

View File

@ -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'
}
}
});

View File

@ -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;
}
}
}
});

View File

@ -1,13 +0,0 @@
const { GraphQLString, GraphQLObjectType } = require('graphql');
module.exports = new GraphQLObjectType({
name: 'ServiceType',
fields: {
name: {
type: GraphQLString
},
url: {
type: GraphQLString
}
}
});

View File

@ -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'
}
}
});

View 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}`);
});
}
);

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

1798
yarn.lock

File diff suppressed because it is too large Load Diff