From dd718e1135e3221e4bed122c1e66b2c8a7f1fd34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81rgio=20Ramos?= Date: Mon, 10 Oct 2016 16:37:26 +0100 Subject: [PATCH] Initial commit --- triton-graphql/.eslintrc | 13 + triton-graphql/.gitignore | 50 +++ triton-graphql/README.md | 144 ++++++++ triton-graphql/package.json | 25 ++ triton-graphql/src/api/account.js | 9 + triton-graphql/src/api/config.js | 5 + triton-graphql/src/api/datacenters.js | 5 + triton-graphql/src/api/fabrics.js | 9 + triton-graphql/src/api/firewall-rules.js | 37 ++ triton-graphql/src/api/images.js | 25 ++ triton-graphql/src/api/index.js | 16 + triton-graphql/src/api/keys.js | 35 ++ triton-graphql/src/api/machines.js | 108 ++++++ triton-graphql/src/api/networks.js | 9 + triton-graphql/src/api/nics.js | 9 + triton-graphql/src/api/packages.js | 9 + triton-graphql/src/api/policies.js | 21 ++ triton-graphql/src/api/request.js | 40 +++ triton-graphql/src/api/roles.js | 31 ++ triton-graphql/src/api/services.js | 5 + triton-graphql/src/api/users.js | 21 ++ triton-graphql/src/index.js | 20 ++ triton-graphql/src/schema/index.js | 12 + .../src/schema/mutations/account.js | 57 +++ .../src/schema/mutations/firewall-rules.js | 102 ++++++ triton-graphql/src/schema/mutations/images.js | 56 +++ triton-graphql/src/schema/mutations/index.js | 18 + triton-graphql/src/schema/mutations/keys.js | 53 +++ .../src/schema/mutations/machines.js | 328 ++++++++++++++++++ .../src/schema/mutations/policies.js | 71 ++++ triton-graphql/src/schema/mutations/roles.js | 105 ++++++ .../src/schema/mutations/snapshots.js | 73 ++++ triton-graphql/src/schema/mutations/users.js | 144 ++++++++ triton-graphql/src/schema/queries/account.js | 13 + .../src/schema/queries/datacenters.js | 21 ++ triton-graphql/src/schema/queries/fabrics.js | 14 + .../src/schema/queries/firewall-rules.js | 26 ++ triton-graphql/src/schema/queries/images.js | 58 ++++ triton-graphql/src/schema/queries/index.js | 22 ++ triton-graphql/src/schema/queries/machines.js | 83 +++++ triton-graphql/src/schema/queries/networks.js | 25 ++ triton-graphql/src/schema/queries/nics.js | 25 ++ triton-graphql/src/schema/queries/packages.js | 62 ++++ triton-graphql/src/schema/queries/policies.js | 26 ++ triton-graphql/src/schema/queries/roles.js | 26 ++ triton-graphql/src/schema/queries/services.js | 21 ++ triton-graphql/src/schema/queries/users.js | 30 ++ triton-graphql/src/schema/types/audit.js | 58 ++++ triton-graphql/src/schema/types/datacenter.js | 17 + .../src/schema/types/dynamic-object.js | 44 +++ triton-graphql/src/schema/types/fabric.js | 23 ++ .../src/schema/types/firewall-rule.js | 93 +++++ triton-graphql/src/schema/types/image.js | 116 +++++++ triton-graphql/src/schema/types/key.js | 19 + triton-graphql/src/schema/types/login.js | 111 ++++++ triton-graphql/src/schema/types/machine.js | 169 +++++++++ triton-graphql/src/schema/types/network.js | 73 ++++ triton-graphql/src/schema/types/nic.js | 43 +++ triton-graphql/src/schema/types/package.js | 52 +++ triton-graphql/src/schema/types/policy.js | 29 ++ triton-graphql/src/schema/types/role.js | 50 +++ triton-graphql/src/schema/types/service.js | 16 + triton-graphql/src/schema/types/snapshot.js | 20 ++ triton-graphql/static/.gitkeep | 0 64 files changed, 3050 insertions(+) create mode 100644 triton-graphql/.eslintrc create mode 100644 triton-graphql/.gitignore create mode 100644 triton-graphql/README.md create mode 100644 triton-graphql/package.json create mode 100644 triton-graphql/src/api/account.js create mode 100644 triton-graphql/src/api/config.js create mode 100644 triton-graphql/src/api/datacenters.js create mode 100644 triton-graphql/src/api/fabrics.js create mode 100644 triton-graphql/src/api/firewall-rules.js create mode 100644 triton-graphql/src/api/images.js create mode 100644 triton-graphql/src/api/index.js create mode 100644 triton-graphql/src/api/keys.js create mode 100644 triton-graphql/src/api/machines.js create mode 100644 triton-graphql/src/api/networks.js create mode 100644 triton-graphql/src/api/nics.js create mode 100644 triton-graphql/src/api/packages.js create mode 100644 triton-graphql/src/api/policies.js create mode 100644 triton-graphql/src/api/request.js create mode 100644 triton-graphql/src/api/roles.js create mode 100644 triton-graphql/src/api/services.js create mode 100644 triton-graphql/src/api/users.js create mode 100644 triton-graphql/src/index.js create mode 100644 triton-graphql/src/schema/index.js create mode 100644 triton-graphql/src/schema/mutations/account.js create mode 100644 triton-graphql/src/schema/mutations/firewall-rules.js create mode 100644 triton-graphql/src/schema/mutations/images.js create mode 100644 triton-graphql/src/schema/mutations/index.js create mode 100644 triton-graphql/src/schema/mutations/keys.js create mode 100644 triton-graphql/src/schema/mutations/machines.js create mode 100644 triton-graphql/src/schema/mutations/policies.js create mode 100644 triton-graphql/src/schema/mutations/roles.js create mode 100644 triton-graphql/src/schema/mutations/snapshots.js create mode 100644 triton-graphql/src/schema/mutations/users.js create mode 100644 triton-graphql/src/schema/queries/account.js create mode 100644 triton-graphql/src/schema/queries/datacenters.js create mode 100644 triton-graphql/src/schema/queries/fabrics.js create mode 100644 triton-graphql/src/schema/queries/firewall-rules.js create mode 100644 triton-graphql/src/schema/queries/images.js create mode 100644 triton-graphql/src/schema/queries/index.js create mode 100644 triton-graphql/src/schema/queries/machines.js create mode 100644 triton-graphql/src/schema/queries/networks.js create mode 100644 triton-graphql/src/schema/queries/nics.js create mode 100644 triton-graphql/src/schema/queries/packages.js create mode 100644 triton-graphql/src/schema/queries/policies.js create mode 100644 triton-graphql/src/schema/queries/roles.js create mode 100644 triton-graphql/src/schema/queries/services.js create mode 100644 triton-graphql/src/schema/queries/users.js create mode 100644 triton-graphql/src/schema/types/audit.js create mode 100644 triton-graphql/src/schema/types/datacenter.js create mode 100644 triton-graphql/src/schema/types/dynamic-object.js create mode 100644 triton-graphql/src/schema/types/fabric.js create mode 100644 triton-graphql/src/schema/types/firewall-rule.js create mode 100644 triton-graphql/src/schema/types/image.js create mode 100644 triton-graphql/src/schema/types/key.js create mode 100644 triton-graphql/src/schema/types/login.js create mode 100644 triton-graphql/src/schema/types/machine.js create mode 100644 triton-graphql/src/schema/types/network.js create mode 100644 triton-graphql/src/schema/types/nic.js create mode 100644 triton-graphql/src/schema/types/package.js create mode 100644 triton-graphql/src/schema/types/policy.js create mode 100644 triton-graphql/src/schema/types/role.js create mode 100644 triton-graphql/src/schema/types/service.js create mode 100644 triton-graphql/src/schema/types/snapshot.js create mode 100644 triton-graphql/static/.gitkeep diff --git a/triton-graphql/.eslintrc b/triton-graphql/.eslintrc new file mode 100644 index 00000000..d1411ab2 --- /dev/null +++ b/triton-graphql/.eslintrc @@ -0,0 +1,13 @@ +{ + "extends": "semistandard", + "rules": { + "no-unused-vars": "error", + "space-before-function-paren": [2, "never"], + "object-curly-newline": ["error", { + "minProperties": 1 + }], + "sort-vars": ["error", { + "ignoreCase": true + }] + } +} diff --git a/triton-graphql/.gitignore b/triton-graphql/.gitignore new file mode 100644 index 00000000..7f3fff9f --- /dev/null +++ b/triton-graphql/.gitignore @@ -0,0 +1,50 @@ +# Logs +logs +*.log +npm-debug.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules +jspm_packages + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Vim files: +*.sw* + +# Mac OS dirty files +.DS_Store diff --git a/triton-graphql/README.md b/triton-graphql/README.md new file mode 100644 index 00000000..72d0ebcf --- /dev/null +++ b/triton-graphql/README.md @@ -0,0 +1,144 @@ +# triton-graphql + +Proof-of-Concept of the Triton API running on GraphQL. + +### install dependencies + +```bash +$ npm install +``` + +### setup credentials + +Edit `credentials.json` + +```json +{ + "url": "https://us-sw-1.api.joyentcloud.com", + "keyId": "", //public key fingerprint ex: 35:jh:42:56... + "account": "", // account ex: raoulmillais + "user": "" // sub-account ex: ramitos +} +``` + +## api + + - [x] Account + - [x] GetAccount + - [x] UpdateAccount + - [x] Keys + - [x] ListKeys + - [x] GetKey + - [x] CreateKey + - [x] DeleteKey + - [x] Users + - [x] ListUsers + - [x] GetUser + - [x] CreateUser + - [x] UpdateUser + - [-] ChangeUserPassword + - [x] DeleteUser + - [x] Roles + - [x] ListRoles + - [x] GetRole + - [x] CreateRole + - [x] UpdateRole + - [x] DeleteRole + - [x] Role Tags + - [x] SetRoleTags + - [x] Policies + - [x] ListPolicies + - [x] GetPolicy + - [x] CreatePolicy + - [x] UpdatePolicy + - [x] DeletePolicy + - [x] User SSH Keys + - [x] ListUserKeys + - [x] GetUserKey + - [x] CreateUserKey + - [x] DeleteUserKey + - [-] Config + - [-] GetConfig + - [-] UpdateConfig + - [x] Datacenters + - [x] ListDatacenters + - [x] GetDatacenter + - [x] Services + - [x] ListServices + - [x] Images + - [x] ListImages + - [x] GetImage + - [x] DeleteImage + - [x] ExportImage + - [x] CreateImageFromMachine + - [-] UpdateImage + - [x] Packages + - [x] ListPackages + - [x] GetPackage + - [x] Instances + - [x] ListMachines + - [x] GetMachine + - [x] CreateMachine + - [x] StopMachine + - [x] StartMachine + - [x] RebootMachine + - [-] ResizeMachine + - [-] RenameMachine + - [x] EnableMachineFirewall + - [x] DisableMachineFirewall + - [x] CreateMachineSnapshot + - [x] StartMachineFromSnapshot + - [x] ListMachineSnapshots + - [x] GetMachineSnapshot + - [x] DeleteMachineSnapshot + - [-] UpdateMachineMetadata + - [-] ListMachineMetadata + - [-] GetMachineMetadata + - [-] DeleteMachineMetadata + - [-] DeleteAllMachineMetadata + - [x] AddMachineTags + - [x] ReplaceMachineTags + - [ ] ListMachineTags + - [x] GetMachineTag + - [x] DeleteMachineTag + - [x] DeleteMachineTags + - [x] DeleteMachine + - [x] MachineAudit + - [-] Analytics + - [-] DescribeAnalytics + - [-] ListInstrumentations + - [-] GetInstrumentation + - [-] GetInstrumentationValue + - [-] GetInstrumentationHeatmap + - [-] GetInstrumentationHeatmapDetails + - [-] CreateInstrumentation + - [-] DeleteInstrumentation + - [x] FirewallRules + - [x] Firewall Rule Syntax + - [x] ListFirewallRules + - [x] GetFirewallRule + - [x] CreateFirewallRule + - [x] UpdateFirewallRule + - [x] EnableFirewallRule + - [x] DisableFirewallRule + - [x] DeleteFirewallRule + - [x] ListMachineFirewallRules + - [x] ListFirewallRuleMachines + - [-] Fabrics + - [-] ListFabricVLANs + - [-] CreateFabricVLAN + - [-] GetFabricVLAN + - [-] UpdateFabricVLAN + - [-] DeleteFabricVLAN + - [-] ListFabricNetworks + - [-] CreateFabricNetwork + - [-] GetFabricNetwork + - [-] DeleteFabricNetwork + - [x] Networks + - [x] ListNetworks + - [x] GetNetwork + - [-] Nics + - [-] ListNics + - [-] GetNic + - [-] AddNic + - [-] RemoveNic \ No newline at end of file diff --git a/triton-graphql/package.json b/triton-graphql/package.json new file mode 100644 index 00000000..1a609697 --- /dev/null +++ b/triton-graphql/package.json @@ -0,0 +1,25 @@ +{ + "name": "triton-graphql", + "private": true, + "license": "Apache-2.0", + "version": "1.0.0", + "main": "src/index.js", + "dependencies": { + "bunyan": "^1.8.1", + "express": "^4.14.0", + "express-graphql": "^0.5.4", + "got": "^6.5.0", + "graphql": "^0.7.1", + "moment": "^2.15.1", + "smartdc-auth": "^2.5.2", + "triton": "^4.14.0", + "user-home": "^2.0.0" + }, + "devDependencies": { + "eslint": "3.7.0", + "eslint-config-semistandard": "^7.0.0", + "eslint-config-standard": "^6.2.0", + "eslint-plugin-promise": "^2.0.1", + "eslint-plugin-standard": "^2.0.1" + } +} diff --git a/triton-graphql/src/api/account.js b/triton-graphql/src/api/account.js new file mode 100644 index 00000000..584c0ac5 --- /dev/null +++ b/triton-graphql/src/api/account.js @@ -0,0 +1,9 @@ +const request = require('./request'); + +module.exports.get = () => { + return request('getAccount'); +}; + +module.exports.update = (ctx) => { + return request('updateAccount', ctx); +}; diff --git a/triton-graphql/src/api/config.js b/triton-graphql/src/api/config.js new file mode 100644 index 00000000..e54bb6a8 --- /dev/null +++ b/triton-graphql/src/api/config.js @@ -0,0 +1,5 @@ +// const request = require('./request'); + +module.exports.get = (ctx) => { + // return request('', ctx); +}; diff --git a/triton-graphql/src/api/datacenters.js b/triton-graphql/src/api/datacenters.js new file mode 100644 index 00000000..7aafe965 --- /dev/null +++ b/triton-graphql/src/api/datacenters.js @@ -0,0 +1,5 @@ +const request = require('./request'); + +module.exports = () => { + return request('listDatacenters'); +}; diff --git a/triton-graphql/src/api/fabrics.js b/triton-graphql/src/api/fabrics.js new file mode 100644 index 00000000..2d1f4779 --- /dev/null +++ b/triton-graphql/src/api/fabrics.js @@ -0,0 +1,9 @@ +const request = require('./request'); + +module.exports.list = () => { + return request('listFirewallRules', {}); +}; + +module.exports.get = (ctx) => { + return request('getFirewallRule', ctx); +}; diff --git a/triton-graphql/src/api/firewall-rules.js b/triton-graphql/src/api/firewall-rules.js new file mode 100644 index 00000000..84b816e3 --- /dev/null +++ b/triton-graphql/src/api/firewall-rules.js @@ -0,0 +1,37 @@ +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); +}; diff --git a/triton-graphql/src/api/images.js b/triton-graphql/src/api/images.js new file mode 100644 index 00000000..ab947d60 --- /dev/null +++ b/triton-graphql/src/api/images.js @@ -0,0 +1,25 @@ +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); +// }; diff --git a/triton-graphql/src/api/index.js b/triton-graphql/src/api/index.js new file mode 100644 index 00000000..7b3d24dd --- /dev/null +++ b/triton-graphql/src/api/index.js @@ -0,0 +1,16 @@ +module.exports = { + account: require('./account'), + users: require('./users'), + policies: require('./policies'), + roles: require('./roles'), + keys: require('./keys'), + 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') +}; diff --git a/triton-graphql/src/api/keys.js b/triton-graphql/src/api/keys.js new file mode 100644 index 00000000..36cee16b --- /dev/null +++ b/triton-graphql/src/api/keys.js @@ -0,0 +1,35 @@ +const request = 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', {}); + }, + + get: (ctx) => { + return request('getKey', ctx); + }, + + create: (ctx) => { + return request('createKey', ctx); + }, + + destroy: (ctx) => { + return request('deleteKey', ctx); + } + } +}; diff --git a/triton-graphql/src/api/machines.js b/triton-graphql/src/api/machines.js new file mode 100644 index 00000000..4532831b --- /dev/null +++ b/triton-graphql/src/api/machines.js @@ -0,0 +1,108 @@ +const request = require('./request'); + +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); + } +}; + +const metadata = { + list: (ctx) => { + return request('', ctx); + }, + get: (ctx) => { + return request('', ctx); + }, + update: (ctx) => { + return request('', ctx); + }, + destroy: (ctx) => { + return request('', ctx); + } +}; + +const firewall = { + enable: (ctx) => { + return request('enableMachineFirewall', ctx); + }, + disable: (ctx) => { + return 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); + } +}; + +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.snapshots = snapshots; +module.exports.metadata = metadata; +module.exports.firewall = firewall; +module.exports.tags = tags; diff --git a/triton-graphql/src/api/networks.js b/triton-graphql/src/api/networks.js new file mode 100644 index 00000000..1a153089 --- /dev/null +++ b/triton-graphql/src/api/networks.js @@ -0,0 +1,9 @@ +const request = require('./request'); + +module.exports.list = () => { + return request('listNetworks'); +}; + +module.exports.get = (ctx) => { + return request('getNetwork', ctx); +}; diff --git a/triton-graphql/src/api/nics.js b/triton-graphql/src/api/nics.js new file mode 100644 index 00000000..d64cf87d --- /dev/null +++ b/triton-graphql/src/api/nics.js @@ -0,0 +1,9 @@ +const request = require('./request'); + +module.exports.list = () => { + return request('listNics'); +}; + +module.exports.get = (ctx) => { + return request('getNic', ctx); +}; diff --git a/triton-graphql/src/api/packages.js b/triton-graphql/src/api/packages.js new file mode 100644 index 00000000..425815b1 --- /dev/null +++ b/triton-graphql/src/api/packages.js @@ -0,0 +1,9 @@ +const request = require('./request'); + +module.exports.list = (ctx) => { + return request('listPackages', ctx); +}; + +module.exports.get = (ctx) => { + return request('getPackage', ctx); +}; diff --git a/triton-graphql/src/api/policies.js b/triton-graphql/src/api/policies.js new file mode 100644 index 00000000..205b984d --- /dev/null +++ b/triton-graphql/src/api/policies.js @@ -0,0 +1,21 @@ +const request = require('./request'); + +module.exports.list = (ctx) => { + 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); +}; diff --git a/triton-graphql/src/api/request.js b/triton-graphql/src/api/request.js new file mode 100644 index 00000000..bc76ad5c --- /dev/null +++ b/triton-graphql/src/api/request.js @@ -0,0 +1,40 @@ +const credentials = require('../../credentials.json'); + +const auth = require('smartdc-auth'); +const cloudapi = require('triton/lib/cloudapi2'); +const bunyan = require('bunyan'); + +var log = bunyan.createLogger({ + name: 'triton-graphql' +}); + +var client = cloudapi.createClient({ + log: log, + url: credentials.url, + account: credentials.account, + user: credentials.user, + sign: auth.cliSigner({ + log: log, + keyId: credentials.keyId, + user: credentials.account, + subuser: credentials.user + }) +}); + +module.exports = (method, args) => { + return new Promise((resolve, reject) => { + const fn = client[method].bind(client); + + const cb = (err, res) => { + if (err) { + return reject(err); + } + + resolve(res); + }; + + return args ? fn(args, cb) : fn(cb); + }); +}; + +module.exports.client = client; diff --git a/triton-graphql/src/api/roles.js b/triton-graphql/src/api/roles.js new file mode 100644 index 00000000..6ad5c0c1 --- /dev/null +++ b/triton-graphql/src/api/roles.js @@ -0,0 +1,31 @@ +const request = require('./request'); + +module.exports.list = (ctx) => { + return request('listRoles'); +}; + +module.exports.get = (ctx) => { + return request('getRole', ctx); +}; + +module.exports.create = (ctx) => { + return request('createRole', ctx); +}; + +module.exports.set = (ctx) => { + const id = ctx.id ? `/${id}` : ''; + const resource = `/${request.client.account}/${ctx.resource}${id}`; + + return request('setRoleTags', { + roleTags: ctx.role, + resource + }); +}; + +module.exports.update = (ctx) => { + return request('updateRole', ctx); +}; + +module.exports.destroy = (ctx) => { + return request('deleteRole', ctx); +}; diff --git a/triton-graphql/src/api/services.js b/triton-graphql/src/api/services.js new file mode 100644 index 00000000..5cad9529 --- /dev/null +++ b/triton-graphql/src/api/services.js @@ -0,0 +1,5 @@ +const request = require('./request'); + +module.exports = () => { + return request('listServices'); +}; diff --git a/triton-graphql/src/api/users.js b/triton-graphql/src/api/users.js new file mode 100644 index 00000000..9ec8842b --- /dev/null +++ b/triton-graphql/src/api/users.js @@ -0,0 +1,21 @@ +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); +}; diff --git a/triton-graphql/src/index.js b/triton-graphql/src/index.js new file mode 100644 index 00000000..f20231be --- /dev/null +++ b/triton-graphql/src/index.js @@ -0,0 +1,20 @@ +const express = require('express'); +const graphqlHTTP = require('express-graphql'); +const schema = require('./schema'); + +const app = express(); + +app.use('/graphql', graphqlHTTP(() => ({ + schema: schema, + graphiql: true, + pretty: true +}))); + +app.listen(3000, (err) => { + if (err) { + console.log(err); + throw err; + } + + console.log('Listening at localhost:3000'); +}); diff --git a/triton-graphql/src/schema/index.js b/triton-graphql/src/schema/index.js new file mode 100644 index 00000000..6a328ec7 --- /dev/null +++ b/triton-graphql/src/schema/index.js @@ -0,0 +1,12 @@ +const graphql = require('graphql'); +const mutation = require('./mutations'); +const query = require('./queries'); + +const { + GraphQLSchema +} = graphql; + +module.exports = new GraphQLSchema({ + query, + mutation +}); diff --git a/triton-graphql/src/schema/mutations/account.js b/triton-graphql/src/schema/mutations/account.js new file mode 100644 index 00000000..9a2374ca --- /dev/null +++ b/triton-graphql/src/schema/mutations/account.js @@ -0,0 +1,57 @@ +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 + }, + company_name: { + type: GraphQLString + }, + first_name: { + type: GraphQLString + }, + last_name: { + type: GraphQLString + }, + address: { + type: GraphQLString + }, + postal_code: { + type: GraphQLString + }, + city: { + type: GraphQLString + }, + state: { + type: GraphQLString + }, + country: { + type: GraphQLString + }, + phone: { + type: GraphQLString + }, + cns_enabled: { + type: GraphQLBoolean + } + }, + resolve: (root, args) => { + return api.account.get().then((account) => { + return api.account.update(Object.assign(account, args, { + firstName: args.first_name || account.firstName, + lastName: args.first_name || account.lastName, + companyName: args.company_name || account.companyName, + postalCode: args.postal_code || account.postalCode + })); + }); + } +}; diff --git a/triton-graphql/src/schema/mutations/firewall-rules.js b/triton-graphql/src/schema/mutations/firewall-rules.js new file mode 100644 index 00000000..e90e4244 --- /dev/null +++ b/triton-graphql/src/schema/mutations/firewall-rules.js @@ -0,0 +1,102 @@ +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: !!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); + } +}; diff --git a/triton-graphql/src/schema/mutations/images.js b/triton-graphql/src/schema/mutations/images.js new file mode 100644 index 00000000..49aa29e8 --- /dev/null +++ b/triton-graphql/src/schema/mutations/images.js @@ -0,0 +1,56 @@ +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); + } +}; diff --git a/triton-graphql/src/schema/mutations/index.js b/triton-graphql/src/schema/mutations/index.js new file mode 100644 index 00000000..b3ce7b63 --- /dev/null +++ b/triton-graphql/src/schema/mutations/index.js @@ -0,0 +1,18 @@ +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') + ) +}); diff --git a/triton-graphql/src/schema/mutations/keys.js b/triton-graphql/src/schema/mutations/keys.js new file mode 100644 index 00000000..af90d609 --- /dev/null +++ b/triton-graphql/src/schema/mutations/keys.js @@ -0,0 +1,53 @@ +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; + }); + } +}; diff --git a/triton-graphql/src/schema/mutations/machines.js b/triton-graphql/src/schema/mutations/machines.js new file mode 100644 index 00000000..da4cb685 --- /dev/null +++ b/triton-graphql/src/schema/mutations/machines.js @@ -0,0 +1,328 @@ +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' + }, + firewall_enabled: { + 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, + firewall_enabled: args.firewall_enabled + }, 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); + } +}; diff --git a/triton-graphql/src/schema/mutations/policies.js b/triton-graphql/src/schema/mutations/policies.js new file mode 100644 index 00000000..59daa97a --- /dev/null +++ b/triton-graphql/src/schema/mutations/policies.js @@ -0,0 +1,71 @@ +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; + }); + } +}; diff --git a/triton-graphql/src/schema/mutations/roles.js b/triton-graphql/src/schema/mutations/roles.js new file mode 100644 index 00000000..536e31cf --- /dev/null +++ b/triton-graphql/src/schema/mutations/roles.js @@ -0,0 +1,105 @@ +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)' + }, + default_members: { + 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)' + }, + default_members: { + 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); + } +}; diff --git a/triton-graphql/src/schema/mutations/snapshots.js b/triton-graphql/src/schema/mutations/snapshots.js new file mode 100644 index 00000000..5842795f --- /dev/null +++ b/triton-graphql/src/schema/mutations/snapshots.js @@ -0,0 +1,73 @@ +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); + } +}; diff --git a/triton-graphql/src/schema/mutations/users.js b/triton-graphql/src/schema/mutations/users.js new file mode 100644 index 00000000..02e9cb6c --- /dev/null +++ b/triton-graphql/src/schema/mutations/users.js @@ -0,0 +1,144 @@ +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) + }, + company_name: { + type: GraphQLString + }, + first_name: { + type: GraphQLString + }, + last_name: { + type: GraphQLString + }, + address: { + type: GraphQLString + }, + postal_code: { + 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.first_name, + lastName: args.first_name, + companyName: args.company_name, + postalCode: args.postal_code + })); + } +}; + +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 + }, + company_name: { + type: GraphQLString + }, + first_name: { + type: GraphQLString + }, + last_name: { + type: GraphQLString + }, + address: { + type: GraphQLString + }, + postal_code: { + 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.first_name, + lastName: args.first_name, + companyName: args.company_name, + postalCode: args.postal_code + })); + } +}; + +// 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); +// } +// }; diff --git a/triton-graphql/src/schema/queries/account.js b/triton-graphql/src/schema/queries/account.js new file mode 100644 index 00000000..61b9b5fe --- /dev/null +++ b/triton-graphql/src/schema/queries/account.js @@ -0,0 +1,13 @@ +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 + }); + }); + } +}; diff --git a/triton-graphql/src/schema/queries/datacenters.js b/triton-graphql/src/schema/queries/datacenters.js new file mode 100644 index 00000000..f62646b3 --- /dev/null +++ b/triton-graphql/src/schema/queries/datacenters.js @@ -0,0 +1,21 @@ +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 + }; + }); + }); + } +}; diff --git a/triton-graphql/src/schema/queries/fabrics.js b/triton-graphql/src/schema/queries/fabrics.js new file mode 100644 index 00000000..95b635e8 --- /dev/null +++ b/triton-graphql/src/schema/queries/fabrics.js @@ -0,0 +1,14 @@ +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(); + } +}; diff --git a/triton-graphql/src/schema/queries/firewall-rules.js b/triton-graphql/src/schema/queries/firewall-rules.js new file mode 100644 index 00000000..50ae70a6 --- /dev/null +++ b/triton-graphql/src/schema/queries/firewall-rules.js @@ -0,0 +1,26 @@ +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 ? list() : get(args.id).then((rule) => [rule]); + } +}; diff --git a/triton-graphql/src/schema/queries/images.js b/triton-graphql/src/schema/queries/images.js new file mode 100644 index 00000000..c33ac548 --- /dev/null +++ b/triton-graphql/src/schema/queries/images.js @@ -0,0 +1,58 @@ +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); + } +}; diff --git a/triton-graphql/src/schema/queries/index.js b/triton-graphql/src/schema/queries/index.js new file mode 100644 index 00000000..1cd08897 --- /dev/null +++ b/triton-graphql/src/schema/queries/index.js @@ -0,0 +1,22 @@ +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') + } +}); diff --git a/triton-graphql/src/schema/queries/machines.js b/triton-graphql/src/schema/queries/machines.js new file mode 100644 index 00000000..36bf7c6a --- /dev/null +++ b/triton-graphql/src/schema/queries/machines.js @@ -0,0 +1,83 @@ +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, ctx) { + 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); + } +}; diff --git a/triton-graphql/src/schema/queries/networks.js b/triton-graphql/src/schema/queries/networks.js new file mode 100644 index 00000000..ce0e5312 --- /dev/null +++ b/triton-graphql/src/schema/queries/networks.js @@ -0,0 +1,25 @@ +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 ? list() : get(args).then((network) => [network]); + } +}; diff --git a/triton-graphql/src/schema/queries/nics.js b/triton-graphql/src/schema/queries/nics.js new file mode 100644 index 00000000..c1fcc1f3 --- /dev/null +++ b/triton-graphql/src/schema/queries/nics.js @@ -0,0 +1,25 @@ +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 ? list() : get(args).then((nic) => [nic]); + } +}; diff --git a/triton-graphql/src/schema/queries/packages.js b/triton-graphql/src/schema/queries/packages.js new file mode 100644 index 00000000..645a0858 --- /dev/null +++ b/triton-graphql/src/schema/queries/packages.js @@ -0,0 +1,62 @@ +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); + } +}; diff --git a/triton-graphql/src/schema/queries/policies.js b/triton-graphql/src/schema/queries/policies.js new file mode 100644 index 00000000..ca72d1ae --- /dev/null +++ b/triton-graphql/src/schema/queries/policies.js @@ -0,0 +1,26 @@ +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 ? list() : get(args).then((policy) => [policy]); + } +}; diff --git a/triton-graphql/src/schema/queries/roles.js b/triton-graphql/src/schema/queries/roles.js new file mode 100644 index 00000000..965e1bf1 --- /dev/null +++ b/triton-graphql/src/schema/queries/roles.js @@ -0,0 +1,26 @@ +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 ? list() : get(args).then((role) => [role]); + } +}; diff --git a/triton-graphql/src/schema/queries/services.js b/triton-graphql/src/schema/queries/services.js new file mode 100644 index 00000000..709ba79f --- /dev/null +++ b/triton-graphql/src/schema/queries/services.js @@ -0,0 +1,21 @@ +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 + }; + }); + }); + } +}; diff --git a/triton-graphql/src/schema/queries/users.js b/triton-graphql/src/schema/queries/users.js new file mode 100644 index 00000000..698cfb41 --- /dev/null +++ b/triton-graphql/src/schema/queries/users.js @@ -0,0 +1,30 @@ +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, ctx) { + const { + list, + get + } = api.users; + + return !args.id ? list() : get(args).then((user) => [user]).then((user) => { + return Object.assign(user, { + isUser: true + }); + }); + } +}; diff --git a/triton-graphql/src/schema/types/audit.js b/triton-graphql/src/schema/types/audit.js new file mode 100644 index 00000000..5d044b78 --- /dev/null +++ b/triton-graphql/src/schema/types/audit.js @@ -0,0 +1,58 @@ +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' + } + } +}); diff --git a/triton-graphql/src/schema/types/datacenter.js b/triton-graphql/src/schema/types/datacenter.js new file mode 100644 index 00000000..febf5d8f --- /dev/null +++ b/triton-graphql/src/schema/types/datacenter.js @@ -0,0 +1,17 @@ +const { + GraphQLString, + GraphQLObjectType +} = require('graphql'); + +module.exports = new GraphQLObjectType({ + name: 'DatacenterType', + fields: { + name: { + type: GraphQLString, + description: 'location of the datacenter' + }, + url: { + type: GraphQLString + } + } +}); diff --git a/triton-graphql/src/schema/types/dynamic-object.js b/triton-graphql/src/schema/types/dynamic-object.js new file mode 100644 index 00000000..4f48cd0e --- /dev/null +++ b/triton-graphql/src/schema/types/dynamic-object.js @@ -0,0 +1,44 @@ +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: parseLiteral +}); diff --git a/triton-graphql/src/schema/types/fabric.js b/triton-graphql/src/schema/types/fabric.js new file mode 100644 index 00000000..13e9af6c --- /dev/null +++ b/triton-graphql/src/schema/types/fabric.js @@ -0,0 +1,23 @@ +const { + GraphQLString, + GraphQLObjectType, + GraphQLInt +} = require('graphql'); + +module.exports = new GraphQLObjectType({ + name: 'FabricsType', + fields: { + name: { + type: GraphQLString, + description: 'A unique name to identify the VLAN' + }, + vlan_id: { + type: GraphQLInt, + description: 'A number from 0-4095 that indicates the VLAN\'s id' + }, + description: { + type: GraphQLString, + description: 'An optional description of the VLAN' + } + } +}); diff --git a/triton-graphql/src/schema/types/firewall-rule.js b/triton-graphql/src/schema/types/firewall-rule.js new file mode 100644 index 00000000..68280444 --- /dev/null +++ b/triton-graphql/src/schema/types/firewall-rule.js @@ -0,0 +1,93 @@ +const MachineType = require('../types/machine'); +const api = require('../../api'); + +console.log(MachineType); + +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', + fields: { + id: { + type: GraphQLID, + description: 'Unique identifier for this rule' + }, + enabled: { + type: GraphQLBoolean, + description: 'Indicates if the rule is enabled', + resolve: (root) => { + return !!root.enabled; + } + }, + rule: { + type: FirewallRuleSyntaxType, + description: 'Firewall rule', + resolve: ({ + 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 !!root.global; + } + }, + description: { + type: GraphQLString, + description: 'Human-readable description for the rule' + } + // machines: { + // type: new GraphQLList(MachineType), + // description: 'Lists all instances a firewall rule is applied to', + // resolve: (root) => { + // return api.firewallRules.listMachines({ + // id: root.id + // }); + // } + // } + } +}); diff --git a/triton-graphql/src/schema/types/image.js b/triton-graphql/src/schema/types/image.js new file mode 100644 index 00000000..e6ad6ca0 --- /dev/null +++ b/triton-graphql/src/schema/types/image.js @@ -0,0 +1,116 @@ +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' + }, + published_at: { + 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 !!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": "", "message": ""}' + } + } +}); diff --git a/triton-graphql/src/schema/types/key.js b/triton-graphql/src/schema/types/key.js new file mode 100644 index 00000000..e117073f --- /dev/null +++ b/triton-graphql/src/schema/types/key.js @@ -0,0 +1,19 @@ +const { + GraphQLString, + GraphQLObjectType +} = require('graphql'); + +module.exports = new GraphQLObjectType({ + name: 'KeyType', + fields: { + name: { + type: GraphQLString + }, + fingerprint: { + type: GraphQLString + }, + key: { + type: GraphQLString + } + } +}); diff --git a/triton-graphql/src/schema/types/login.js b/triton-graphql/src/schema/types/login.js new file mode 100644 index 00000000..16cb31d4 --- /dev/null +++ b/triton-graphql/src/schema/types/login.js @@ -0,0 +1,111 @@ +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' + }, + company_name: { + type: GraphQLString, + resolve: (root) => { + return !!root.company_name || root.companyName; + } + }, + first_name: { + type: GraphQLString, + resolve: (root) => { + return !!root.first_name || root.firstName; + } + }, + last_name: { + type: GraphQLString, + resolve: (root) => { + return !!root.last_name || root.lastName; + } + }, + address: { + type: GraphQLString + }, + postal_code: { + type: GraphQLString, + resolve: (root) => { + return !!root.postal_code || root.postalCode; + } + }, + city: { + type: GraphQLString + }, + state: { + type: GraphQLString + }, + country: { + type: GraphQLString + }, + phone: { + type: GraphQLString + }, + cns_enabled: { + type: GraphQLBoolean, + description: 'true if Triton CNS is enabled for account', + resolve: (root) => { + return root.isUser ? null : !!root.triton_cns_enabled; + } + }, + 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 ? list(newArgs) : get(newArgs).then((key) => [key]); + } + }, + updated: { + type: GraphQLString, + description: 'When this user/account\'s details was last updated' + }, + created: { + type: GraphQLString, + description: 'When this user/account was created' + } + } +}); diff --git a/triton-graphql/src/schema/types/machine.js b/triton-graphql/src/schema/types/machine.js new file mode 100644 index 00000000..6ea46cdc --- /dev/null +++ b/triton-graphql/src/schema/types/machine.js @@ -0,0 +1,169 @@ +const FirewallRuleType = require('./firewall-rule'); +const DynamicObjectType = require('./dynamic-object'); +const SnapshotType = require('./snapshot'); +const api = require('../../api'); + +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', + 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' + }, + 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 ? root.tags : get({ + id: root.id, + tag: args.name + }).then((value) => { + return { + [args.name]: value + }; + }); + } + }, + 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 !!root.docker; + } + }, + ips: { + type: new GraphQLList(GraphQLString), + description: 'The IP addresses this instance has' + }, + networks: { + type: new GraphQLList(GraphQLString), + description: 'The network UUIDs of the nics this instance has' + }, + primaryIp: { + type: GraphQLString, + description: 'IP address of the primary nic of this instance' + }, + firewall_enabled: { + type: GraphQLBoolean, + description: 'Whether firewall rules are enforced on this instance', + resolve: (root) => { + return !!root.firewall_enabled; + } + }, + firewall_rules: { + type: new GraphQLList(FirewallRuleType), + description: 'List of FirewallRules affecting this machine', + resolve: (root) => { + return api.firewallRules.listByMachine(root.id); + } + }, + compute_node: { + 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: (root, args) => { + const { + snapshot: { + list, + get + } + } = api.machines; + + return !args.id ? list(root) : get({ + id: root.id, + name: args.name + }); + } + } + } +}); + +module.exports.locality = new GraphQLInputObjectType({ + name: 'LocalityType', + fields: { + strict: { + type: GraphQLBoolean, + resolve: (root) => { + return !!root.strict; + } + }, + near: { + type: new GraphQLList(GraphQLID) + }, + far: { + type: new GraphQLList(GraphQLID) + } + } +}); diff --git a/triton-graphql/src/schema/types/network.js b/triton-graphql/src/schema/types/network.js new file mode 100644 index 00000000..e45a5721 --- /dev/null +++ b/triton-graphql/src/schema/types/network.js @@ -0,0 +1,73 @@ +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 !!root['public']; + } + }, + fabric: { + type: GraphQLBoolean, + description: 'Whether this network is created on a fabric', + resolve: (root) => { + return !!root.fabric; + } + }, + description: { + type: GraphQLString, + description: 'Description of this network' + }, + subnet: { + type: GraphQLString, + description: 'A CIDR formatted string that describes the network' + }, + provision_start_ip: { + type: GraphQLString, + description: 'The first IP on the network that may be assigned' + }, + provision_end_ip: { + 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' + }, + internet_nat: { + type: GraphQLBoolean, + description: 'Provision internet NAT zone on gateway address', + resolve: (root) => { + return !!root.internet_nat; + } + } + } +}); diff --git a/triton-graphql/src/schema/types/nic.js b/triton-graphql/src/schema/types/nic.js new file mode 100644 index 00000000..7c894aa3 --- /dev/null +++ b/triton-graphql/src/schema/types/nic.js @@ -0,0 +1,43 @@ +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)' + } + } +}); diff --git a/triton-graphql/src/schema/types/package.js b/triton-graphql/src/schema/types/package.js new file mode 100644 index 00000000..15ea5302 --- /dev/null +++ b/triton-graphql/src/schema/types/package.js @@ -0,0 +1,52 @@ +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' + } + } +}); diff --git a/triton-graphql/src/schema/types/policy.js b/triton-graphql/src/schema/types/policy.js new file mode 100644 index 00000000..4bad990a --- /dev/null +++ b/triton-graphql/src/schema/types/policy.js @@ -0,0 +1,29 @@ +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' + } + } +}); diff --git a/triton-graphql/src/schema/types/role.js b/triton-graphql/src/schema/types/role.js new file mode 100644 index 00000000..1cc62fca --- /dev/null +++ b/triton-graphql/src/schema/types/role.js @@ -0,0 +1,50 @@ +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)' + }, + default_members: { + 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' + }, + role_tag: { + type: new GraphQLList(GraphQLString), + description: 'The role name', + resolve: (root) => { + return root['role-tag'] || root.role_tag; + } + } + } +}); diff --git a/triton-graphql/src/schema/types/service.js b/triton-graphql/src/schema/types/service.js new file mode 100644 index 00000000..feabcae1 --- /dev/null +++ b/triton-graphql/src/schema/types/service.js @@ -0,0 +1,16 @@ +const { + GraphQLString, + GraphQLObjectType +} = require('graphql'); + +module.exports = new GraphQLObjectType({ + name: 'ServiceType', + fields: { + name: { + type: GraphQLString + }, + url: { + type: GraphQLString + } + } +}); diff --git a/triton-graphql/src/schema/types/snapshot.js b/triton-graphql/src/schema/types/snapshot.js new file mode 100644 index 00000000..106bd137 --- /dev/null +++ b/triton-graphql/src/schema/types/snapshot.js @@ -0,0 +1,20 @@ +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' + } + } +}); diff --git a/triton-graphql/static/.gitkeep b/triton-graphql/static/.gitkeep new file mode 100644 index 00000000..e69de29b